summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml244
-rw-r--r--.rubocop.yml72
-rw-r--r--CHANGELOG.md42
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock26
-rw-r--r--PROCESS.md7
-rw-r--r--app/assets/images/icons.json2
-rw-r--r--app/assets/images/icons.svg2
-rw-r--r--app/assets/images/illustrations/canceled-job_empty.svg1
-rw-r--r--app/assets/images/illustrations/epics.svg2
-rw-r--r--app/assets/images/illustrations/epics/list.svg1
-rw-r--r--app/assets/images/illustrations/epics/roadmap.svg1
-rw-r--r--app/assets/images/illustrations/issue-dashboard_results-without-filiter.svg1
-rw-r--r--app/assets/images/illustrations/lock_promotion.svg1
-rw-r--r--app/assets/images/illustrations/milestone_removing-page.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/activity.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/contributed-projects.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/groups.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/personal-project.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/personal-projects.svg1
-rw-r--r--app/assets/images/illustrations/profile-page/snippets.svg1
-rw-r--r--app/assets/images/illustrations/prometheus-graphs_empty.svg1
-rw-r--r--app/assets/images/illustrations/web-ide_promotion.svg1
-rw-r--r--app/assets/javascripts/behaviors/quick_submit.js2
-rw-r--r--app/assets/javascripts/behaviors/toggler_behavior.js4
-rw-r--r--app/assets/javascripts/boards/components/board_card.vue5
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue7
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.vue110
-rw-r--r--app/assets/javascripts/boards/components/issue_card_inner.js14
-rw-r--r--app/assets/javascripts/boards/components/project_select.vue127
-rw-r--r--app/assets/javascripts/boards/components/sidebar/remove_issue.js8
-rw-r--r--app/assets/javascripts/boards/filtered_search_boards.js1
-rw-r--r--app/assets/javascripts/boards/index.js7
-rw-r--r--app/assets/javascripts/boards/mixins/sortable_default_options.js13
-rw-r--r--app/assets/javascripts/boards/models/issue.js10
-rw-r--r--app/assets/javascripts/boards/models/project.js6
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue7
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table.vue38
-rw-r--r--app/assets/javascripts/commons/vue.js1
-rw-r--r--app/assets/javascripts/groups/components/app.vue10
-rw-r--r--app/assets/javascripts/importer_status.js31
-rw-r--r--app/assets/javascripts/milestone_select.js3
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue86
-rw-r--r--app/assets/javascripts/monitoring/components/graph.vue17
-rw-r--r--app/assets/javascripts/monitoring/components/graph/legend.vue78
-rw-r--r--app/assets/javascripts/monitoring/components/graph_group.vue16
-rw-r--r--app/assets/javascripts/monitoring/monitoring_bundle.js23
-rw-r--r--app/assets/javascripts/monitoring/services/monitoring_service.js3
-rw-r--r--app/assets/javascripts/monitoring/utils/multiple_time_series.js2
-rw-r--r--app/assets/javascripts/notes/components/diff_file_header.vue2
-rw-r--r--app/assets/javascripts/pages/groups/boards/index.js9
-rw-r--r--app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue64
-rw-r--r--app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js84
-rw-r--r--app/assets/javascripts/pages/milestones/shared/index.js89
-rw-r--r--app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js82
-rw-r--r--app/assets/javascripts/pages/projects/environments/index/index.js (renamed from app/assets/javascripts/pages/projects/environments/index.js)0
-rw-r--r--app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue79
-rw-r--r--app/assets/javascripts/pages/projects/labels/event_hub.js3
-rw-r--r--app/assets/javascripts/pages/projects/labels/index/index.js90
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/index/index.js19
-rw-r--r--app/assets/javascripts/pipelines/components/blank_state.vue32
-rw-r--r--app/assets/javascripts/pipelines/components/empty_state.vue49
-rw-r--r--app/assets/javascripts/pipelines/components/error_state.vue26
-rw-r--r--app/assets/javascripts/pipelines/components/nav_controls.vue92
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines.vue271
-rw-r--r--app/assets/javascripts/pipelines/mixins/pipelines.js31
-rw-r--r--app/assets/javascripts/prometheus_metrics/prometheus_metrics.js59
-rw-r--r--app/assets/javascripts/registry/components/collapsible_container.vue1
-rw-r--r--app/assets/javascripts/registry/components/table_registry.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue (renamed from app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js)89
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js2
-rw-r--r--app/assets/javascripts/sortable/sortable_config.js7
-rw-r--r--app/assets/javascripts/terminal/terminal.js10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue (renamed from app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js)87
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue20
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue34
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/dependencies.js5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/clipboard_button.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/memory_graph.vue (renamed from app/assets/javascripts/vue_shared/components/memory_graph.js)38
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue149
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue78
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue84
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue34
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue21
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_hidden_input.vue22
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue27
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue30
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue63
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue48
-rw-r--r--app/assets/javascripts/vue_shared/models/label.js (renamed from app/assets/javascripts/boards/models/label.js)4
-rw-r--r--app/assets/stylesheets/framework/common.scss4
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss2
-rw-r--r--app/assets/stylesheets/framework/flash.scss6
-rw-r--r--app/assets/stylesheets/framework/modal.scss9
-rw-r--r--app/assets/stylesheets/pages/environments.scss3
-rw-r--r--app/assets/stylesheets/pages/settings.scss3
-rw-r--r--app/controllers/admin/impersonation_tokens_controller.rb1
-rw-r--r--app/controllers/boards/issues_controller.rb15
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb1
-rw-r--r--app/controllers/concerns/boards_responses.rb44
-rw-r--r--app/controllers/concerns/creates_commit.rb8
-rw-r--r--app/controllers/groups/boards_controller.rb27
-rw-r--r--app/controllers/groups/labels_controller.rb16
-rw-r--r--app/controllers/import/github_controller.rb18
-rw-r--r--app/controllers/invites_controller.rb2
-rw-r--r--app/controllers/projects/application_controller.rb12
-rw-r--r--app/controllers/projects/blob_controller.rb10
-rw-r--r--app/controllers/projects/branches_controller.rb41
-rw-r--r--app/controllers/projects/compare_controller.rb6
-rw-r--r--app/controllers/projects/deployments_controller.rb2
-rw-r--r--app/controllers/projects/labels_controller.rb8
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb1
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/controllers/projects/milestones_controller.rb14
-rw-r--r--app/controllers/projects/network_controller.rb25
-rw-r--r--app/controllers/projects/prometheus/metrics_controller.rb11
-rw-r--r--app/controllers/projects/services_controller.rb33
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb10
-rw-r--r--app/controllers/projects/tree_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb16
-rw-r--r--app/finders/branches_finder.rb2
-rw-r--r--app/finders/todos_finder.rb4
-rw-r--r--app/finders/user_recent_events_finder.rb45
-rw-r--r--app/helpers/boards_helper.rb28
-rw-r--r--app/helpers/branches_helper.rb11
-rw-r--r--app/helpers/form_helper.rb2
-rw-r--r--app/helpers/groups_helper.rb2
-rw-r--r--app/helpers/import_helper.rb76
-rw-r--r--app/helpers/issuables_helper.rb2
-rw-r--r--app/helpers/labels_helper.rb1
-rw-r--r--app/helpers/merge_requests_helper.rb13
-rw-r--r--app/helpers/projects_helper.rb8
-rw-r--r--app/helpers/search_helper.rb2
-rw-r--r--app/helpers/todos_helper.rb2
-rw-r--r--app/helpers/tree_helper.rb21
-rw-r--r--app/mailers/notify.rb2
-rw-r--r--app/models/badge.rb51
-rw-r--r--app/models/badges/group_badge.rb5
-rw-r--r--app/models/badges/project_badge.rb15
-rw-r--r--app/models/board.rb8
-rw-r--r--app/models/clusters/applications/prometheus.rb4
-rw-r--r--app/models/clusters/applications/runner.rb5
-rw-r--r--app/models/clusters/cluster.rb3
-rw-r--r--app/models/commit.rb7
-rw-r--r--app/models/concerns/deployment_platform.rb3
-rw-r--r--app/models/concerns/issuable.rb4
-rw-r--r--app/models/concerns/prometheus_adapter.rb48
-rw-r--r--app/models/cycle_analytics/summary.rb0
-rw-r--r--app/models/deployment.rb17
-rw-r--r--app/models/environment.rb22
-rw-r--r--app/models/event.rb10
-rw-r--r--app/models/group.rb3
-rw-r--r--app/models/label.rb1
-rw-r--r--app/models/member.rb5
-rw-r--r--app/models/members/project_member.rb6
-rw-r--r--app/models/merge_request.rb40
-rw-r--r--app/models/namespace.rb5
-rw-r--r--app/models/network/commit.rb7
-rw-r--r--app/models/note.rb9
-rw-r--r--app/models/project.rb89
-rw-r--r--app/models/project_services/asana_service.rb2
-rw-r--r--app/models/project_services/campfire_service.rb2
-rw-r--r--app/models/project_services/chat_notification_service.rb2
-rw-r--r--app/models/project_services/hipchat_service.rb4
-rw-r--r--app/models/project_services/jira_service.rb6
-rw-r--r--app/models/project_services/mattermost_slash_commands_service.rb2
-rw-r--r--app/models/project_services/monitoring_service.rb4
-rw-r--r--app/models/project_services/prometheus_service.rb89
-rw-r--r--app/models/project_services/pushover_service.rb4
-rw-r--r--app/models/project_team.rb9
-rw-r--r--app/models/repository.rb97
-rw-r--r--app/models/service.rb11
-rw-r--r--app/models/snippet.rb4
-rw-r--r--app/models/todo.rb14
-rw-r--r--app/models/user.rb40
-rw-r--r--app/models/user_interacted_project.rb59
-rw-r--r--app/policies/group_policy.rb7
-rw-r--r--app/policies/project_policy.rb14
-rw-r--r--app/presenters/merge_request_presenter.rb19
-rw-r--r--app/serializers/merge_request_widget_entity.rb8
-rw-r--r--app/services/badges/base_service.rb11
-rw-r--r--app/services/badges/build_service.rb12
-rw-r--r--app/services/badges/create_service.rb10
-rw-r--r--app/services/badges/update_service.rb12
-rw-r--r--app/services/boards/issues/list_service.rb6
-rw-r--r--app/services/boards/issues/move_service.rb4
-rw-r--r--app/services/boards/lists/create_service.rb6
-rw-r--r--app/services/ci/create_pipeline_service.rb2
-rw-r--r--app/services/ci/create_trace_artifact_service.rb36
-rw-r--r--app/services/issuable_base_service.rb6
-rw-r--r--app/services/members/destroy_service.rb40
-rw-r--r--app/services/merge_requests/base_service.rb19
-rw-r--r--app/services/merge_requests/build_service.rb1
-rw-r--r--app/services/merge_requests/conflicts/list_service.rb10
-rw-r--r--app/services/merge_requests/create_service.rb6
-rw-r--r--app/services/merge_requests/update_service.rb11
-rw-r--r--app/services/notes/build_service.rb9
-rw-r--r--app/services/notes/post_process_service.rb2
-rw-r--r--app/services/notification_recipient_service.rb2
-rw-r--r--app/services/projects/create_service.rb2
-rw-r--r--app/services/projects/import_export/export_service.rb2
-rw-r--r--app/services/projects/update_pages_service.rb35
-rw-r--r--app/services/projects/update_service.rb2
-rw-r--r--app/services/prometheus/adapter_service.rb36
-rw-r--r--app/services/quick_actions/interpret_service.rb6
-rw-r--r--app/services/system_hooks_service.rb4
-rw-r--r--app/services/todo_service.rb3
-rw-r--r--app/services/users/destroy_service.rb2
-rw-r--r--app/validators/url_placeholder_validator.rb32
-rw-r--r--app/views/admin/application_settings/_form.html.haml6
-rw-r--r--app/views/admin/dashboard/index.html.haml2
-rw-r--r--app/views/admin/groups/show.html.haml4
-rw-r--r--app/views/admin/hooks/_form.html.haml42
-rw-r--r--app/views/admin/hooks/index.html.haml58
-rw-r--r--app/views/admin/projects/show.html.haml6
-rw-r--r--app/views/admin/runners/show.html.haml6
-rw-r--r--app/views/admin/users/projects.html.haml4
-rw-r--r--app/views/groups/boards/index.html.haml1
-rw-r--r--app/views/groups/boards/show.html.haml1
-rw-r--r--app/views/groups/issues.html.haml3
-rw-r--r--app/views/groups/labels/index.html.haml6
-rw-r--r--app/views/groups/projects.html.haml2
-rw-r--r--app/views/import/_githubish_status.html.haml22
-rw-r--r--app/views/import/github/new.html.haml38
-rw-r--r--app/views/import/github/status.html.haml6
-rw-r--r--app/views/invites/show.html.haml2
-rw-r--r--app/views/layouts/nav/projects_dropdown/_show.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml9
-rw-r--r--app/views/layouts/project.html.haml2
-rw-r--r--app/views/notify/project_was_exported_email.html.haml2
-rw-r--r--app/views/notify/project_was_moved_email.html.haml2
-rw-r--r--app/views/profiles/chat_names/_chat_name.html.haml2
-rw-r--r--app/views/profiles/keys/index.html.haml4
-rw-r--r--app/views/projects/_commit_button.html.haml4
-rw-r--r--app/views/projects/_home_panel.html.haml6
-rw-r--r--app/views/projects/_new_project_fields.html.haml2
-rw-r--r--app/views/projects/blob/_new_dir.html.haml4
-rw-r--r--app/views/projects/blob/_upload.html.haml4
-rw-r--r--app/views/projects/branches/_panel.html.haml19
-rw-r--r--app/views/projects/branches/index.html.haml53
-rw-r--r--app/views/projects/ci/builds/_build.html.haml2
-rw-r--r--app/views/projects/clusters/_integration_form.html.haml6
-rw-r--r--app/views/projects/commit/_change.html.haml4
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml2
-rw-r--r--app/views/projects/environments/index.html.haml3
-rw-r--r--app/views/projects/environments/metrics.html.haml5
-rw-r--r--app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml2
-rw-r--r--app/views/projects/imports/show.html.haml13
-rw-r--r--app/views/projects/issues/_merge_requests.html.haml2
-rw-r--r--app/views/projects/issues/index.html.haml3
-rw-r--r--app/views/projects/labels/index.html.haml1
-rw-r--r--app/views/projects/merge_requests/index.html.haml3
-rw-r--r--app/views/projects/milestones/index.html.haml1
-rw-r--r--app/views/projects/milestones/show.html.haml11
-rw-r--r--app/views/projects/new.html.haml33
-rw-r--r--app/views/projects/pipelines/index.html.haml9
-rw-r--r--app/views/projects/pipelines/show.html.haml3
-rw-r--r--app/views/projects/registry/repositories/index.html.haml2
-rw-r--r--app/views/projects/services/_form.html.haml3
-rw-r--r--app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml4
-rw-r--r--app/views/projects/services/prometheus/_show.html.haml18
-rw-r--r--app/views/projects/services/slack_slash_commands/_help.html.haml2
-rw-r--r--app/views/projects/settings/repository/show.html.haml3
-rw-r--r--app/views/projects/tags/index.html.haml1
-rw-r--r--app/views/search/_filter.html.haml2
-rw-r--r--app/views/search/_results.html.haml2
-rw-r--r--app/views/search/results/_issue.html.haml2
-rw-r--r--app/views/search/results/_merge_request.html.haml2
-rw-r--r--app/views/search/results/_note.html.haml2
-rw-r--r--app/views/search/results/_snippet_title.html.haml2
-rw-r--r--app/views/sent_notifications/unsubscribe.html.haml2
-rw-r--r--app/views/shared/_import_form.html.haml19
-rw-r--r--app/views/shared/_label.html.haml12
-rw-r--r--app/views/shared/_new_commit_form.html.haml9
-rw-r--r--app/views/shared/_service_settings.html.haml4
-rw-r--r--app/views/shared/boards/_show.html.haml5
-rw-r--r--app/views/shared/boards/components/_board.html.haml1
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml3
-rw-r--r--app/views/shared/issuable/form/_contribution.html.haml20
-rw-r--r--app/views/shared/milestones/_issuable.html.haml2
-rw-r--r--app/views/shared/milestones/_milestone.html.haml33
-rw-r--r--app/views/shared/milestones/_top.html.haml2
-rw-r--r--app/views/shared/plugins/_index.html.haml23
-rw-r--r--app/views/shared/projects/_edit_information.html.haml6
-rw-r--r--app/views/shared/snippets/_snippet.html.haml2
-rw-r--r--app/workers/all_queues.yml4
-rw-r--r--app/workers/archive_trace_worker.rb10
-rw-r--r--app/workers/build_finished_worker.rb2
-rw-r--r--app/workers/concerns/gitlab/github_import/object_importer.rb2
-rw-r--r--app/workers/concerns/pipeline_background_queue.rb10
-rw-r--r--app/workers/create_trace_artifact_worker.rb10
-rw-r--r--app/workers/emails_on_push_worker.rb2
-rw-r--r--app/workers/git_garbage_collect_worker.rb4
-rw-r--r--app/workers/gitlab/github_import/stage/finish_import_worker.rb2
-rw-r--r--app/workers/pages_worker.rb2
-rw-r--r--app/workers/post_receive.rb2
-rw-r--r--app/workers/process_commit_worker.rb7
-rw-r--r--app/workers/update_head_pipeline_for_merge_request_worker.rb2
-rw-r--r--changelogs/unreleased/29130-api-project-export.yml5
-rw-r--r--changelogs/unreleased/38587-pipelines-empty-state.yml5
-rw-r--r--changelogs/unreleased/39444-make-margin-around-dropdown-dividers-4px.yml5
-rw-r--r--changelogs/unreleased/40187-project-branch-dashboard-with-active-stale-branches.yml5
-rw-r--r--changelogs/unreleased/40525-listing-user-activity-timeouts.yml5
-rw-r--r--changelogs/unreleased/41719-mr-title-fix.yml5
-rw-r--r--changelogs/unreleased/42921-ci-charts-include-current-day.yml5
-rw-r--r--changelogs/unreleased/43261-fix-prometheus-installation.yml5
-rw-r--r--changelogs/unreleased/43460-track-projects-a-user-interacted-with.yml5
-rw-r--r--changelogs/unreleased/43510-merge-requests-and-issues-don-t-show-for-all-subgroups.yml6
-rw-r--r--changelogs/unreleased/43531-500-error-searching-wiki-incompatible-character-encodings-utf-8-and-ascii-8bit.yml5
-rw-r--r--changelogs/unreleased/43532-error-on-admin-applications-prometheus-template.yml5
-rw-r--r--changelogs/unreleased/43780-add-a-paragraph-about-clusters-security-implications.yml5
-rw-r--r--changelogs/unreleased/43793-enable-privileged-mode-for-runner.yml5
-rw-r--r--changelogs/unreleased/43802-ensure-foreign-keys-on-clusters-applications.yml5
-rw-r--r--changelogs/unreleased/43829-update-ssh-addtion-text.yml5
-rw-r--r--changelogs/unreleased/43837-error-handle-in-updating-milestone-on-issue.yml5
-rw-r--r--changelogs/unreleased/43924-breadcrumbs-on-project-tags.yml5
-rw-r--r--changelogs/unreleased/43949-verify-job-artifacts.yml5
-rw-r--r--changelogs/unreleased/an-network-controller-fix.yml5
-rw-r--r--changelogs/unreleased/bvl-allow-maintainer-to-push.yml5
-rw-r--r--changelogs/unreleased/bvl-port-of-ee-translations.yml5
-rw-r--r--changelogs/unreleased/cache-refactor.yml5
-rw-r--r--changelogs/unreleased/ce-jej-github-project-service-for-ci.yml5
-rw-r--r--changelogs/unreleased/ce-jej-integrations-can-hide-trigger-checkboxes.yml6
-rw-r--r--changelogs/unreleased/discussions-api.yml5
-rw-r--r--changelogs/unreleased/dz-plugins-project-integrations.yml5
-rw-r--r--changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml5
-rw-r--r--changelogs/unreleased/feature-sm-add-check-sum-to-job-artifacts.yml5
-rw-r--r--changelogs/unreleased/fix-mattermost-delete-team.yml5
-rw-r--r--changelogs/unreleased/fj-41174-projects-groups-badges-api.yml5
-rw-r--r--changelogs/unreleased/grpc-unavailable-restart.yml5
-rw-r--r--changelogs/unreleased/issue-edit-shortcut.yml5
-rw-r--r--changelogs/unreleased/issue_31081.yml5
-rw-r--r--changelogs/unreleased/issue_38337.yml5
-rw-r--r--changelogs/unreleased/jivl-new-modal-project-labels-milestones.yml5
-rw-r--r--changelogs/unreleased/kp-label-select-vue.yml5
-rw-r--r--changelogs/unreleased/merge-request-widget-source-branch-improvements.yml6
-rw-r--r--changelogs/unreleased/minimal-fix-for-artifacts-service.yml5
-rw-r--r--changelogs/unreleased/mk-fix-error-code-for-repo-does-not-exist.yml5
-rw-r--r--changelogs/unreleased/mr-commit-optimization.yml5
-rw-r--r--changelogs/unreleased/oauth_generic_provider.yml4
-rw-r--r--changelogs/unreleased/proper-fix-for-artifacts-service.yml5
-rw-r--r--changelogs/unreleased/refactor-move-mr-widget-memory-usage-and-graph-components.yml5
-rw-r--r--changelogs/unreleased/refactor-move-sidebar-assignee-vue-component.yml5
-rw-r--r--changelogs/unreleased/remove-projects-finder-from-todos-finder.yml5
-rw-r--r--changelogs/unreleased/replace_redcarpet_with_cmark.yml5
-rw-r--r--changelogs/unreleased/revert-project-visibility-changes.yml5
-rw-r--r--changelogs/unreleased/sh-add-missing-acts-as-taggable-indices.yml5
-rw-r--r--changelogs/unreleased/sh-add-section-name-index.yml5
-rw-r--r--changelogs/unreleased/sh-cleanup-after-git-gc.yml5
-rw-r--r--changelogs/unreleased/sh-dashboard-sort-fix.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-43871-system-hooks.yml5
-rw-r--r--changelogs/unreleased/sh-fix-otp-backup-code-invalidation.yml5
-rw-r--r--changelogs/unreleased/sh-make-prune-optional-in-git-fetch.yml5
-rw-r--r--changelogs/unreleased/sh-remove-double-caching-repo-empty.yml5
-rw-r--r--changelogs/unreleased/unassign-when-leaving.yml5
-rw-r--r--changelogs/unreleased/upgrade-workhorse-4-0-0.yml5
-rw-r--r--changelogs/unreleased/wip-new-mr-cmd.yml5
-rw-r--r--changelogs/unreleased/zj-gitaly-encoding-issue.yml5
-rw-r--r--changelogs/unreleased/zj-move-opt-out-ruby-endpoints.yml5
-rw-r--r--config.ru1
-rw-r--r--config/application.rb7
-rw-r--r--config/initializers/8_metrics.rb1
-rw-r--r--config/initializers/forbid_sidekiq_in_transactions.rb17
-rw-r--r--config/prometheus/additional_metrics.yml12
-rw-r--r--config/routes/git_http.rb2
-rw-r--r--config/routes/group.rb7
-rw-r--r--config/routes/project.rb9
-rw-r--r--config/routes/repository.rb1
-rw-r--r--config/routes/user.rb4
-rw-r--r--config/sidekiq_queues.yml1
-rw-r--r--config/webpack.config.js2
-rw-r--r--db/migrate/20180214093516_create_badges.rb17
-rw-r--r--db/migrate/20180221151752_add_allow_maintainer_to_push_to_merge_requests.rb18
-rw-r--r--db/migrate/20180223120443_create_user_interacted_projects_table.rb18
-rw-r--r--db/migrate/20180226050030_add_checksum_to_ci_job_artifacts.rb7
-rw-r--r--db/migrate/20180227182112_add_group_id_to_boards_ce.rb34
-rw-r--r--db/migrate/20180302152117_ensure_foreign_keys_on_clusters_applications.rb50
-rw-r--r--db/migrate/20180305144721_add_privileged_to_runner.rb18
-rw-r--r--db/migrate/20180306134842_add_missing_indexes_acts_as_taggable_on_engine.rb21
-rw-r--r--db/migrate/20180308052825_add_section_name_id_index_on_ci_build_trace_sections.rb22
-rw-r--r--db/post_migrate/20180223124427_build_user_interacted_projects_table.rb124
-rw-r--r--db/post_migrate/20180306074045_migrate_create_trace_artifact_sidekiq_queue.rb13
-rw-r--r--db/post_migrate/20180307012445_migrate_update_head_pipeline_for_merge_request_sidekiq_queue.rb15
-rw-r--r--db/schema.rb39
-rw-r--r--doc/README.md1
-rw-r--r--doc/administration/monitoring/index.md1
-rw-r--r--doc/administration/raketasks/check.md4
-rw-r--r--doc/api/README.md4
-rw-r--r--doc/api/discussions.md411
-rw-r--r--doc/api/group_badges.md191
-rw-r--r--doc/api/group_boards.md284
-rw-r--r--doc/api/groups.md4
-rw-r--r--doc/api/merge_requests.md62
-rw-r--r--doc/api/notes.md77
-rw-r--r--doc/api/project_badges.md188
-rw-r--r--doc/api/project_import_export.md82
-rw-r--r--doc/api/projects.md4
-rw-r--r--doc/ci/examples/README.md16
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.pngbin0 -> 22046 bytes
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.pngbin0 -> 27620 bytes
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.pngbin0 -> 18789 bytes
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md526
-rw-r--r--doc/ci/runners/README.md3
-rw-r--r--doc/development/automatic_ce_ee_merge.md93
-rw-r--r--doc/development/i18n/externalization.md2
-rw-r--r--doc/development/new_fe_guide/dependencies.md3
-rw-r--r--doc/development/new_fe_guide/development/accessibility.md3
-rw-r--r--doc/development/new_fe_guide/development/components.md3
-rw-r--r--doc/development/new_fe_guide/development/design_patterns.md3
-rw-r--r--doc/development/new_fe_guide/development/index.md29
-rw-r--r--doc/development/new_fe_guide/development/network_requests.md3
-rw-r--r--doc/development/new_fe_guide/development/performance.md3
-rw-r--r--doc/development/new_fe_guide/development/security.md3
-rw-r--r--doc/development/new_fe_guide/development/testing.md3
-rw-r--r--doc/development/new_fe_guide/index.md28
-rw-r--r--doc/development/new_fe_guide/initiatives.md3
-rw-r--r--doc/development/new_fe_guide/principles.md3
-rw-r--r--doc/development/new_fe_guide/style/html.md3
-rw-r--r--doc/development/new_fe_guide/style/index.md9
-rw-r--r--doc/development/new_fe_guide/style/javascript.md3
-rw-r--r--doc/development/new_fe_guide/style/scss.md3
-rw-r--r--doc/development/new_fe_guide/style/vue.md3
-rw-r--r--doc/development/new_fe_guide/tips.md3
-rw-r--r--doc/development/writing_documentation.md49
-rw-r--r--doc/install/installation.md4
-rw-r--r--doc/install/requirements.md8
-rw-r--r--doc/topics/autodevops/index.md12
-rw-r--r--doc/update/10.5-to-10.6.md361
-rw-r--r--doc/user/admin_area/settings/img/update-available.pngbin0 -> 89748 bytes
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md26
-rw-r--r--doc/user/permissions.md3
-rw-r--r--doc/user/project/clusters/index.md42
-rw-r--r--doc/user/project/import/img/import_projects_from_repo_url.pngbin0 -> 150259 bytes
-rw-r--r--doc/user/project/import/index.md1
-rw-r--r--doc/user/project/import/perforce.md6
-rw-r--r--doc/user/project/import/repo_by_url.md12
-rw-r--r--doc/user/project/integrations/prometheus_library/kubernetes.md15
-rw-r--r--doc/user/project/issue_board.md21
-rw-r--r--doc/user/project/members/share_project_with_groups.md24
-rw-r--r--doc/user/project/merge_requests/img/allow_maintainer_push.pngbin0 -> 99079 bytes
-rw-r--r--doc/user/project/merge_requests/index.md1
-rw-r--r--doc/user/project/merge_requests/maintainer_access.md13
-rw-r--r--features/steps/shared/project.rb6
-rw-r--r--lib/api/api.rb4
-rw-r--r--lib/api/badges.rb134
-rw-r--r--lib/api/discussions.rb195
-rw-r--r--lib/api/entities.rb41
-rw-r--r--lib/api/group_boards.rb117
-rw-r--r--lib/api/helpers/badges_helpers.rb28
-rw-r--r--lib/api/helpers/internal_helpers.rb7
-rw-r--r--lib/api/helpers/notes_helpers.rb76
-rw-r--r--lib/api/job_artifacts.rb17
-rw-r--r--lib/api/merge_requests.rb62
-rw-r--r--lib/api/notes.rb94
-rw-r--r--lib/api/project_export.rb41
-rw-r--r--lib/api/runner.rb3
-rw-r--r--lib/banzai/filter/autolink_filter.rb86
-rw-r--r--lib/banzai/filter/commit_reference_filter.rb3
-rw-r--r--lib/banzai/filter/markdown_engines/common_mark.rb45
-rw-r--r--lib/banzai/filter/markdown_engines/redcarpet.rb32
-rw-r--r--lib/banzai/filter/markdown_filter.rb41
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb1
-rw-r--r--lib/banzai/renderer/common_mark/html.rb21
-rw-r--r--lib/banzai/renderer/html.rb13
-rw-r--r--lib/banzai/renderer/redcarpet/html.rb15
-rw-r--r--lib/constraints/group_url_constrainer.rb12
-rw-r--r--lib/constraints/project_url_constrainer.rb20
-rw-r--r--lib/constraints/user_url_constrainer.rb12
-rw-r--r--lib/declarative_policy.rb4
-rw-r--r--lib/declarative_policy/delegate_dsl.rb16
-rw-r--r--lib/declarative_policy/dsl.rb103
-rw-r--r--lib/declarative_policy/policy_dsl.rb44
-rw-r--r--lib/declarative_policy/preferred_scope.rb2
-rw-r--r--lib/declarative_policy/rule_dsl.rb45
-rw-r--r--lib/gitlab/auth.rb30
-rw-r--r--lib/gitlab/auth/database/authentication.rb16
-rw-r--r--lib/gitlab/auth/ldap/authentication.rb10
-rw-r--r--lib/gitlab/auth/o_auth/authentication.rb21
-rw-r--r--lib/gitlab/auth/o_auth/provider.rb17
-rw-r--r--lib/gitlab/auth/o_auth/user.rb2
-rw-r--r--lib/gitlab/auth/result.rb2
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb2
-rw-r--r--lib/gitlab/checks/change_access.rb7
-rw-r--r--lib/gitlab/ci/charts.rb15
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb2
-rw-r--r--lib/gitlab/ci/trace.rb47
-rw-r--r--lib/gitlab/conflict/file_collection.rb32
-rw-r--r--lib/gitlab/contributions_calendar.rb2
-rw-r--r--lib/gitlab/data_builder/build.rb2
-rw-r--r--lib/gitlab/data_builder/pipeline.rb1
-rw-r--r--lib/gitlab/git/blob.rb14
-rw-r--r--lib/gitlab/git/branch.rb14
-rw-r--r--lib/gitlab/git/commit.rb2
-rw-r--r--lib/gitlab/git/gitlab_projects.rb5
-rw-r--r--lib/gitlab/git/lfs_changes.rb26
-rw-r--r--lib/gitlab/git/repository.rb66
-rw-r--r--lib/gitlab/gitaly_client/blob_service.rb55
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb4
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb4
-rw-r--r--lib/gitlab/gon_helper.rb1
-rw-r--r--lib/gitlab/health_checks/metric.rb2
-rw-r--r--lib/gitlab/health_checks/result.rb2
-rw-r--r--lib/gitlab/i18n.rb5
-rw-r--r--lib/gitlab/import_export/import_export.yml5
-rw-r--r--lib/gitlab/import_export/importer.rb2
-rw-r--r--lib/gitlab/import_export/relation_factory.rb3
-rw-r--r--lib/gitlab/import_export/shared.rb14
-rw-r--r--lib/gitlab/legacy_github_import/project_creator.rb9
-rw-r--r--lib/gitlab/middleware/read_only.rb83
-rw-r--r--lib/gitlab/middleware/read_only/controller.rb86
-rw-r--r--lib/gitlab/middleware/release_env.rb14
-rw-r--r--lib/gitlab/prometheus/additional_metrics_parser.rb21
-rw-r--r--lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb2
-rw-r--r--lib/gitlab/prometheus/queries/base_query.rb4
-rw-r--r--lib/gitlab/prometheus/queries/deployment_query.rb7
-rw-r--r--lib/gitlab/prometheus/queries/environment_query.rb5
-rw-r--r--lib/gitlab/prometheus/queries/matched_metric_query.rb (renamed from lib/gitlab/prometheus/queries/matched_metrics_query.rb)2
-rw-r--r--lib/gitlab/prometheus/queries/query_additional_metrics.rb22
-rw-r--r--lib/gitlab/prometheus_client.rb6
-rw-r--r--lib/gitlab/repository_cache.rb33
-rw-r--r--lib/gitlab/repository_cache_adapter.rb84
-rw-r--r--lib/gitlab/shell.rb10
-rw-r--r--lib/gitlab/slash_commands/presenters/issue_new.rb2
-rw-r--r--lib/gitlab/slash_commands/presenters/issue_show.rb2
-rw-r--r--lib/gitlab/slash_commands/result.rb2
-rw-r--r--lib/gitlab/string_placeholder_replacer.rb27
-rw-r--r--lib/gitlab/string_range_marker.rb2
-rw-r--r--lib/gitlab/string_regex_marker.rb12
-rw-r--r--lib/gitlab/user_access.rb7
-rw-r--r--lib/gitlab/utils.rb8
-rw-r--r--lib/gitlab/verify/job_artifacts.rb27
-rw-r--r--lib/gitlab/workhorse.rb22
-rw-r--r--lib/haml_lint/inline_javascript.rb2
-rw-r--r--lib/mattermost/session.rb6
-rw-r--r--lib/mattermost/team.rb5
-rw-r--r--lib/repository_cache.rb30
-rw-r--r--lib/rouge/plugins/common_mark.rb20
-rw-r--r--lib/system_check/helpers.rb2
-rw-r--r--lib/tasks/gitlab/artifacts/check.rake8
-rw-r--r--lib/tasks/gitlab/traces.rake24
-rw-r--r--locale/bg/gitlab.po511
-rw-r--r--locale/de/gitlab.po509
-rw-r--r--locale/eo/gitlab.po511
-rw-r--r--locale/es/gitlab.po1041
-rw-r--r--locale/fil_PH/gitlab.po4351
-rw-r--r--locale/fr/gitlab.po1339
-rw-r--r--locale/gitlab.pot267
-rw-r--r--locale/id_ID/gitlab.po4325
-rw-r--r--locale/it/gitlab.po507
-rw-r--r--locale/ja/gitlab.po506
-rw-r--r--locale/ko/gitlab.po508
-rw-r--r--locale/nl_NL/gitlab.po501
-rw-r--r--locale/pl_PL/gitlab.po530
-rw-r--r--locale/pt_BR/gitlab.po515
-rw-r--r--locale/ru/gitlab.po656
-rw-r--r--locale/tr_TR/gitlab.po4351
-rw-r--r--locale/uk/gitlab.po974
-rw-r--r--locale/zh_CN/gitlab.po514
-rw-r--r--locale/zh_HK/gitlab.po508
-rw-r--r--locale/zh_TW/gitlab.po510
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/project/settings/ci_cd.rb2
-rw-r--r--rubocop/rubocop.rb1
-rwxr-xr-xscripts/trigger-build-docs46
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb4
-rw-r--r--spec/controllers/groups/boards_controller_spec.rb136
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb33
-rw-r--r--spec/controllers/projects/deployments_controller_spec.rb4
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb6
-rw-r--r--spec/controllers/projects/prometheus/metrics_controller_spec.rb25
-rw-r--r--spec/controllers/projects/services_controller_spec.rb12
-rw-r--r--spec/controllers/projects/settings/ci_cd_controller_spec.rb19
-rw-r--r--spec/factories/badge.rb14
-rw-r--r--spec/factories/boards.rb25
-rw-r--r--spec/factories/ci/job_artifacts.rb6
-rw-r--r--spec/factories/notes.rb8
-rw-r--r--spec/features/admin/admin_groups_spec.rb2
-rw-r--r--spec/features/admin/admin_hooks_spec.rb10
-rw-r--r--spec/features/admin/admin_projects_spec.rb2
-rw-r--r--spec/features/admin/admin_runners_spec.rb8
-rw-r--r--spec/features/dashboard/issues_spec.rb8
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb4
-rw-r--r--spec/features/dashboard/projects_spec.rb8
-rw-r--r--spec/features/dashboard/todos/todos_filtering_spec.rb8
-rw-r--r--spec/features/issues/move_spec.rb2
-rw-r--r--spec/features/merge_request/maintainer_edits_fork_spec.rb44
-rw-r--r--spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb85
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb26
-rw-r--r--spec/features/milestone_spec.rb11
-rw-r--r--spec/features/projects/branches/download_buttons_spec.rb2
-rw-r--r--spec/features/projects/branches_spec.rb137
-rw-r--r--spec/features/projects/environments/environment_spec.rb2
-rw-r--r--spec/features/projects/members/master_manages_access_requests_spec.rb4
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb2
-rw-r--r--spec/features/projects/merge_request_button_spec.rb4
-rw-r--r--spec/features/projects/new_project_spec.rb6
-rw-r--r--spec/features/projects/pages_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb41
-rw-r--r--spec/features/projects/services/disable_triggers_spec.rb35
-rw-r--r--spec/features/projects/settings/user_manages_project_members_spec.rb2
-rw-r--r--spec/features/projects/user_creates_files_spec.rb11
-rw-r--r--spec/features/search/user_searches_for_code_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_issues_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_merge_requests_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_milestones_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_wiki_pages_spec.rb2
-rw-r--r--spec/features/search/user_uses_search_filters_spec.rb6
-rw-r--r--spec/features/users/login_spec.rb12
-rw-r--r--spec/finders/todos_finder_spec.rb27
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_basic.json3
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_widget.json1
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/merge_requests.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/notes.json1
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/project/export_status.json17
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/project/identity.json21
-rw-r--r--spec/helpers/boards_helper_spec.rb28
-rw-r--r--spec/helpers/members_helper_spec.rb10
-rw-r--r--spec/helpers/todos_helper_spec.rb4
-rw-r--r--spec/helpers/tree_helper_spec.rb9
-rw-r--r--spec/javascripts/api_spec.js21
-rw-r--r--spec/javascripts/boards/board_card_spec.js2
-rw-r--r--spec/javascripts/boards/boards_store_spec.js2
-rw-r--r--spec/javascripts/boards/issue_card_spec.js2
-rw-r--r--spec/javascripts/boards/issue_spec.js2
-rw-r--r--spec/javascripts/boards/list_spec.js2
-rw-r--r--spec/javascripts/boards/modal_store_spec.js2
-rw-r--r--spec/javascripts/environments/environments_app_spec.js13
-rw-r--r--spec/javascripts/fixtures/environments.rb30
-rw-r--r--spec/javascripts/groups/components/app_spec.js59
-rw-r--r--spec/javascripts/importer_status_spec.js15
-rw-r--r--spec/javascripts/monitoring/dashboard_spec.js67
-rw-r--r--spec/javascripts/pages/labels/components/promote_label_modal_spec.js88
-rw-r--r--spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js83
-rw-r--r--spec/javascripts/pipelines/blank_state_spec.js29
-rw-r--r--spec/javascripts/pipelines/empty_state_spec.js28
-rw-r--r--spec/javascripts/pipelines/error_state_spec.js27
-rw-r--r--spec/javascripts/pipelines/nav_controls_spec.js99
-rw-r--r--spec/javascripts/pipelines/pipelines_spec.js677
-rw-r--r--spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js2
-rw-r--r--spec/javascripts/sidebar/sidebar_assignees_spec.js2
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js40
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js18
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js12
-rw-r--r--spec/javascripts/vue_mr_widget/mr_widget_options_spec.js42
-rw-r--r--spec/javascripts/vue_shared/components/clipboard_button_spec.js5
-rw-r--r--spec/javascripts/vue_shared/components/memory_graph_spec.js26
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js81
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button_spec.js82
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js84
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js42
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header_spec.js36
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_hidden_input_spec.js37
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input_spec.js39
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title_spec.js42
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js74
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js94
-rw-r--r--spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js49
-rw-r--r--spec/lib/banzai/filter/autolink_filter_spec.rb126
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb8
-rw-r--r--spec/lib/constraints/group_url_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/project_url_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/user_url_constrainer_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb3
-rw-r--r--spec/lib/gitlab/checks/lfs_integrity_spec.rb22
-rw-r--r--spec/lib/gitlab/ci/charts_spec.rb45
-rw-r--r--spec/lib/gitlab/ci/trace_spec.rb136
-rw-r--r--spec/lib/gitlab/conflict/file_collection_spec.rb32
-rw-r--r--spec/lib/gitlab/contributions_calendar_spec.rb21
-rw-r--r--spec/lib/gitlab/data_builder/build_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/pipeline_spec.rb1
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb29
-rw-r--r--spec/lib/gitlab/git/branch_spec.rb64
-rw-r--r--spec/lib/gitlab/git/gitlab_projects_spec.rb20
-rw-r--r--spec/lib/gitlab/git/lfs_changes_spec.rb38
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb360
-rw-r--r--spec/lib/gitlab/gitaly_client/blob_service_spec.rb60
-rw-r--r--spec/lib/gitlab/gitaly_client/repository_service_spec.rb14
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml4
-rw-r--r--spec/lib/gitlab/import_export/avatar_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/avatar_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/file_importer_spec.rb3
-rw-r--r--spec/lib/gitlab/import_export/fork_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project.json767
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb9
-rw-r--r--spec/lib/gitlab/import_export/reader_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/repo_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/repo_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml10
-rw-r--r--spec/lib/gitlab/import_export/uploads_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/uploads_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/version_checker_spec.rb3
-rw-r--r--spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/wiki_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/middleware/read_only_spec.rb25
-rw-r--r--spec/lib/gitlab/middleware/release_env_spec.rb16
-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.rb4
-rw-r--r--spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb (renamed from spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb)2
-rw-r--r--spec/lib/gitlab/repository_cache_adapter_spec.rb76
-rw-r--r--spec/lib/gitlab/repository_cache_spec.rb50
-rw-r--r--spec/lib/gitlab/shell_spec.rb32
-rw-r--r--spec/lib/gitlab/string_placeholder_replacer_spec.rb38
-rw-r--r--spec/lib/gitlab/string_regex_marker_spec.rb35
-rw-r--r--spec/lib/gitlab/user_access_spec.rb35
-rw-r--r--spec/lib/gitlab/utils_spec.rb16
-rw-r--r--spec/lib/gitlab/verify/job_artifacts_spec.rb35
-rw-r--r--spec/lib/mattermost/team_spec.rb104
-rw-r--r--spec/lib/repository_cache_spec.rb34
-rw-r--r--spec/mailers/notify_spec.rb22
-rw-r--r--spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb66
-rw-r--r--spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb64
-rw-r--r--spec/models/badge_spec.rb94
-rw-r--r--spec/models/badges/group_badge_spec.rb11
-rw-r--r--spec/models/badges/project_badge_spec.rb43
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb12
-rw-r--r--spec/models/clusters/applications/runner_spec.rb30
-rw-r--r--spec/models/concerns/prometheus_adapter_spec.rb121
-rw-r--r--spec/models/deployment_spec.rb16
-rw-r--r--spec/models/environment_spec.rb61
-rw-r--r--spec/models/event_spec.rb16
-rw-r--r--spec/models/group_spec.rb1
-rw-r--r--spec/models/members/project_member_spec.rb23
-rw-r--r--spec/models/merge_request_spec.rb78
-rw-r--r--spec/models/project_services/asana_service_spec.rb2
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb4
-rw-r--r--spec/models/project_services/jira_service_spec.rb3
-rw-r--r--spec/models/project_services/mattermost_slash_commands_service_spec.rb6
-rw-r--r--spec/models/project_services/prometheus_service_spec.rb189
-rw-r--r--spec/models/project_spec.rb148
-rw-r--r--spec/models/project_wiki_spec.rb6
-rw-r--r--spec/models/repository_spec.rb77
-rw-r--r--spec/models/user_interacted_project_spec.rb60
-rw-r--r--spec/models/user_spec.rb1
-rw-r--r--spec/policies/project_policy_spec.rb37
-rw-r--r--spec/requests/api/badges_spec.rb367
-rw-r--r--spec/requests/api/discussions_spec.rb33
-rw-r--r--spec/requests/api/group_boards_spec.rb54
-rw-r--r--spec/requests/api/internal_spec.rb28
-rw-r--r--spec/requests/api/merge_requests_spec.rb28
-rw-r--r--spec/requests/api/notes_spec.rb590
-rw-r--r--spec/requests/api/pages_domains_spec.rb2
-rw-r--r--spec/requests/api/project_export_spec.rb290
-rw-r--r--spec/requests/api/runner_spec.rb8
-rw-r--r--spec/requests/git_http_spec.rb6
-rw-r--r--spec/routing/routing_spec.rb4
-rw-r--r--spec/serializers/merge_request_widget_entity_spec.rb6
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb18
-rw-r--r--spec/services/boards/create_service_spec.rb30
-rw-r--r--spec/services/boards/issues/list_service_spec.rb157
-rw-r--r--spec/services/boards/issues/move_service_spec.rb119
-rw-r--r--spec/services/boards/list_service_spec.rb32
-rw-r--r--spec/services/boards/lists/create_service_spec.rb89
-rw-r--r--spec/services/boards/lists/destroy_service_spec.rb39
-rw-r--r--spec/services/boards/lists/list_service_spec.rb36
-rw-r--r--spec/services/boards/lists/move_service_spec.rb100
-rw-r--r--spec/services/ci/create_trace_artifact_service_spec.rb63
-rw-r--r--spec/services/members/destroy_service_spec.rb96
-rw-r--r--spec/services/merge_requests/create_service_spec.rb35
-rw-r--r--spec/services/merge_requests/update_service_spec.rb37
-rw-r--r--spec/services/projects/update_pages_service_spec.rb16
-rw-r--r--spec/services/projects/update_service_spec.rb9
-rw-r--r--spec/services/prometheus/adapter_service_spec.rb40
-rw-r--r--spec/services/system_hooks_service_spec.rb12
-rw-r--r--spec/services/system_note_service_spec.rb6
-rw-r--r--spec/support/bare_repo_operations.rb14
-rw-r--r--spec/support/matchers/match_ids.rb24
-rw-r--r--spec/support/shared_examples/requests/api/discussions.rb169
-rw-r--r--spec/support/shared_examples/requests/api/notes.rb206
-rw-r--r--spec/support/shared_examples/services/boards/boards_create_service.rb27
-rw-r--r--spec/support/shared_examples/services/boards/boards_list_service.rb29
-rw-r--r--spec/support/shared_examples/services/boards/issues_list_service.rb60
-rw-r--r--spec/support/shared_examples/services/boards/issues_move_service.rb87
-rw-r--r--spec/support/shared_examples/services/boards/lists_destroy_service.rb30
-rw-r--r--spec/support/shared_examples/services/boards/lists_list_service.rb23
-rw-r--r--spec/support/shared_examples/services/boards/lists_move_service.rb93
-rw-r--r--spec/tasks/gitlab/artifacts/check_rake_spec.rb34
-rw-r--r--spec/tasks/gitlab/traces_rake_spec.rb55
-rw-r--r--spec/validators/url_placeholder_validator_spec.rb39
-rw-r--r--spec/validators/url_validator_spec.rb46
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb2
-rw-r--r--spec/views/projects/_home_panel.html.haml_spec.rb54
-rw-r--r--spec/views/projects/tree/show.html.haml_spec.rb1
-rw-r--r--spec/workers/archive_trace_worker_spec.rb (renamed from spec/workers/create_trace_artifact_worker_spec.rb)8
-rw-r--r--spec/workers/build_finished_worker_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/github_import/object_importer_spec.rb2
-rw-r--r--spec/workers/concerns/pipeline_background_queue_spec.rb19
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb6
-rw-r--r--spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_issue_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_note_worker_spec.rb2
-rw-r--r--spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb2
-rw-r--r--spec/workers/post_receive_spec.rb12
-rw-r--r--spec/workers/process_commit_worker_spec.rb74
-rw-r--r--vendor/gitignore/Dart.gitignore2
-rw-r--r--vendor/gitignore/Qt.gitignore8
-rw-r--r--vendor/gitignore/R.gitignore3
-rw-r--r--vendor/gitignore/TeX.gitignore8
-rw-r--r--vendor/gitignore/VisualStudio.gitignore3
-rw-r--r--vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml19
-rw-r--r--vendor/licenses.csv514
-rw-r--r--vendor/runner/values.yaml2
-rw-r--r--yarn.lock6
813 files changed, 38229 insertions, 6927 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8b489f1a07c..5556bf5bc0b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -35,8 +35,14 @@ variables:
before_script:
- bundle --version
+ - date
- source scripts/utils.sh
+ - date
- source scripts/prepare_build.sh
+ - date
+
+after_script:
+ - date
stages:
- build
@@ -88,6 +94,26 @@ stages:
- /(^docs[\/-].*|.*-docs$)/
- /(^qa[\/-].*|.*-qa$)/
+# Jobs that only need to pull cache
+.dedicated-no-docs-pull-cache-job: &dedicated-no-docs-pull-cache-job
+ <<: *dedicated-runner
+ <<: *except-docs-and-qa
+ <<: *pull-cache
+ dependencies:
+ - setup-test-env
+ stage: test
+
+# Jobs that do not need a DB
+.dedicated-no-docs-no-db-pull-cache-job: &dedicated-no-docs-no-db-pull-cache-job
+ <<: *dedicated-no-docs-pull-cache-job
+ variables:
+ SETUP_DB: "false"
+
+.rake-exec: &rake-exec
+ <<: *dedicated-no-docs-no-db-pull-cache-job
+ script:
+ - bundle exec rake $CI_JOB_NAME
+
.rspec-metadata: &rspec-metadata
<<: *dedicated-runner
<<: *except-docs-and-qa
@@ -164,21 +190,23 @@ stages:
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
-##
-# Trigger a package build in omnibus-gitlab repository
-#
-package-qa:
- <<: *dedicated-runner
- image: ruby:2.4-alpine
- before_script: []
- stage: build
- cache: {}
- when: manual
+.gitlab-setup: &gitlab-setup
+ <<: *dedicated-no-docs-pull-cache-job
+ <<: *use-pg
+ variables:
+ CREATE_DB_USER: "true"
script:
- - scripts/trigger-build-omnibus
- only:
- - //@gitlab-org/gitlab-ce
- - //@gitlab-org/gitlab-ee
+ # Manually clone gitlab-test and only seed this project in
+ # 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
+ - scripts/gitaly-test-spawn
+ - force=yes SIZE=1 FIXTURE_PATH="db/fixtures/development" bundle exec rake gitlab:setup
+ artifacts:
+ when: on_failure
+ expire_in: 1d
+ paths:
+ - log/development.log
# Review docs base
.review-docs: &review-docs
@@ -201,6 +229,47 @@ package-qa:
only:
- branches
+# DB migration, rollback, and seed jobs
+.db-migrate-reset: &db-migrate-reset
+ <<: *dedicated-no-docs-pull-cache-job
+ script:
+ - bundle exec rake db:migrate:reset
+
+.migration-paths: &migration-paths
+ <<: *dedicated-no-docs-pull-cache-job
+ variables:
+ CREATE_DB_USER: "true"
+ script:
+ - git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0
+ - git checkout -f FETCH_HEAD
+ - bundle install $BUNDLE_INSTALL_FLAGS
+ - date
+ - cp config/gitlab.yml.example config/gitlab.yml
+ - bundle exec rake db:drop db:create db:schema:load db:seed_fu
+ - date
+ - git checkout $CI_COMMIT_SHA
+ - bundle install $BUNDLE_INSTALL_FLAGS
+ - date
+ - . scripts/prepare_build.sh
+ - date
+ - bundle exec rake db:migrate
+
+##
+# Trigger a package build in omnibus-gitlab repository
+#
+package-qa:
+ <<: *dedicated-runner
+ image: ruby:2.4-alpine
+ before_script: []
+ stage: build
+ cache: {}
+ when: manual
+ script:
+ - scripts/trigger-build-omnibus
+ only:
+ - //@gitlab-org/gitlab-ce
+ - //@gitlab-org/gitlab-ee
+
# Trigger a docs build in gitlab-docs
# Useful to preview the docs changes live
review-docs-deploy:
@@ -265,7 +334,7 @@ update-tests-metadata:
flaky-examples-check:
<<: *dedicated-runner
- image: ruby:2.3-alpine
+ image: ruby:2.4-alpine
services: []
before_script: []
variables:
@@ -299,7 +368,9 @@ compile-assets:
<<: *default-cache
script:
- node --version
+ - date
- yarn install --frozen-lockfile --cache-folder .yarn-cache
+ - date
- bundle exec rake gitlab:assets:compile
artifacts:
expire_in: 7d
@@ -387,26 +458,11 @@ spinach-pg 1 2: *spinach-metadata-pg
spinach-mysql 0 2: *spinach-metadata-mysql
spinach-mysql 1 2: *spinach-metadata-mysql
-# Static analysis jobs
-.ruby-static-analysis: &ruby-static-analysis
- variables:
- SIMPLECOV: "false"
- SETUP_DB: "false"
-
-.rake-exec: &rake-exec
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
- <<: *ruby-static-analysis
- stage: test
- script:
- - bundle exec rake $CI_JOB_NAME
-
static-analysis:
- <<: *dedicated-runner
- <<: *except-docs
- <<: *ruby-static-analysis
- stage: test
+ <<: *dedicated-no-docs-no-db-pull-cache-job
+ dependencies:
+ - compile-assets
+ - setup-test-env
script:
- scripts/static-analysis
cache:
@@ -463,15 +519,6 @@ ee_compat_check:
paths:
- ee_compat_check/patches/*.patch
-# DB migration, rollback, and seed jobs
-.db-migrate-reset: &db-migrate-reset
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
- stage: test
- script:
- - bundle exec rake db:migrate:reset
-
db:migrate:reset-pg:
<<: *db-migrate-reset
<<: *use-pg
@@ -486,25 +533,6 @@ db:check-schema-pg:
script:
- source scripts/schema_changed.sh
-.migration-paths: &migration-paths
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
- stage: test
- variables:
- SETUP_DB: "false"
- CREATE_DB_USER: "true"
- script:
- - git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0
- - git checkout -f FETCH_HEAD
- - bundle install $BUNDLE_INSTALL_FLAGS
- - cp config/gitlab.yml.example config/gitlab.yml
- - bundle exec rake db:drop db:create db:schema:load db:seed_fu
- - git checkout $CI_COMMIT_SHA
- - bundle install $BUNDLE_INSTALL_FLAGS
- - . scripts/prepare_build.sh
- - bundle exec rake db:migrate
-
migration:path-pg:
<<: *migration-paths
<<: *use-pg
@@ -514,10 +542,7 @@ migration:path-mysql:
<<: *use-mysql
.db-rollback: &db-rollback
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
- stage: test
+ <<: *dedicated-no-docs-pull-cache-job
script:
- bundle exec rake db:rollback STEP=119
- bundle exec rake db:migrate
@@ -530,27 +555,6 @@ db:rollback-mysql:
<<: *db-rollback
<<: *use-mysql
-.gitlab-setup: &gitlab-setup
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
- stage: test
- variables:
- SIZE: "1"
- SETUP_DB: "false"
- CREATE_DB_USER: "true"
- FIXTURE_PATH: db/fixtures/development
- script:
- - git clone https://gitlab.com/gitlab-org/gitlab-test.git
- /home/git/repositories/gitlab-org/gitlab-test.git
- - scripts/gitaly-test-spawn
- - force=yes bundle exec rake gitlab:setup
- artifacts:
- when: on_failure
- expire_in: 1d
- paths:
- - log/development.log
-
gitlab:setup-pg:
<<: *gitlab-setup
<<: *use-pg
@@ -561,10 +565,7 @@ gitlab:setup-mysql:
# Frontend-related jobs
gitlab:assets:compile:
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
- stage: test
+ <<: *dedicated-no-docs-no-db-pull-cache-job
dependencies: []
variables:
NODE_ENV: "production"
@@ -574,7 +575,9 @@ gitlab:assets:compile:
WEBPACK_REPORT: "true"
NO_COMPRESSION: "true"
script:
+ - date
- yarn install --frozen-lockfile --production --cache-folder .yarn-cache
+ - date
- bundle exec rake gitlab:assets:compile
artifacts:
name: webpack-report
@@ -583,17 +586,16 @@ gitlab:assets:compile:
- webpack-report/
karma:
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
+ <<: *dedicated-no-docs-pull-cache-job
<<: *use-pg
- stage: test
- variables:
- BABEL_ENV: "coverage"
- CHROME_LOG_FILE: "chrome_debug.log"
+ dependencies:
+ - compile-assets
+ - setup-test-env
script:
+ - export BABEL_ENV=coverage CHROME_LOG_FILE=chrome_debug.log
+ - date
- scripts/gitaly-test-spawn
- - bundle exec rake gettext:po_to_json
+ - date
- bundle exec rake karma
coverage: '/^Statements *: (\d+\.\d+%)/'
artifacts:
@@ -601,13 +603,11 @@ karma:
expire_in: 31d
when: always
paths:
- - chrome_debug.log
- - coverage-javascript/
+ - chrome_debug.log
+ - coverage-javascript/
codequality:
- <<: *except-docs
- <<: *pull-cache
- stage: test
+ <<: *dedicated-no-docs-no-db-pull-cache-job
image: docker:latest
before_script: []
services:
@@ -639,11 +639,7 @@ sast:
paths: [gl-sast-report.json]
qa:internal:
- <<: *dedicated-runner
- <<: *except-docs
- stage: test
- variables:
- SETUP_DB: "false"
+ <<: *dedicated-no-docs-no-db-pull-cache-job
services: []
script:
- cd qa/
@@ -651,11 +647,7 @@ qa:internal:
- bundle exec rspec
qa:selectors:
- <<: *dedicated-runner
- <<: *except-docs
- stage: test
- variables:
- SETUP_DB: "false"
+ <<: *dedicated-no-docs-no-db-pull-cache-job
services: []
script:
- cd qa/
@@ -663,14 +655,8 @@ qa:selectors:
- bundle exec bin/qa Test::Sanity::Selectors
coverage:
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
+ <<: *dedicated-no-docs-no-db-pull-cache-job
stage: post-test
- services: []
- variables:
- SETUP_DB: "false"
- USE_BUNDLE_INSTALL: "true"
script:
- bundle exec scripts/merge-simplecov
coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
@@ -682,26 +668,25 @@ coverage:
- coverage/assets/
lint:javascript:report:
- <<: *dedicated-runner
- <<: *except-docs-and-qa
- <<: *pull-cache
+ <<: *dedicated-no-docs-no-db-pull-cache-job
stage: post-test
dependencies:
- compile-assets
- setup-test-env
before_script: []
script:
+ - date
- find app/ spec/ -name '*.js' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files
+ - date
- yarn run eslint-report || true # ignore exit code
artifacts:
name: eslint-report
expire_in: 31d
paths:
- - eslint-report.html
+ - eslint-report.html
pages:
- <<: *dedicated-runner
- <<: *pull-cache
+ <<: *dedicated-no-docs-no-db-pull-cache-job
before_script: []
stage: pages
dependencies:
@@ -726,10 +711,7 @@ pages:
# Insurance in case a gem needed by one of our releases gets yanked from
# rubygems.org in the future.
cache gems:
- <<: *dedicated-runner
- <<: *pull-cache
- variables:
- SETUP_DB: "false"
+ <<: *dedicated-no-docs-no-db-pull-cache-job
script:
- bundle package --all --all-platforms
artifacts:
diff --git a/.rubocop.yml b/.rubocop.yml
index 293f61fb725..14840ddd262 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -31,6 +31,78 @@ Style/MutableConstant:
- 'ee/db/post_migrate/**/*'
- 'ee/db/geo/migrate/**/*'
+Naming/FileName:
+ ExpectMatchingDefinition: true
+ Exclude:
+ - 'spec/**/*'
+ - 'features/**/*'
+ - 'ee/spec/**/*'
+ - 'qa/spec/**/*'
+ - 'qa/qa/specs/**/*'
+ - 'qa/bin/*'
+ - 'config/**/*'
+ - 'lib/generators/**/*'
+ - 'ee/lib/generators/**/*'
+ IgnoreExecutableScripts: true
+ AllowedAcronyms:
+ - EE
+ - JSON
+ - LDAP
+ - IO
+ - HMAC
+ - QA
+ - ENV
+ - STL
+ - PDF
+ - SVG
+ - CTE
+ - DN
+ - RSA
+ - CI
+ - CD
+ - OAuth
+ # default ones:
+ - CLI
+ - DSL
+ - ACL
+ - API
+ - ASCII
+ - CPU
+ - CSS
+ - DNS
+ - EOF
+ - GUID
+ - HTML
+ - HTTP
+ - HTTPS
+ - ID
+ - IP
+ - JSON
+ - LHS
+ - QPS
+ - RAM
+ - RHS
+ - RPC
+ - SLA
+ - SMTP
+ - SQL
+ - SSH
+ - TCP
+ - TLS
+ - TTL
+ - UDP
+ - UI
+ - UID
+ - UUID
+ - URI
+ - URL
+ - UTF8
+ - VM
+ - XML
+ - XMPP
+ - XSRF
+ - XSS
+
# Gitlab ###################################################################
Gitlab/ModuleWithInstanceVariables:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c8d399b2b98..630aef6751f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,34 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 10.5.4 (2018-03-08)
+
+### Fixed (11 changes)
+
+- Encode branch name as binary before creating a RPC request to copy attributes. !17291
+- Restart Unicorn and Sidekiq when GRPC throws 14:Endpoint read failed. !17293
+- Ensure group issues and merge requests pages show results from subgroups when there are no results from the current group. !17312
+- Prevent trace artifact migration to incur data loss. !17313
+- Return a 404 instead of 403 if the repository does not exist on disk. !17341
+- Allow Prometheus application to be installed from Cluster applications. !17372
+- Fixes Prometheus admin configuration page. !17377
+- Fix code and wiki search results pages when non-ASCII text is displayed. !17413
+- Fix pages flaky failure by reloading stale object. !17522
+- Fixed issue edit shortcut not opening edit form.
+- Revert Project.public_or_visible_to_user changes and only apply to snippets.
+
+### Performance (1 change)
+
+- Don't use ProjectsFinder in TodosFinder.
+
+
+## 10.5.3 (2018-03-01)
+
+### Security (1 change)
+
+- Ensure that OTP backup codes are always invalidated.
+
+
## 10.5.2 (2018-02-25)
### Fixed (7 changes)
@@ -219,6 +247,13 @@ entry.
- Adds empty state illustration for pending job.
+## 10.4.5 (2018-03-01)
+
+### Security (1 change)
+
+- Ensure that OTP backup codes are always invalidated.
+
+
## 10.4.4 (2018-02-16)
### Security (1 change)
@@ -443,6 +478,13 @@ entry.
- Use a background migration for issues.closed_at.
+## 10.3.8 (2018-03-01)
+
+### Security (1 change)
+
+- Ensure that OTP backup codes are always invalidated.
+
+
## 10.3.7 (2018-02-05)
### Security (4 changes)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 359ee08a7ce..fe6d01c1a45 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.87.0
+0.88.0
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index a918a2aa18d..faef31a4357 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-0.6.0
+0.7.0
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 090ea9dad19..1aa5e414fd3 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-6.0.3
+6.0.4
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 19811903a7f..fcdb2e109f6 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-3.8.0
+4.0.0
diff --git a/Gemfile b/Gemfile
index d8cb5267d81..2793463fd81 100644
--- a/Gemfile
+++ b/Gemfile
@@ -126,6 +126,7 @@ gem 'html-pipeline', '~> 1.11.0'
gem 'deckar01-task_list', '2.0.0'
gem 'gitlab-markup', '~> 1.6.2'
gem 'redcarpet', '~> 3.4'
+gem 'commonmarker', '~> 0.17'
gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~> 4.2'
gem 'org-ruby', '~> 0.9.12'
@@ -411,7 +412,9 @@ group :ed25519 do
end
# Gitaly GRPC client
-gem 'gitaly-proto', '~> 0.87.0', require: 'gitaly'
+gem 'gitaly-proto', '~> 0.88.0', require: 'gitaly'
+gem 'grpc', '~> 1.10.0'
+
# Locked until https://github.com/google/protobuf/issues/4210 is closed
gem 'google-protobuf', '= 3.5.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index 6918f92aa84..fa99ec3febe 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -131,6 +131,8 @@ GEM
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
colorize (0.7.7)
+ commonmarker (0.17.8)
+ ruby-enum (~> 0.5)
concord (0.1.5)
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
@@ -285,7 +287,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
- gitaly-proto (0.87.0)
+ gitaly-proto (0.88.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (5.3.3)
@@ -343,9 +345,9 @@ GEM
google-protobuf (3.5.1)
googleapis-common-protos-types (1.0.1)
google-protobuf (~> 3.0)
- googleauth (0.5.3)
+ googleauth (0.6.2)
faraday (~> 0.12)
- jwt (~> 1.4)
+ jwt (>= 1.4, < 3.0)
logging (~> 2.0)
memoist (~> 0.12)
multi_json (~> 1.11)
@@ -369,7 +371,7 @@ GEM
rake
grape_logging (1.7.0)
grape
- grpc (1.8.3)
+ grpc (1.10.0)
google-protobuf (~> 3.1)
googleapis-common-protos-types (~> 1.0.0)
googleauth (>= 0.5.1, < 0.7)
@@ -503,7 +505,7 @@ GEM
mini_portile2 (2.3.0)
minitest (5.7.0)
mousetrap-rails (1.4.6)
- multi_json (1.12.2)
+ multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
mustermann (1.0.0)
@@ -601,7 +603,7 @@ GEM
atomic (>= 1.0.0)
mysql2
peek
- peek-performance_bar (1.3.0)
+ peek-performance_bar (1.3.1)
peek (>= 0.1.0)
peek-pg (1.3.0)
concurrent-ruby
@@ -646,7 +648,7 @@ GEM
pry (~> 0.10)
pry-rails (0.3.5)
pry (>= 0.9.10)
- public_suffix (3.0.0)
+ public_suffix (3.0.2)
pyu-ruby-sasl (0.0.3.3)
rack (1.6.8)
rack-accept (0.4.5)
@@ -797,6 +799,8 @@ GEM
rubocop (>= 0.51)
rubocop-rspec (1.22.1)
rubocop (>= 0.52.1)
+ ruby-enum (0.7.2)
+ i18n
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-prof (0.16.2)
@@ -858,10 +862,10 @@ GEM
sidekiq (>= 4.2.1)
sidekiq-limit_fetch (3.4.0)
sidekiq (>= 4)
- signet (0.7.3)
+ signet (0.8.1)
addressable (~> 2.3)
faraday (~> 0.9)
- jwt (~> 1.5)
+ jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simple_po_parser (1.1.2)
simplecov (0.14.1)
@@ -1019,6 +1023,7 @@ DEPENDENCIES
charlock_holmes (~> 0.7.5)
chronic (~> 0.10.2)
chronic_duration (~> 0.10.6)
+ commonmarker (~> 0.17)
concurrent-ruby (~> 1.0.5)
connection_pool (~> 2.0)
creole (~> 0.5.0)
@@ -1057,7 +1062,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
- gitaly-proto (~> 0.87.0)
+ gitaly-proto (~> 0.88.0)
github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.6.2)
@@ -1073,6 +1078,7 @@ DEPENDENCIES
grape-entity (~> 0.6.0)
grape-route-helpers (~> 2.1.0)
grape_logging (~> 1.7)
+ grpc (~> 1.10.0)
haml_lint (~> 0.26.0)
hamlit (~> 2.6.1)
hashie-forbidden_attributes
diff --git a/PROCESS.md b/PROCESS.md
index c24210341e0..f206506f7c5 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -53,7 +53,7 @@ Below we describe the contributing process to GitLab for two reasons:
Several people from the [GitLab team][team] are helping community members to get
their contributions accepted by meeting our [Definition of done][done].
-What you can expect from them is described at https://about.gitlab.com/jobs/merge-request-coach/.
+What you can expect from them is described at https://about.gitlab.com/roles/merge-request-coach/.
## Assigning issues
@@ -71,7 +71,7 @@ star, smile, etc.). Some good tips about code reviews can be found in our
## Feature freeze on the 7th for the release on the 22nd
-After 7th at 23:59 (Pacific Standard Time Zone) of each month, RC1 of the upcoming release (to be shipped on the 22nd) is created and deployed to GitLab.com and the stable branch for this release is frozen, which means master is no longer merged into it.
+After 7th at 23:59 (Pacific Time Zone) of each month, RC1 of the upcoming release (to be shipped on the 22nd) is created and deployed to GitLab.com and the stable branch for this release is frozen, which means master is no longer merged into it.
Merge requests may still be merged into master during this period,
but they will go into the _next_ release, unless they are manually cherry-picked into the stable branch.
@@ -202,6 +202,9 @@ you can ask for an exception to be made.
Go to [Release tasks issue tracker](https://gitlab.com/gitlab-org/release/tasks/issues/new) and create an issue
using the `Exception-request` issue template.
+**Do not** set the relevant `Pick into X.Y` label (see above) before request an
+exception; this should be done after the exception is approved.
+
You can find who is who on the [team page](https://about.gitlab.com/team/).
Whether an exception is made is determined by weighing the benefit and urgency of the change
diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json
index 19843d24e22..d6f6e50398b 100644
--- a/app/assets/images/icons.json
+++ b/app/assets/images/icons.json
@@ -1 +1 @@
-{"iconCount":191,"spriteSize":86607,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","soft-unwrap","soft-wrap","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_notfound","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]} \ No newline at end of file
+{"iconCount":198,"spriteSize":89379,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","blame","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","compress","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","error","expand","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","go-back","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor-lines","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","soft-unwrap","soft-wrap","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_notfound","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","time-out","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]} \ No newline at end of file
diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg
index 6aec54d0543..70205220e87 100644
--- a/app/assets/images/icons.svg
+++ b/app/assets/images/icons.svg
@@ -1 +1 @@
-<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 16 16" id="abuse" xmlns="http://www.w3.org/2000/svg"><path d="M11.408.328l4.029 3.222A1.5 1.5 0 0 1 16 4.72v6.555a1.5 1.5 0 0 1-.563 1.171l-4.026 3.224a1.5 1.5 0 0 1-.937.329H5.529a1.5 1.5 0 0 1-.937-.328L.563 12.45A1.5 1.5 0 0 1 0 11.28V4.724a1.5 1.5 0 0 1 .563-1.171L4.589.329A1.5 1.5 0 0 1 5.526 0h4.945c.34 0 .67.116.937.328zM10.296 2H5.702L2 4.964v6.074L5.704 14h4.594L14 11.036V4.962L10.296 2zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="account" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.195 9.965l-.568-.875a.25.25 0 0 1 .015-.294l.405-.5a.25.25 0 0 1 .283-.075l.938.36c.257-.183.543-.325.851-.42l.322-.988A.25.25 0 0 1 11.679 7h.642a.25.25 0 0 1 .238.173l.322.988c.308.095.594.237.851.42l.938-.36a.25.25 0 0 1 .283.076l.405.5a.25.25 0 0 1 .015.293l-.568.875c.113.297.18.616.193.95l.898.54a.25.25 0 0 1 .115.27l-.144.626a.25.25 0 0 1-.222.193l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.281a.25.25 0 0 1-.29-.05l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.904a.25.25 0 0 1-.289.051l-.577-.281a.25.25 0 0 1-.138-.26l.165-1.18a3.015 3.015 0 0 1-.512-.607l-1.115-.098a.25.25 0 0 1-.222-.193l-.144-.626a.25.25 0 0 1 .115-.27l.898-.54c.013-.334.08-.653.193-.95zM6.789 8.023A12.845 12.845 0 0 0 6 8c-5.036 0-6 2.74-6 4.48C0 14.22.076 15 6 15c.553 0 1.055-.006 1.51-.02A5.977 5.977 0 0 1 6 11c0-1.083.287-2.1.79-2.977zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM12 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="admin" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.162 2.5a3.5 3.5 0 0 1-3.163 5.479L6.08 14.766a1.5 1.5 0 0 1-2.598-1.5L7.4 6.479A3.5 3.5 0 0 1 10.564 1L8.9 3.88l2.599 1.5 1.663-2.88zm-8.63 11.949a.5.5 0 1 0 .5-.866.5.5 0 0 0-.5.866z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.414 7.95l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 1 0 1.414-1.415L10.414 7.95zm-7 0l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 0 0 1.414-1.415L3.414 7.95z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.536 7.95L1.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 1 1-1.414-1.415L5.536 7.95zm7 0L8.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 0 1-1.414-1.415l4.243-4.242z"/></symbol><symbol viewBox="0 0 16 16" id="angle-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 10.243l-4.95-4.95a1 1 0 0 0-1.414 1.414l5.657 5.657a.997.997 0 0 0 1.414 0l5.657-5.657a1 1 0 0 0-1.414-1.414L8 10.243z"/></symbol><symbol viewBox="0 0 16 16" id="angle-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.757 8l4.95-4.95a1 1 0 1 0-1.414-1.414L3.636 7.293a.997.997 0 0 0 0 1.414l5.657 5.657a1 1 0 0 0 1.414-1.414L5.757 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.243 8l-4.95-4.95a1 1 0 0 1 1.414-1.414l5.657 5.657a.997.997 0 0 1 0 1.414l-5.657 5.657a1 1 0 0 1-1.414-1.414L10.243 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 6.757l-4.95 4.95a1 1 0 1 1-1.414-1.414l5.657-5.657a.997.997 0 0 1 1.414 0l5.657 5.657a1 1 0 0 1-1.414 1.414L8 6.757z"/></symbol><symbol viewBox="0 0 16 16" id="appearance" xmlns="http://www.w3.org/2000/svg"><path d="M11.161 12.456l.232.121c.1.053.175.094.249.137.53.318.844.75.857 1.402.012 1.397-1.116 1.756-3.12 1.858a23.85 23.85 0 0 1-1.38.026A8 8 0 0 1 0 8a8 8 0 0 1 8-8c4.417 0 7.998 3.582 7.998 7.977.06 2.621-1.312 3.586-4.48 3.648-.602.008-1.068.043-1.4.104.228.192.598.47 1.043.727zm-3.287-.943c-.019-1.495 1.228-1.856 3.611-1.888C13.67 9.582 14.028 9.33 13.998 8A6 6 0 1 0 8 14c.603 0 .91-.004 1.277-.023a9.7 9.7 0 0 0 .478-.035c-1.172-.738-1.868-1.47-1.88-2.43zM6 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-2-3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM4 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="applications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 1v2h2V1H7zm0 5h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm0 1v2h2V7h-2zM1 12h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm0 1v2h2v-2H1zm6-1h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm6 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="approval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.536 10.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 1 1 9.12 9.243l1.415 1.414zM7.632 8.109A2 2 0 0 0 7 11.364l2.121 2.121a1.996 1.996 0 0 0 2.807.021C11.686 14.554 10.627 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.6 0 1.142.038 1.632.109zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-down" xmlns="http://www.w3.org/2000/svg"><path d="M10.472 7.282a.862.862 0 0 1 1.26-.006c.357.364.357.958 0 1.285L8.627 11.73A.886.886 0 0 1 8 12a.849.849 0 0 1-.627-.27L4.275 8.561a.904.904 0 0 1-.013-1.285.861.861 0 0 1 1.26-.007l2.486 2.527z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 6H2a2 2 0 1 0 0 4h7v2.586a1 1 0 0 0 1.707.707l4.586-4.586a1 1 0 0 0 0-1.414l-4.586-4.586A1 1 0 0 0 9 3.414V6z"/></symbol><symbol viewBox="0 0 16 16" id="assignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 5V4a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V7h-1a1 1 0 0 1 0-2h1zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="bold" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4 12.5v-9A1.5 1.5 0 0 1 5.5 2h2.104c2.182 0 3.879.681 3.879 2.982 0 1.067-.517 2.227-1.374 2.595v.073C11.176 7.963 12 8.865 12 10.466 12 12.914 10.19 14 7.911 14H5.5A1.5 1.5 0 0 1 4 12.5zm2.376-5.696H7.49c1.164 0 1.665-.552 1.665-1.417 0-.94-.534-1.289-1.649-1.289h-1.13v2.706zm0 5.098h1.341c1.293 0 1.956-.515 1.956-1.62 0-1.049-.647-1.472-1.956-1.472H6.376v3.092z"/></symbol><symbol viewBox="0 0 16 16" id="book" xmlns="http://www.w3.org/2000/svg"><path d="M7 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2v4.191a.5.5 0 0 1-.724.447l-1.052-.526a.5.5 0 0 0-.448 0l-1.052.526A.5.5 0 0 1 7 6.191V2zM5 0h6a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="bookmark" xmlns="http://www.w3.org/2000/svg"><path d="M6.746 10.505a2 2 0 0 1 2.508 0L11 11.911V3H5v8.91l1.746-1.405zM5 1h6a2 2 0 0 1 2 2v10.999a1 1 0 0 1-1.627.779L8 12.064l-3.373 2.714A1 1 0 0 1 3 13.998V3a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="branch" xmlns="http://www.w3.org/2000/svg"><path d="M6 11.978v.29a2 2 0 1 1-2 0V3.732a2 2 0 1 1 2 0v3.849c.592-.491 1.31-.854 2.15-1.081 1.308-.353 1.875-.882 1.893-1.743a2 2 0 1 1 2.002-.051C12.053 6.54 10.857 7.84 8.67 8.43 7.056 8.867 6.195 9.98 6 11.978zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm6 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="bullhorn" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.143 10H7V4H3a3 3 0 1 0 0 6h.143l.734 5.141a1 1 0 0 0 .99.859h1.556a.5.5 0 0 0 .495-.57L6.143 10zM8 4c1.034.02 2.039-.274 3.014-.883.727-.455 1.836-1.334 3.328-2.637A1 1 0 0 1 16 1.233v10.764a1 1 0 0 1-1.595.803c-1.658-1.227-2.788-1.992-3.392-2.294-.781-.39-1.785-.559-3.013-.506V4z"/></symbol><symbol viewBox="0 0 16 16" id="calendar" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 2h2a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2h2V1a1 1 0 1 1 2 0v1h4V1a1 1 0 1 1 2 0v1zM0 4h16v9a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4zm2 2.5V13a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6.5a.5.5 0 0 0-.5-.5h-11a.5.5 0 0 0-.5.5zM5 8h2a1 1 0 1 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="cancel" xmlns="http://www.w3.org/2000/svg"><path d="M3.11 4.523a6 6 0 0 0 8.367 8.367L3.109 4.524zM4.522 3.11l8.368 8.368A6 6 0 0 0 4.524 3.11zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 16 16" id="chart" xmlns="http://www.w3.org/2000/svg"><path d="M15 14a1 1 0 0 1 0 2H2a2 2 0 0 1-2-2V1a1 1 0 1 1 2 0v13h13zM3.142 8.735l2.502-2.561a.5.5 0 0 1 .714-.003L8 7.833l3.592-4.553a.5.5 0 0 1 .796.015l2.516 3.454a.5.5 0 0 1 .096.295V12.5a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5V9.085a.5.5 0 0 1 .142-.35z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.078 8.2l3.535-3.536a2 2 0 0 1 2.828 2.828l-4.949 4.95c-.39.39-.902.586-1.414.586a1.994 1.994 0 0 1-1.414-.586l-4.95-4.95a2 2 0 1 1 2.828-2.828l3.536 3.535z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.977 7.998l3.535-3.535a2 2 0 1 0-2.828-2.828l-4.95 4.949c-.39.39-.586.902-.586 1.414 0 .512.196 1.024.586 1.414l4.95 4.95a2 2 0 1 0 2.828-2.828L7.977 7.998z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.22 7.998L4.683 4.463a2 2 0 0 1 2.828-2.828l4.95 4.949c.39.39.586.902.586 1.414a1.99 1.99 0 0 1-.586 1.414l-4.95 4.95a2 2 0 0 1-2.828-2.828l3.535-3.536z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.778 8.957l3.535 3.535a2 2 0 1 0 2.828-2.828l-4.949-4.95a1.994 1.994 0 0 0-1.414-.586c-.512 0-1.024.196-1.414.586l-4.95 4.95a2 2 0 1 0 2.828 2.828l3.536-3.535z"/></symbol><symbol viewBox="0 0 16 16" id="clock" xmlns="http://www.w3.org/2000/svg"><path d="M9 7h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V5a1 1 0 1 1 2 0v2zm-1 9A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.414 8l4.95-4.95a1 1 0 0 0-1.414-1.414L8 6.586l-4.95-4.95A1 1 0 0 0 1.636 3.05L6.586 8l-4.95 4.95a1 1 0 1 0 1.414 1.414L8 9.414l4.95 4.95a1 1 0 1 0 1.414-1.414L9.414 8z"/></symbol><symbol viewBox="0 0 16 16" id="code" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.871 8.243a.997.997 0 0 0-.293-.707L12.75 4.707a1 1 0 0 0-1.414 1.414l2.12 2.122-2.12 2.121a1 1 0 0 0 1.414 1.414l2.828-2.828a.997.997 0 0 0 .293-.707zm-13.243 0L4.75 6.12a1 1 0 1 0-1.414-1.414L.507 7.536a.997.997 0 0 0 0 1.414l2.829 2.828a1 1 0 1 0 1.414-1.414L2.628 8.243zm6.407-4.107a1 1 0 0 1 .707 1.225L8.19 11.157a1 1 0 1 1-1.931-.518L7.81 4.843a1 1 0 0 1 1.224-.707z"/></symbol><symbol viewBox="0 0 9 13" id="collapse"><path d="M.084.25C.01.18-.015.12.008.071.031.024.093 0 .194 0h8.521c.1 0 .162.024.185.072.023.048-.002.107-.075.177l-4.11 3.935a.372.372 0 0 1-.11.072h-.301a.508.508 0 0 1-.11-.072L.084.249zM.377 6.88a.364.364 0 0 1-.26-.105.334.334 0 0 1-.11-.25v-.709c0-.096.036-.179.11-.249a.364.364 0 0 1 .26-.105h8.15c.101 0 .188.035.261.105.074.07.11.153.11.25v.709c0 .096-.036.179-.11.249a.364.364 0 0 1-.26.105H.377zM.084 12.132c-.074.07-.099.129-.076.177.023.048.085.072.186.072h8.521c.1 0 .162-.024.185-.072.023-.048-.002-.107-.075-.177l-4.11-3.935a.372.372 0 0 0-.11-.072h-.301a.508.508 0 0 0-.11.072l-4.11 3.935z"/></symbol><symbol viewBox="0 0 16 16" id="comment" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comment-dots" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586zM5 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="comment-next" xmlns="http://www.w3.org/2000/svg"><path d="M8 5V4a.5.5 0 0 1 .8-.4l2.667 2a.5.5 0 0 1 0 .8L8.8 8.4A.5.5 0 0 1 8 8V7H6a1 1 0 1 1 0-2h2zM1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comments" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.75 10L0 13V3a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H3.75zM13 5h1a2 2 0 0 1 2 2v8l-2.667-2H8a2 2 0 0 1-2-2h4a3 3 0 0 0 3-3V5z"/></symbol><symbol viewBox="0 0 16 16" id="commit" xmlns="http://www.w3.org/2000/svg"><path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3.876-1.008a4.002 4.002 0 0 1-7.752 0A1.01 1.01 0 0 1 4 9H1a1 1 0 1 1 0-2h3c.042 0 .083.003.124.008a4.002 4.002 0 0 1 7.752 0A1.01 1.01 0 0 1 12 7h3a1 1 0 0 1 0 2h-3a1.01 1.01 0 0 1-.124-.008z"/></symbol><symbol viewBox="0 0 16 16" id="credit-card" xmlns="http://www.w3.org/2000/svg"><path d="M14 5a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1h12zm0 3H2v3a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V8zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm6.5 8h3a.5.5 0 1 1 0 1h-3a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="cut" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="2" y="7" fill-rule="evenodd" rx="1"/></symbol><symbol viewBox="0 0 16 16" id="dashboard" xmlns="http://www.w3.org/2000/svg"><path d="M7.709 10.021l.696-2.6a.5.5 0 0 1 .966.26l-.657 2.45A2 2 0 0 1 10 12H6a2 2 0 0 1 1.709-1.979zM0 8.9a8 8 0 0 1 15.998 0H16v3.6a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5V8.9zM14 9A6 6 0 1 0 2 9v3.5a.5.5 0 0 0 .5.5h11a.5.5 0 0 0 .5-.5V9zM3.5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm9 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-7-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm5 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1z"/></symbol><symbol viewBox="0 0 16 16" id="disk" xmlns="http://www.w3.org/2000/svg"><path d="M16 11.764V3a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3v8.764A2.989 2.989 0 0 1 2 11V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v8c.768 0 1.47.289 2 .764zM2 12h12a2 2 0 1 1 0 4H2a2 2 0 1 1 0-4zm10 1a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="doc_code" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zm1.036 7.607a.498.498 0 0 1-.147.354l-1.414 1.414a.5.5 0 0 1-.707-.707l1.06-1.06-1.06-1.061a.5.5 0 0 1 .707-.707l1.414 1.414a.498.498 0 0 1 .147.353zm-4.822 0l1.06 1.061a.5.5 0 0 1-.706.707l-1.414-1.414a.498.498 0 0 1 0-.707l1.414-1.414a.5.5 0 1 1 .707.707l-1.06 1.06zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="doc_image" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM7.333 9.667l1.313-1.313a.5.5 0 0 1 .708 0L12 11H4l2.188-1.75a.5.5 0 0 1 .624 0l.521.417zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4 11h8v.7a.3.3 0 0 1-.3.3H4.3a.3.3 0 0 1-.3-.3V11z"/></symbol><symbol viewBox="0 0 16 16" id="doc_text" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 11h5a.5.5 0 1 1 0 1h-5a.5.5 0 1 1 0-1zm0-2h5a.5.5 0 1 1 0 1h-5a.5.5 0 0 1 0-1zm0-2h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z"/></symbol><symbol viewBox="0 0 105 26" id="double-headed-arrow" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.018 11.089L15.138.614c1.23-.911 3.086-.795 4.147.26.461.46.715 1.045.715 1.651v20.95C20 24.869 18.684 26 17.06 26a3.238 3.238 0 0 1-1.921-.614L1.019 14.911C-.212 14-.347 12.405.714 11.35c.094-.094.195-.18.303-.261zm102.964 0c.108.08.21.167.303.26 1.061 1.056.925 2.65-.303 3.562l-14.12 10.475A3.238 3.238 0 0 1 87.94 26C86.316 26 85 24.87 85 23.475V2.525c0-.606.254-1.192.715-1.65 1.061-1.056 2.917-1.172 4.146-.26l14.12 10.474zM35 17a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="download" xmlns="http://www.w3.org/2000/svg"><path d="M9 12h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0l-2-2.667A.5.5 0 0 1 6 12h1V8a1 1 0 1 1 2 0v4zM4 9a1 1 0 1 1 0 2 4 4 0 0 1-1.971-7.481 4 4 0 0 1 6.633-2.505 3.999 3.999 0 0 1 3.82 2.014A4 4 0 0 1 12 11a1 1 0 0 1 0-2 2 2 0 1 0 0-4h-1a2 2 0 0 0-3.112-1.662A2 2 0 1 0 4.268 5H4a2 2 0 1 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M14 10h-3a1 1 0 0 1-1-1V6H8.527A.527.527 0 0 0 8 6.527V13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-3zm-4-7H8.527c-.18 0-.355.013-.527.04V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2v2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3zM8.527 4h2.323a.5.5 0 0 1 .35.143l4.65 4.551a.5.5 0 0 1 .15.357V13a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V6.527A2.527 2.527 0 0 1 8.527 4z"/></symbol><symbol viewBox="0 0 16 16" id="earth" xmlns="http://www.w3.org/2000/svg"><path d="M8.7 2.04l-.082.177c.283.223.422.413.417.571-.008.237-.311.057-.444.274-.133.218.038.542-.112.637-.15.096-.398-.386-.479-.46-.054-.049-.166-.257-.336-.625l-.216-.225a.844.844 0 0 0-.418-.035c-.177.038-.075.1-.035.132.04.032.32.037.452.2.132.164.03.224-.05.298-.054.05-.157.062-.31.035H5.952l-.402.398.03.325.229.455.324-.463c.008-.206.058-.342.15-.41.14-.1.342-.15.534-.085.191.066-.057.218.011.271.068.053.204-.098.313-.02.11.08.07.155.104.322.036.167.254.114.398.328.144.215.19.29.147.483-.043.195-.168.26-.305.232-.138-.028-.107-.246-.275-.348-.168-.102-.266-.114-.386-.054-.12.06-.016.129.023.235.04.106.274.321.224.43-.05.107-.108.116-.42 0-.21-.077-.414-.007-.615.212l-.76.722c-.153.715-.3 1.13-.44 1.243-.211.17-.177-.483-.483-.656-.306-.174-.494-.047-.8-.07-.307-.023-.42.65-.38.873a.434.434 0 0 0 .221.321c.236-.141.39-.184.465-.128.11.084-.144.267-.074.425.07.158.314.069.386.283.073.213.084.48-.05.706-.135.227-.275.178-.4.053-.127-.126-.033-.375-.255-.704-.223-.329-.381-.337-.63-.787-.158-.287-.35-.743-.575-1.366a6 6 0 0 0 3.21 7.198l.001-.075c0-.577-.004-.944-.012-1.102-.011-.236-.95-.945-1.104-1.2-.154-.256-.34-.595-.355-.746-.016-.151.185-.232.344-.325.16-.093-.11-.367.028-.626.137-.258.395-.438.496-.356.101.081.058.228.267.333.209.104.077-.213.456-.178.38.035.143.201.252.216.11.016.113-.127.299-.143.186-.015.282.445.471.622.19.178.452.008.611.043.159.034.267.09.402.255.136.166-.03.352.073.557.103.205 1.07.22 1.433.255.364.034.371.011.371.324s-.166.314-.453.507c-.286.193-.166.462-.38.762-.212.3-.316.062-.622.14-.306.077-.413.382-.452.568-.039.186-.386.094-.877.232-.29.082-.429.144-.569.204a6.002 6.002 0 0 0 7.682-4.3c-.094-.384-.18-.63-.258-.74-.213-.297-.36.21-.924.49-.564.278-.57-.288-.81-.49-.16-.133-.212-.44-.158-.92-.005-.478.02-.828.077-1.049.057-.221.126-.543.207-.965.351-.373.606-.572.764-.595.237-.034.336.374.658.3a.315.315 0 0 0 .035-.01 5.993 5.993 0 0 0-.475-.824l-.309-.043a.646.646 0 0 0-.332-.117c-.205-.02-.025.128-.089.24-.064.112-.235.724-.437.685-.201-.039-.204-.374-.17-.668.036-.294-.077-.35-.2-.412-.124-.062-.325-.213-.556-.295-.232-.082-.123-.175-.093-.274.03-.1.208-.015.193-.058-.014-.044-.313-.135-.266-.167.03-.02.2-.02.506.003l.216-.012.293-.163a.58.58 0 0 0-.376-.22c-.233-.036-.513-.034-.73-.142-.205-.103-.458-.36-.643-.638A5.965 5.965 0 0 0 8.7 2.04zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 1600 1600" id="ellipsis_v" xmlns="http://www.w3.org/2000/svg"><path d="M1088 1248v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V736q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V224q0-40 28-68t68-28h192q40 0 68 28t28 68z"/></symbol><symbol viewBox="0 0 18 18" id="emoji_slightly_smiling_face" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369.721.721 0 0 1 .568.047.715.715 0 0 1 .37.445 2.91 2.91 0 0 0 1.084 1.518A2.93 2.93 0 0 0 9 12.75a2.93 2.93 0 0 0 1.775-.58 2.913 2.913 0 0 0 1.084-1.518.711.711 0 0 1 .375-.445.737.737 0 0 1 .575-.047c.195.063.34.186.433.37.094.183.11.372.047.568zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smile" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568zM14 6.37c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm-6.5 0c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm9 2.63a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smiley" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568h.001zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6c.92.397 1.91.6 2.912.598a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39c.397-.92.6-1.91.598-2.912zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z"/></symbol><symbol viewBox="0 0 16 16" id="epic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.985 8.044l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637A2 2 0 0 0 1.618 9h11.661a2 2 0 0 0 1.706-.956zm0 3l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637a2 2 0 0 0 .576.084h11.661a2 2 0 0 0 1.706-.956zM3.618 2h10.995a1 1 0 0 1 .948 1.316l-1.333 4a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l2-4A1 1 0 0 1 3.618 2zm-.382 4h9.322l.667-2H4.236l-1 2z"/></symbol><symbol viewBox="0 0 16 16" id="external-link" xmlns="http://www.w3.org/2000/svg"><path d="M13.121 4.177l-4.95 4.95a1 1 0 1 1-1.414-1.414l4.95-4.95-1.386-1.386a.5.5 0 0 1 .299-.85l4.709-.524a.5.5 0 0 1 .552.552l-.523 4.71a.5.5 0 0 1-.851.297l-1.386-1.385zM12 8.884a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-4z"/></symbol><symbol viewBox="0 0 16 16" id="eye" xmlns="http://www.w3.org/2000/svg"><path d="M8 14C4.816 14 2.253 12.284.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2s5.747 1.716 7.607 5.019a2 2 0 0 1 0 1.962C13.747 12.284 11.184 14 8 14zm0-2c2.41 0 4.338-1.29 5.864-4C12.338 5.29 10.411 4 8 4 5.59 4 3.662 5.29 2.136 8 3.662 10.71 5.589 12 8 12zm0-1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm1-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="eye-slash" xmlns="http://www.w3.org/2000/svg"><path d="M13.618 2.62L1.62 14.619a1 1 0 0 1-.985-1.668l1.525-1.526C1.516 10.742.926 9.927.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2c1.074 0 2.076.195 3.006.58l.944-.944a1 1 0 0 1 1.668.985zM8.068 11a3 3 0 0 0 2.931-2.932l-2.931 2.931zm-3.02-2.462a3 3 0 0 1 3.49-3.49l.884-.884A6.044 6.044 0 0 0 8 4C5.59 4 3.662 5.29 2.136 8c.445.79.924 1.46 1.439 2.011l1.473-1.473zm.421 5.06l1.658-1.658c.283.04.575.06.873.06 2.41 0 4.338-1.29 5.864-4a11.023 11.023 0 0 0-1.133-1.664l1.418-1.418a12.799 12.799 0 0 1 1.458 2.1 2 2 0 0 1 0 1.963C13.747 12.284 11.184 14 8 14a7.883 7.883 0 0 1-2.53-.402z"/></symbol><symbol viewBox="0 0 16 16" id="file-addition" xmlns="http://www.w3.org/2000/svg"><path d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3z"/></symbol><symbol viewBox="0 0 16 16" id="file-deletion" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm2 6h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="file-modified" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm5 4a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/></symbol><symbol viewBox="0 0 16 16" id="filter" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 6v9l-3.724-1.862A.5.5 0 0 1 6 12.691V6L1.854 1.854A.5.5 0 0 1 2.207 1h11.586a.5.5 0 0 1 .353.854L10 6z"/></symbol><symbol viewBox="0 0 16 16" id="folder" xmlns="http://www.w3.org/2000/svg"><path d="M13 3a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="folder-o" xmlns="http://www.w3.org/2000/svg"><path d="M13 5l-4.365-.005a2 2 0 0 1-1.882-1.33A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1zm0-2a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="folder-open" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.59 5.464a2.998 2.998 0 0 1 1.096 3.845l-1.666 3.436A4 4 0 0 1 10.46 15H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.558a2 2 0 0 1 1.898 1.368l.21.632h4.973a2 2 0 0 1 2 2 2 2 0 0 1-.027.329l-.023.135zM5.285 7a1 1 0 0 0-.9.564l-1.939 4a1 1 0 0 0 .9 1.436h7.074a2 2 0 0 0 1.8-1.128l1.665-3.436a1 1 0 0 0-.9-1.436h-7.7z"/></symbol><symbol viewBox="0 0 16 16" id="fork" xmlns="http://www.w3.org/2000/svg"><path d="M9 12.268a2 2 0 1 1-2 0V8.874A4.002 4.002 0 0 1 4 5V3.732a2 2 0 1 1 2 0V5a2 2 0 1 0 4 0V3.732a2 2 0 1 1 2 0V5a4.002 4.002 0 0 1-3 3.874v3.394zM11 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm3 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="geo-nodes" xmlns="http://www.w3.org/2000/svg"><path d="M9.7 13.1l-.2.2c-.7.8-2 .9-2.8.1-.1 0-.1-.1-.1-.1l-.2-.2c-2 .2-3.4.7-3.4 1.4 0 .8 2.2 1.5 5 1.5s5-.7 5-1.5c0-.7-1.4-1.2-3.3-1.4M7.3 12.7c.4.4 1 .3 1.4-.1C11.6 9.5 13 7 13 5.3 13 2.4 10.8 0 8 0S3 2.4 3 5.3C3 7 4.4 9.5 7.3 12.7M8 2c1.6 0 3 1.4 3 3.3 0 1-1 2.8-3 5.2-2-2.4-3-4.2-3-5.2C5 3.4 6.4 2 8 2"/><circle cx="8" cy="5" r="1"/></symbol><symbol viewBox="0 0 16 16" id="git-merge" xmlns="http://www.w3.org/2000/svg"><path d="M11 12.268V5a1 1 0 0 0-1-1v1a.5.5 0 0 1-.8.4l-2.667-2a.5.5 0 0 1 0-.8L9.2.6a.5.5 0 0 1 .8.4v1a3 3 0 0 1 3 3v7.268a2 2 0 1 1-2 0zm-6 0a2 2 0 1 1-2 0V4.732a2 2 0 1 1 2 0v7.536zM4 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="group" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.048 11.997C-.377 11.975.013 11.782.013 10.56.013 9.235.653 8 4 8c.444 0 .84.022 1.194.062.164.435.426.82.76 1.132-1.786.389-2.721 1.353-2.906 2.803zm2.94-7.222a2.993 2.993 0 0 0-.976 1.95 2 2 0 1 1 .975-1.95zm6.964 7.222c-.185-1.45-1.12-2.414-2.906-2.803.334-.311.596-.697.76-1.132C11.16 8.022 11.556 8 12 8c3.346 0 3.987 1.235 3.987 2.56 0 1.222.39 1.415-3.035 1.437zm-1.964-5.272a2.993 2.993 0 0 0-.976-1.95 2 2 0 1 1 .976 1.95zM8 9a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 5c-2.177 0-3.987-.115-3.987-1.44S4.653 10 8 10c3.346 0 3.987 1.235 3.987 2.56S10.177 14 8 14z"/></symbol><symbol viewBox="0 0 16 16" id="history" xmlns="http://www.w3.org/2000/svg"><path d="M2.868 3.24a7 7 0 1 1-.043 9.475 1 1 0 0 1 1.478-1.348 5 5 0 1 0 .124-6.865l.796.645a.5.5 0 0 1-.193.873l-3.232.814a.5.5 0 0 1-.622-.504L1.3 3a.5.5 0 0 1 .814-.37l.754.61zM9 8h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V6a1 1 0 1 1 2 0v2z"/></symbol><symbol viewBox="0 0 16 16" id="home" xmlns="http://www.w3.org/2000/svg"><path d="M9 13h3v-3H4v3h3v-1a1 1 0 0 1 2 0v1zm5-3v3.659c0 .729-.657 1.341-1.5 1.341h-9c-.843 0-1.5-.612-1.5-1.341V10h-.88C.502 10 0 9.486 0 8.853c0-.307.12-.601.333-.816l6.405-6.463a1.56 1.56 0 0 1 2.374-.052L15.66 8.03c.444.441.455 1.167.024 1.622a1.108 1.108 0 0 1-.804.348H14zM7.95 3.273l-4.595 4.64h9.264l-4.67-4.64z"/></symbol><symbol viewBox="0 0 16 16" id="hook" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1h4zm0 1H6v1a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V4zM7 8a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3v4a2 2 0 1 0 4 0h-.44a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H15a4 4 0 0 1-7 2.646A4 4 0 0 1 1 12H.56a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H3a2 2 0 1 0 4 0V8z"/></symbol><symbol viewBox="0 0 16 16" id="hourglass" xmlns="http://www.w3.org/2000/svg"><path d="M10.331 4.889A2.988 2.988 0 0 0 11 3V2H5v1c0 .362.064.709.182 1.03l5.15.859zM3 14v-1c0-1.78.93-3.342 2.33-4.228.447-.327.67-.582.67-.764 0-.19-.242-.46-.725-.815A4.996 4.996 0 0 1 3 3V2H2a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2h-1v1a4.997 4.997 0 0 1-2.39 4.266c-.407.3-.61.545-.61.734 0 .19.203.434.61.734A4.997 4.997 0 0 1 13 13v1h1a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2h1zm8 0v-1a3 3 0 0 0-6 0v1h6z"/></symbol><symbol viewBox="0 0 38 38" id="image-comment-dark" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="19" cy="19" r="18" fill="#1F78D1"/><path fill="#FFF" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-2c9.389 0 17-7.611 17-17S28.389 2 19 2 2 9.611 2 19s7.611 17 17 17zm-6.293-8.293c-.63.63-1.707.184-1.707-.707V15a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-7.586l-3.707 3.707zM13 24.586l2.293-2.293A1 1 0 0 1 16 22h8a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1H14a1 1 0 0 0-1 1v9.586z"/></g></symbol><symbol viewBox="0 0 38 38" id="image-comment-light" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="19" cy="19" r="18" fill="#FFF"/><path fill="#1F78D1" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-2c9.389 0 17-7.611 17-17S28.389 2 19 2 2 9.611 2 19s7.611 17 17 17zm-6.293-8.293c-.63.63-1.707.184-1.707-.707V15a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-7.586l-3.707 3.707zM13 24.586l2.293-2.293A1 1 0 0 1 16 22h8a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1H14a1 1 0 0 0-1 1v9.586z"/></g></symbol><symbol viewBox="0 0 16 16" id="import" xmlns="http://www.w3.org/2000/svg"><path d="M9 8h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0L5.6 8.8A.5.5 0 0 1 6 8h1V1a1 1 0 1 1 2 0v7zM0 8a1 1 0 1 1 2 0 6 6 0 1 0 12 0 1 1 0 0 1 2 0A8 8 0 1 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-block" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.803 8a5.97 5.97 0 0 0-.462 1H4.5a.5.5 0 0 1 0-1h1.303zM4.5 5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1zm7.5.083a6.04 6.04 0 0 0-2 0V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2.083a5.96 5.96 0 0 0 .72 2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h6a3 3 0 0 1 3 3v2.083zm1.121 3.796zM11 16a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm-1.293-2.292a3 3 0 0 0 4.001-4.001l-4.001 4zm-1.415-1.415l4.001-4a3 3 0 0 0-4.001 4.001z"/></symbol><symbol viewBox="0 0 16 16" id="issue-child" xmlns="http://www.w3.org/2000/svg"><path d="M11 8H5v1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h2V7a.997.997 0 0 1 1-1h3V4H4.5a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9v2h3a.997.997 0 0 1 1 1v2h2a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm-9 3v2h3v-2H2zm9 0v2h3v-2h-3z"/></symbol><symbol viewBox="0 0 16 16" id="issue-close" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M10.874 2H12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-2c-.918 0-1.74-.413-2.29-1.063a3.987 3.987 0 0 0 1.988-.984A1 1 0 0 0 10 14h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-1V3c0-.345-.044-.68-.126-1zM4 0h3a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-external" xmlns="http://www.w3.org/2000/svg"><path d="M11 4a5.99 5.99 0 0 0-2 .341V3a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h2.528a6.003 6.003 0 0 0 2.705 1.736A2.99 2.99 0 0 1 8 16H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3v1zM8.212 8.97l-.568-.876A.25.25 0 0 1 7.66 7.8l.404-.5a.25.25 0 0 1 .284-.076l.938.36c.256-.182.543-.325.85-.42l.323-.988a.25.25 0 0 1 .237-.173h.643a.25.25 0 0 1 .238.173l.321.989c.308.094.595.237.852.418l.937-.359a.25.25 0 0 1 .284.076l.404.5a.25.25 0 0 1 .016.293l-.568.875c.113.297.18.616.192.95l.9.54a.25.25 0 0 1 .114.27l-.145.627a.25.25 0 0 1-.221.192l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.282a.25.25 0 0 1-.29-.051l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.905a.25.25 0 0 1-.29.05l-.577-.281a.25.25 0 0 1-.138-.26L9 12.254a3.015 3.015 0 0 1-.512-.607l-1.114-.098a.25.25 0 0 1-.222-.192l-.145-.627a.25.25 0 0 1 .115-.27l.899-.54c.012-.334.08-.653.192-.95zm2.806 2.034a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="issue-new" xmlns="http://www.w3.org/2000/svg"><path d="M10 2V1a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V4H9a1 1 0 1 1 0-2h1zm0 6a1 1 0 0 1 2 0v5a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h1a1 1 0 1 1 0 2H5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm0-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open-m" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-parent" xmlns="http://www.w3.org/2000/svg"><path d="M11 11H5v1h1.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H3v-2a.997.997 0 0 1 1-1h3V7H5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H9v2h3a.997.997 0 0 1 1 1v2h2.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H11v-1zM6 3v2h4V3H6z"/></symbol><symbol viewBox="0 0 16 16" id="issues" xmlns="http://www.w3.org/2000/svg"><path d="M10.458 15.012l.311.055a3 3 0 0 0 3.476-2.433l1.389-7.879A3 3 0 0 0 13.2 1.28L11.23.933a3.002 3.002 0 0 0-.824-.031c.364.59.58 1.28.593 2.02l1.854.328a1 1 0 0 1 .811 1.158l-1.389 7.879a1 1 0 0 1-1.158.81l-.118-.02a3.98 3.98 0 0 1-.541 1.935zM3 0h4a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="italic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.5 12l2-8H6a1 1 0 1 1 0-2h6a1 1 0 0 1 0 2h-1.5l-2 8H10a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2h1.5z"/></symbol><symbol viewBox="0 0 16 16" id="key" xmlns="http://www.w3.org/2000/svg"><path d="M7.575 6.689a4.002 4.002 0 0 1 6.274-4.86 4 4 0 0 1-4.86 6.274l-2.21 2.21.706.708a1 1 0 1 1-1.414 1.414l-.707-.707-.707.707.707.707a1 1 0 1 1-1.414 1.414l-.707-.707a1 1 0 0 1-1.414-1.414l5.746-5.746zm2.032-.618a2 2 0 1 0 2.828-2.828A2 2 0 0 0 9.607 6.07z"/></symbol><symbol viewBox="0 0 16 16" id="key-2" xmlns="http://www.w3.org/2000/svg"><path d="M5.172 14.157l-.344.344-2.485.133a.462.462 0 0 1-.497-.503l.14-2.24a.599.599 0 0 1 .177-.382l5.155-5.155a4 4 0 1 1 2.828 2.828l-1.439 1.44-1.06-.354-.708.707.354 1.06-.707.708-1.06-.354-.708.707.354 1.06zm6.01-8.839a1 1 0 1 0 1.414-1.414 1 1 0 0 0-1.414 1.414z"/></symbol><symbol viewBox="0 0 16 16" id="label" xmlns="http://www.w3.org/2000/svg"><path d="M11.782 14.718a3 3 0 0 1-4.242 0L1.652 8.829a2 2 0 0 1-.565-1.702l.54-3.703a2 2 0 0 1 1.69-1.69l3.703-.54a2 2 0 0 1 1.703.564l5.888 5.888a3 3 0 0 1 0 4.243l-2.829 2.829zm1.415-5.657L7.309 3.173l-3.703.54-.54 3.702 5.888 5.888a1 1 0 0 0 1.414 0l2.829-2.828a1 1 0 0 0 0-1.414zM5.732 5.525A1 1 0 1 1 7.146 6.94a1 1 0 0 1-1.414-1.414z"/></symbol><symbol viewBox="0 0 16 16" id="labels" xmlns="http://www.w3.org/2000/svg"><path d="M9.424 2.254l2.08-.905a1 1 0 0 1 1.206.326l3.013 4.12a1 1 0 0 1 .16.849l-1.947 7.264a3 3 0 0 1-3.675 2.122l-.5-.135a3.999 3.999 0 0 0 1.082-1.782 1 1 0 0 0 1.16-.722l1.823-6.802-2.258-3.087-.687.299a2 2 0 0 0-.628-.88l-.829-.667zM.377 3.7L4.4.498a1 1 0 0 1 1.25.003L9.627 3.7a1 1 0 0 1 .373.78V13a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4.482A1 1 0 0 1 .377 3.7zM2 13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V4.958L5.02 2.561 2 4.964V13zm3-6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="leave" xmlns="http://www.w3.org/2000/svg"><path d="M11 7V5.883a.5.5 0 0 1 .757-.429l3.528 2.117a.5.5 0 0 1 0 .858l-3.528 2.117a.5.5 0 0 1-.757-.43V9H7a1 1 0 1 1 0-2h4zm-2 6.256a1 1 0 0 1 2 0A2.744 2.744 0 0 1 8.256 16H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h5.19A2.81 2.81 0 0 1 11 2.81a1 1 0 0 1-2 0A.81.81 0 0 0 8.19 2H3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h5.256c.41 0 .744-.333.744-.744z"/></symbol><symbol viewBox="0 0 16 16" id="level-up" xmlns="http://www.w3.org/2000/svg"><path fill="#2E2E2E" fill-rule="evenodd" d="M7 6h3.489a.5.5 0 0 0 .373-.832L6.374.117a.5.5 0 0 0-.748 0l-4.488 5.05A.5.5 0 0 0 1.51 6H5v7a3 3 0 0 0 3 3h6a1 1 0 0 0 0-2H8a1 1 0 0 1-1-1V6z"/></symbol><symbol viewBox="0 0 16 16" id="license" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12.56 8.9l2.66 4.606a.3.3 0 0 1-.243.45l-1.678.094a.1.1 0 0 0-.078.044l-.953 1.432a.3.3 0 0 1-.51-.016L9.097 10.9a5.994 5.994 0 0 0 3.464-2zm-5.23 2.063L4.707 15.51a.3.3 0 0 1-.51.016l-.953-1.432a.1.1 0 0 0-.078-.044l-1.678-.094a.3.3 0 0 1-.243-.45l2.48-4.297a5.983 5.983 0 0 0 3.607 1.754zM8 10A5 5 0 1 1 8 0a5 5 0 0 1 0 10zm0-2a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-1a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="link" xmlns="http://www.w3.org/2000/svg"><path d="M6.986 3.35l2.12-2.122a4 4 0 0 1 5.657 5.657l-2.828 2.829a4 4 0 0 1-5.657 0 1 1 0 0 1 1.414-1.415 2 2 0 0 0 2.829 0l2.828-2.828a2 2 0 1 0-2.828-2.828l-1.001 1a5.018 5.018 0 0 0-2.534-.294zm2.12 9.192l-2.12 2.121a4 4 0 1 1-5.658-5.656l2.829-2.829a4 4 0 0 1 5.657 0 1 1 0 1 1-1.415 1.414 2 2 0 0 0-2.828 0l-2.828 2.829a2 2 0 1 0 2.828 2.828l1.001-1.001a5.018 5.018 0 0 0 2.534.294z"/></symbol><symbol viewBox="0 0 16 16" id="list-bulleted" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-7h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 5h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm-4 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-2h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="list-numbered" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 2h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2zM1.156 5v-.828h.816V2.204h-.72v-.636c.432-.084.708-.192.996-.372h.756v2.976h.684V5H1.156zm-.18 5v-.588c.9-.828 1.596-1.464 1.596-1.98 0-.342-.192-.504-.468-.504-.252 0-.444.18-.624.36l-.552-.552c.396-.42.756-.612 1.32-.612.768 0 1.308.492 1.308 1.248 0 .612-.576 1.284-1.092 1.812.192-.024.468-.048.636-.048h.636V10H.976zm1.26 5.072c-.618 0-1.068-.204-1.356-.54l.468-.648c.234.216.51.36.78.36.336 0 .552-.12.552-.36 0-.288-.15-.456-.948-.456v-.72c.636 0 .828-.168.828-.432 0-.228-.138-.348-.396-.348-.252 0-.432.108-.672.312l-.516-.624c.372-.312.768-.492 1.236-.492.84 0 1.38.384 1.38 1.074 0 .366-.204.642-.612.822v.024c.432.132.732.432.732.912 0 .72-.684 1.116-1.476 1.116z"/></symbol><symbol viewBox="0 0 16 16" id="location" xmlns="http://www.w3.org/2000/svg"><path d="M8.755 15.144a1 1 0 0 1-1.51 0C3.748 11.114 2 8.065 2 6a6 6 0 1 1 12 0c0 2.065-1.748 5.113-5.245 9.144zM12 6a4 4 0 1 0-8 0c0 1.314 1.312 3.71 4 6.944C10.688 9.71 12 7.314 12 6zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="location-dot" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.314 13.087C4.382 13.295 3 13.85 3 14.5c0 .828 2.239 1.5 5 1.5s5-.672 5-1.5c0-.65-1.382-1.205-3.314-1.413l-.202.225a2 2 0 0 1-2.968 0l-.202-.225zm2.428-.445a1 1 0 0 1-1.484 0C4.419 9.5 3 7.037 3 5.252 3 2.353 5.239 0 8 0s5 2.352 5 5.253c0 1.784-1.42 4.247-4.258 7.389zM11 5.252C11 3.436 9.634 2 8 2S5 3.435 5 5.253c0 1.027.974 2.824 3 5.203 2.026-2.38 3-4.176 3-5.203zM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="lock" xmlns="http://www.w3.org/2000/svg"><path d="M10 5V4h2v1a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V8a3 3 0 0 1 3-3V4h2v1h4zM4 7a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H4zm0-3a4 4 0 1 1 8 0h-2a2 2 0 1 0-4 0H4z"/></symbol><symbol viewBox="0 0 16 16" id="lock-open" xmlns="http://www.w3.org/2000/svg"><path d="M4.044 4a4 4 0 0 1 6.99-2.658 1 1 0 1 1-1.495 1.33A2 2 0 0 0 6.044 4a.998.998 0 0 1-.07.367v.701H12a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3v-5a3 3 0 0 1 2.974-3V4h.07zM4 7.07a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="log" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4zm1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-5h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm0 3h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm-3 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-2h3a1 1 0 0 1 0 2H8a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="mail" xmlns="http://www.w3.org/2000/svg"><path d="M14 5.6L9.338 9.796a2 2 0 0 1-2.676 0L2 5.6V11a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5.6zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm.212 2L8 8.31 12.788 4H3.212z"/></symbol><symbol viewBox="0 0 16 16" id="menu" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.143 2h13.714C15.488 2 16 2.448 16 3s-.512 1-1.143 1H1.143C.512 4 0 3.552 0 3s.512-1 1.143-1zm0 5h13.714C15.488 7 16 7.448 16 8s-.512 1-1.143 1H1.143C.512 9 0 8.552 0 8s.512-1 1.143-1zm0 5h13.714c.631 0 1.143.448 1.143 1s-.512 1-1.143 1H1.143C.512 14 0 13.552 0 13s.512-1 1.143-1z"/></symbol><symbol viewBox="0 0 16 16" id="merge-request-close" xmlns="http://www.w3.org/2000/svg"><path d="M9.414 8l1.414 1.414a1 1 0 1 1-1.414 1.414L8 9.414l-1.414 1.414a1 1 0 1 1-1.414-1.414L6.586 8 5.172 6.586a1 1 0 1 1 1.414-1.414L8 6.586l1.414-1.414a1 1 0 1 1 1.414 1.414L9.414 8zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="messages" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-.98-1.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM4.464 2.464L5.88 3.88a3 3 0 0 0 0 4.242L4.464 9.536a5 5 0 0 1 0-7.072zm7.072 7.072L10.12 8.12a3 3 0 0 0 0-4.242l1.415-1.415a5 5 0 0 1 0 7.072zM2.343.343l1.414 1.414a6 6 0 0 0 0 8.486l-1.414 1.414a8 8 0 0 1 0-11.314zm11.314 11.314l-1.414-1.414a6 6 0 0 0 0-8.486L13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="mobile-issue-close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.657 10.728L2.12 7.192A1 1 0 1 0 .707 8.607l4.243 4.242a.997.997 0 0 0 1.414 0l8.485-8.485a1 1 0 1 0-1.414-1.414l-7.778 7.778z"/></symbol><symbol viewBox="0 0 16 16" id="monitor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 13v1h3a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2h3v-1H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3h-3zM3 2a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm5.723 6.416l-2.66-1.773-1.71 1.71a.5.5 0 1 1-.707-.707l2-2a.5.5 0 0 1 .631-.062l2.66 1.773 2.71-2.71a.5.5 0 0 1 .707.707l-3 3a.5.5 0 0 1-.631.062z"/></symbol><symbol viewBox="0 0 16 16" id="more" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 4a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="notifications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 14H2.435a2 2 0 0 1-1.761-2.947c.962-1.788 1.521-3.065 1.68-3.832.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024c3.755.528 4.375 4.27 4.761 6.043.188.86.742 2.188 1.661 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0zm5.805-6.468c-.325-1.492-.37-1.674-.61-2.288C10.6 3.716 9.742 3 8.07 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.208 1.012-.827 2.424-1.877 4.375H13.64c-.993-1.937-1.6-3.396-1.835-4.468z"/></symbol><symbol viewBox="0 0 16 16" id="notifications-off" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.26 5.089c.243.757.382 1.478.5 2.017.187.86.74 2.188 1.66 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0H4.35l2-2h7.29c-.993-1.937-1.6-3.396-1.835-4.468-.07-.326-.129-.59-.178-.81l1.634-1.633zM10.943 1.75l-1.48 1.48C9.07 3.076 8.612 3 8.069 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.065.317-.17.673-.317 1.073L.45 12.242a1.99 1.99 0 0 1 .224-1.19c.962-1.787 1.521-3.064 1.68-3.831.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024 4.867 4.867 0 0 1 1.944.688zm2.932-.105a1 1 0 0 1 0 1.415L2.561 14.374a1 1 0 1 1-1.415-1.414L12.46 1.646a1 1 0 0 1 1.414 0z"/></symbol><symbol viewBox="0 0 16 16" id="overview" xmlns="http://www.w3.org/2000/svg"><path d="M2 0h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2h-3zM2 9h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3h-3z"/></symbol><symbol viewBox="0 0 16 16" id="pencil" xmlns="http://www.w3.org/2000/svg"><path d="M13.02 1.293l1.414 1.414a1 1 0 0 1 0 1.414L4.119 14.436a1 1 0 0 1-.704.293l-2.407.008L1 12.316a1 1 0 0 1 .293-.71L11.605 1.292a1 1 0 0 1 1.414 0zm-1.416 1.415l-.707.707L12.31 4.83l.707-.707-1.414-1.415zM3.411 13.73l1.123-1.122H3.12v-1.415L2 12.312l.005 1.422 1.406-.005z"/></symbol><symbol viewBox="0 0 16 16" id="pencil-square" xmlns="http://www.w3.org/2000/svg"><path d="M12 9a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V9zm.778-7.179l1.414 1.415-6.476 6.476a1 1 0 0 1-.498.27l-1.51.325.323-1.512a1 1 0 0 1 .27-.497l6.477-6.477zM15.607.407a1 1 0 0 1 0 1.414l-.708.707-1.414-1.414.707-.707a1 1 0 0 1 1.415 0z"/></symbol><symbol viewBox="0 0 16 16" id="pipeline" xmlns="http://www.w3.org/2000/svg"><path d="M8.969 7.25a2 2 0 1 1-1.938 0A1.002 1.002 0 0 1 7 7V5.083a.2.2 0 0 1 .06-.142l.877-.87a.1.1 0 0 1 .141 0l.864.87A.2.2 0 0 1 9 5.083V7c0 .086-.01.17-.031.25zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm4.5-4a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zM8 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="play" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.765 15.835c-.545.321-1.258.159-1.593-.363A1.075 1.075 0 0 1 1 14.89V1.11C1 .496 1.518 0 2.158 0c.214 0 .424.057.607.165l11.684 6.89c.544.321.714 1.005.38 1.526a1.135 1.135 0 0 1-.38.364l-11.684 6.89z"/></symbol><symbol viewBox="0 0 16 16" id="plus" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7H2a1 1 0 1 0 0 2h5v5a1 1 0 0 0 2 0V9h5a1 1 0 0 0 0-2H9V2a1 1 0 1 0-2 0v5z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 7V4a1 1 0 1 0-2 0v3H4a1 1 0 1 0 0 2h3v3a1 1 0 0 0 2 0V9h3a1 1 0 0 0 0-2H9zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square-o" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="podcast" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862a1 1 0 0 1-.785 1.177A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-1-1 1 1 0 0 1 .02-.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 7.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4.464 2.464A1 1 0 0 1 5.88 3.88a3 3 0 0 0 0 4.242 1 1 0 0 1-1.415 1.415 5 5 0 0 1 0-7.072zm7.072 7.072A1 1 0 0 1 10.12 8.12a3 3 0 0 0 0-4.242 1 1 0 0 1 1.415-1.415 5 5 0 0 1 0 7.072zM2.343.343a1 1 0 1 1 1.414 1.414 6 6 0 0 0 0 8.486 1 1 0 1 1-1.414 1.414 8 8 0 0 1 0-11.314zm11.314 11.314a1 1 0 1 1-1.414-1.414 6 6 0 0 0 0-8.486A1 1 0 0 1 13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="preferences" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5 12h10a1 1 0 0 1 0 2H5a1 1 0 0 1-2 0v-2a1 1 0 0 1 2 0zm-3 0H1a1 1 0 0 0 0 2h1v-2zm11-5h2a1 1 0 0 1 0 2h-2a1 1 0 0 1-2 0V7a1 1 0 0 1 2 0zm-3 0H1a1 1 0 1 0 0 2h9V7zM6 2h9a1 1 0 0 1 0 2H6a1 1 0 1 1-2 0V2a1 1 0 1 1 2 0zM3 2H1a1 1 0 1 0 0 2h2V2z"/></symbol><symbol viewBox="0 0 16 16" id="profile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-4.274-3.404C4.412 9.709 5.694 9 8 9c2.313 0 3.595.7 4.28 1.586A4.997 4.997 0 0 1 8 13a4.997 4.997 0 0 1-4.274-2.404zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="project" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177l-.038.044a.505.505 0 0 0 .038-.044zm-.787 0a.5.5 0 0 0 .038.043l-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol><symbol viewBox="0 0 16 16" id="push-rules" xmlns="http://www.w3.org/2000/svg"><path d="M6.268 9a2 2 0 0 1 3.464 0H11a1 1 0 0 1 0 2H9.732a2 2 0 0 1-3.464 0H5a1 1 0 0 1 0-2h1.268zM7 2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1v3.515a.3.3 0 0 1-.434.268l-1.432-.716a.3.3 0 0 0-.268 0l-1.432.716A.3.3 0 0 1 7 5.515V2zM4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm4 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="question" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm-1.46-5.602h2.233a3.97 3.97 0 0 1 .051-.558c.029-.17.073-.326.133-.469.06-.143.14-.28.242-.41.102-.13.228-.263.38-.399.26-.24.504-.467.733-.683a5.03 5.03 0 0 0 .598-.668c.17-.23.302-.477.399-.742a2.66 2.66 0 0 0 .144-.907c0-.505-.083-.95-.25-1.335a2.55 2.55 0 0 0-.723-.97 3.2 3.2 0 0 0-1.152-.589 5.441 5.441 0 0 0-1.531-.2c-.516 0-.998.063-1.445.188a3.19 3.19 0 0 0-1.168.59c-.331.268-.594.61-.79 1.027-.195.417-.295.917-.3 1.5h2.64c.006-.224.04-.416.102-.578.062-.161.142-.293.238-.394a.921.921 0 0 1 .332-.227 1.04 1.04 0 0 1 .39-.074c.34 0 .593.095.763.285.169.19.254.488.254.895 0 .328-.106.63-.317.906-.21.276-.499.565-.863.867-.214.182-.39.374-.531.574-.141.2-.253.42-.336.657a3.656 3.656 0 0 0-.176.777 7.89 7.89 0 0 0-.05.937zm-.321 2.375c0 .188.035.362.105.524.07.161.17.3.301.418.13.117.284.21.46.277.178.068.376.102.595.102.218 0 .416-.034.593-.102.178-.068.331-.16.461-.277a1.2 1.2 0 0 0 .301-.418c.07-.162.106-.336.106-.524a1.3 1.3 0 0 0-.106-.523 1.2 1.2 0 0 0-.3-.418 1.461 1.461 0 0 0-.462-.277 1.651 1.651 0 0 0-.593-.102c-.22 0-.417.034-.594.102a1.46 1.46 0 0 0-.461.277 1.2 1.2 0 0 0-.3.418 1.284 1.284 0 0 0-.106.523z"/></symbol><symbol viewBox="0 0 16 16" id="question-o" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-.778-4.151c0-.301.014-.575.044-.82a3.2 3.2 0 0 1 .154-.68c.073-.208.17-.4.294-.575.123-.176.278-.343.465-.503a4.81 4.81 0 0 0 .755-.758c.185-.242.277-.506.277-.793 0-.356-.074-.617-.222-.783-.148-.166-.37-.25-.667-.25a.92.92 0 0 0-.342.065.806.806 0 0 0-.29.199 1.04 1.04 0 0 0-.209.345 1.5 1.5 0 0 0-.088.506H5.082c.005-.51.092-.948.263-1.313.171-.364.401-.664.69-.899.29-.234.63-.406 1.023-.516a4.66 4.66 0 0 1 1.264-.164c.497 0 .944.058 1.34.174.397.117.733.289 1.008.517.276.227.487.51.633.847.146.337.218.727.218 1.17 0 .295-.042.56-.126.792a2.52 2.52 0 0 1-.349.65 4.4 4.4 0 0 1-.523.584c-.2.19-.414.389-.642.598a2.73 2.73 0 0 0-.332.349c-.089.114-.16.233-.212.359a1.868 1.868 0 0 0-.116.41 3.39 3.39 0 0 0-.044.489H7.222zm-.28 2.078c0-.164.03-.317.092-.458a1.05 1.05 0 0 1 .263-.366c.114-.103.248-.183.403-.243a1.45 1.45 0 0 1 .52-.089c.191 0 .364.03.52.09.154.059.289.14.403.242.114.103.201.224.263.366.061.141.092.294.092.458 0 .164-.03.316-.092.458a1.05 1.05 0 0 1-.263.365 1.278 1.278 0 0 1-.404.243 1.43 1.43 0 0 1-.52.089c-.19 0-.364-.03-.519-.089-.155-.06-.29-.14-.403-.243a1.05 1.05 0 0 1-.263-.365 1.135 1.135 0 0 1-.093-.458z"/></symbol><symbol viewBox="0 0 16 16" id="quote" xmlns="http://www.w3.org/2000/svg"><path d="M15 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9h-2a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1zM7 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9H3a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="redo" xmlns="http://www.w3.org/2000/svg"><path d="M4.625 4.423A4.897 4.897 0 0 1 8.079 3c2.73 0 4.944 2.239 4.944 5s-2.214 5-4.944 5c-1.41 0-2.723-.6-3.655-1.633a.98.98 0 0 0-1.397-.066 1.008 1.008 0 0 0-.064 1.413A6.87 6.87 0 0 0 8.079 15C11.9 15 15 11.866 15 8s-3.099-7-6.921-7A6.866 6.866 0 0 0 3.08 3.158L1.833 2.137a.49.49 0 0 0-.695.074.504.504 0 0 0-.11.311L1 7.26a.497.497 0 0 0 .6.492l4.576-1.013a.5.5 0 0 0 .206-.877L4.625 4.423z"/></symbol><symbol viewBox="0 0 16 16" id="remove" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2v10a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V3zm3-2a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1H5zM4 3v10a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3H4zm2.5 2a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm3 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 16 16" id="repeat" xmlns="http://www.w3.org/2000/svg"><path d="M11.375 4.423A4.897 4.897 0 0 0 7.921 3c-2.73 0-4.944 2.239-4.944 5s2.214 5 4.944 5c1.41 0 2.723-.6 3.655-1.633a.98.98 0 0 1 1.397-.066c.403.373.432 1.005.064 1.413A6.87 6.87 0 0 1 7.921 15C4.1 15 1 11.866 1 8s3.099-7 6.921-7c1.915 0 3.706.792 4.999 2.158l1.247-1.021a.49.49 0 0 1 .695.074c.07.088.11.198.11.311L15 7.26a.497.497 0 0 1-.6.492L9.824 6.739a.5.5 0 0 1-.206-.877l1.757-1.439z"/></symbol><symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.114 6.958a4 4 0 0 0 5.283 4.775 1 1 0 1 1 .712 1.87A6 6 0 0 1 2.182 6.44l-.741-.2a.5.5 0 0 1-.12-.915l2.195-1.268a.5.5 0 0 1 .683.183l1.268 2.196a.5.5 0 0 1-.563.733l-.79-.212zm7.777 2.084a4 4 0 0 0-5.284-4.775 1 1 0 0 1-.712-1.87 6 6 0 0 1 7.927 7.162l.742.2a.5.5 0 0 1 .12.915l-2.196 1.268a.5.5 0 0 1-.683-.183l-1.267-2.196a.5.5 0 0 1 .562-.733l.79.212z"/></symbol><symbol viewBox="0 0 16 16" id="scale" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.99 9a.792.792 0 0 0-.078-.231L13 7l-.912 1.769a.791.791 0 0 0-.077.231h1.978zm-10 0a.792.792 0 0 0-.078-.231L3 7l-.912 1.769A.791.791 0 0 0 2.011 9h1.978zM2 0h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm3 14h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zM8 4a1 1 0 0 1 1 1v9H7V5a1 1 0 0 1 1-1zm-4.53-.714l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 3 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158L2.53 3.286a.53.53 0 0 1 .94 0zm10 0l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 13 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158l2.266-4.735a.53.53 0 0 1 .94 0z"/></symbol><symbol viewBox="0 0 16 16" id="screen-full" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14 14v-2a1 1 0 0 1 2 0v3a.997.997 0 0 1-1 1h-3a1 1 0 0 1 0-2h2zM2 14v-2a1 1 0 0 0-2 0v3a1 1 0 0 0 1 1h3a1 1 0 0 0 0-2H2zM15.707.293A.997.997 0 0 1 16 1v3a1 1 0 0 1-2 0V2h-2a1 1 0 0 1 0-2h3c.276 0 .526.112.707.293zM2 2v2a1 1 0 1 1-2 0V1a.997.997 0 0 1 1-1h3a1 1 0 1 1 0 2H2zm4 4h4a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="screen-normal" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 3V1a1 1 0 1 1 2 0v3a.997.997 0 0 1-1 1H1a1 1 0 1 1 0-2h2zm10 0h2a1 1 0 0 1 0 2h-3a.997.997 0 0 1-1-1V1a1 1 0 0 1 2 0v2zM3 13H1a1 1 0 0 1 0-2h3a.997.997 0 0 1 1 1v3a1 1 0 0 1-2 0v-2zm10 0v2a1 1 0 0 1-2 0v-3a.997.997 0 0 1 1-1h3a1 1 0 0 1 0 2h-2zM6.5 7h3a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 12 16" id="scroll_down" xmlns="http://www.w3.org/2000/svg"><path class="fbfirst-triangle" d="M1.048 14.155a.508.508 0 0 0-.32.105c-.091.07-.136.154-.136.25v.71c0 .095.045.178.135.249.09.07.197.105.321.105h10.043a.51.51 0 0 0 .321-.105c.09-.07.136-.154.136-.25v-.71c0-.095-.045-.178-.136-.249a.508.508 0 0 0-.32-.105"/><path class="fbsecond-triangle" d="M.687 8.027c-.09-.087-.122-.16-.093-.22.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 12.91a.458.458 0 0 1-.136.089h-.37a.626.626 0 0 1-.136-.09"/><path class="fbthird-triangle" d="M.687 1.027C.597.94.565.867.594.807c.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 5.91a.458.458 0 0 1-.136.09h-.37a.626.626 0 0 1-.136-.09"/></symbol><symbol viewBox="0 0 12 16" id="scroll_up" xmlns="http://www.w3.org/2000/svg"><path d="M1.048 1.845a.508.508 0 0 1-.32-.105c-.091-.07-.136-.154-.136-.25V.78c0-.095.045-.178.135-.249a.508.508 0 0 1 .321-.105h10.043a.51.51 0 0 1 .321.105c.09.07.136.154.136.25v.71c0 .095-.045.178-.136.249a.508.508 0 0 1-.32.105M.687 7.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 3.09A.458.458 0 0 0 6.257 3h-.37a.626.626 0 0 0-.136.09M.687 14.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 10.09a.458.458 0 0 0-.136-.09h-.37a.626.626 0 0 0-.136.09"/></symbol><symbol viewBox="0 0 16 16" id="search" xmlns="http://www.w3.org/2000/svg"><path d="M8.853 8.854a3.5 3.5 0 1 0-4.95-4.95 3.5 3.5 0 0 0 4.95 4.95zm.207 2.328a5.5 5.5 0 1 1 2.121-2.121l3.329 3.328a1.5 1.5 0 0 1-2.121 2.121L9.06 11.182z"/></symbol><symbol viewBox="0 0 16 16" id="settings" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.415 5.803L1.317 4.084A.5.5 0 0 1 1.35 3.5l.805-.994a.5.5 0 0 1 .564-.153l1.878.704a5.975 5.975 0 0 1 1.65-.797L6.885.342A.5.5 0 0 1 7.36 0h1.28a.5.5 0 0 1 .474.342l.639 1.918a5.97 5.97 0 0 1 1.65.797l1.877-.704a.5.5 0 0 1 .565.153l.805.994a.5.5 0 0 1 .032.584l-1.097 1.719c.217.551.354 1.143.399 1.76l1.731 1.058a.5.5 0 0 1 .227.54l-.288 1.246a.5.5 0 0 1-.44.385l-2.008.19a6.026 6.026 0 0 1-1.142 1.431l.265 1.995a.5.5 0 0 1-.277.516l-1.15.56a.5.5 0 0 1-.576-.1l-1.424-1.452a6.047 6.047 0 0 1-1.804 0l-1.425 1.453a.5.5 0 0 1-.576.1l-1.15-.561a.5.5 0 0 1-.276-.516l.265-1.995a6.026 6.026 0 0 1-1.143-1.43l-2.008-.191a.5.5 0 0 1-.44-.385L.058 9.16a.5.5 0 0 1 .226-.539l1.732-1.058a5.968 5.968 0 0 1 .399-1.76zM8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="shield" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8c1.657 0 3 1.373 3 3.067v7.346c0 1.065-.54 2.053-1.426 2.611l-4 2.52a2.944 2.944 0 0 1-3.148 0l-4-2.52A3.083 3.083 0 0 1 1 10.414V3.066C1 1.373 2.343 0 4 0zm0 2.045c-.552 0-1 .457-1 1.022v7.346c0 .355.18.685.475.87l4 2.52a.981.981 0 0 0 1.05 0l4-2.52c.295-.185.475-.515.475-.87V3.067c0-.565-.448-1.022-1-1.022H4zm0 1.533c0-.282.224-.511.5-.511h4V12.1a.52.52 0 0 1-.069.258.494.494 0 0 1-.684.183l-3.5-2.098a.513.513 0 0 1-.247-.44V3.577z"/></symbol><symbol viewBox="0 0 16 16" id="slight-frown" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-2.163-3.275a2.499 2.499 0 0 1 4.343.03.5.5 0 0 1-.871.49 1.5 1.5 0 0 0-2.607-.018.5.5 0 1 1-.865-.502zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="slight-smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-5.163 2.254a.5.5 0 1 1 .865-.502 1.499 1.499 0 0 0 2.607-.018.5.5 0 1 1 .871.49 2.499 2.499 0 0 1-4.343.03z"/></symbol><symbol viewBox="0 0 16 16" id="smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM6.18 6.27a.5.5 0 0 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zm6 0a.5.5 0 1 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zM5 9a3 3 0 0 0 6 0H5z"/></symbol><symbol viewBox="0 0 16 16" id="smiley" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM5 9h6a3 3 0 0 1-6 0z"/></symbol><symbol viewBox="0 0 16 16" id="snippet" xmlns="http://www.w3.org/2000/svg"><path d="M10.67 9.31a3.001 3.001 0 0 1 2.062 5.546 3 3 0 0 1-3.771-4.559 1.007 1.007 0 0 1-.095-.137l-4.5-7.794a1 1 0 0 1 1.732-1l4.5 7.794c.028.05.052.1.071.15zm-3.283.35l-.289.5c-.028.05-.06.095-.095.137a3.001 3.001 0 0 1-3.77 4.56A3 3 0 0 1 5.294 9.31c.02-.051.043-.102.071-.15l.866-1.5 1.155 2zm2.31-4l-1.156-2 1.325-2.294a1 1 0 0 1 1.732 1L9.696 5.66zm-5.465 7.464a1 1 0 1 0 1-1.732 1 1 0 0 0-1 1.732zm7.5 0a1 1 0 1 0-1-1.732 1 1 0 0 0 1 1.732z"/></symbol><symbol viewBox="0 0 16 16" id="soft-unwrap" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.5 11v-.598a.5.5 0 0 1 .765-.424l2.557 1.598a.5.5 0 0 1 0 .848l-2.557 1.598a.5.5 0 0 1-.765-.424V13H2a1 1 0 0 1 0-2h4.5zM2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm10 4h2a1 1 0 0 1 0 2h-2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="soft-wrap" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.5 13v.598a.5.5 0 0 1-.765.424l-2.557-1.598a.5.5 0 0 1 0-.848l2.557-1.598a.5.5 0 0 1 .765.424V11H12a1 1 0 0 0 0-2H2a1 1 0 1 1 0-2h10a3 3 0 0 1 0 6h-1.5zM2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 8h3a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="spam" xmlns="http://www.w3.org/2000/svg"><path d="M8.75.433l5.428 3.134a1.5 1.5 0 0 1 .75 1.299v6.268a1.5 1.5 0 0 1-.75 1.299L8.75 15.567a1.5 1.5 0 0 1-1.5 0l-5.428-3.134a1.5 1.5 0 0 1-.75-1.299V4.866a1.5 1.5 0 0 1 .75-1.299L7.25.433a1.5 1.5 0 0 1 1.5 0zM3.072 5.155v5.69L8 13.691l4.928-2.846v-5.69L8 2.309 3.072 5.155zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 14 14" id="spinner" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="7" cy="7" r="6" stroke="#000" stroke-opacity=".1" stroke-width="2"/><path fill="#000" fill-opacity=".1" fill-rule="nonzero" d="M7 0a7 7 0 0 1 7 7h-2a5 5 0 0 0-5-5V0z"/></g></symbol><symbol viewBox="0 0 16 16" id="staged" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3h4a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm9 6a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM2 7h4a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="star" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.609 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 16 16" id="star-o" xmlns="http://www.w3.org/2000/svg"><path d="M10.975 10.99a3 3 0 0 1 .655-2.083l1.54-1.916-2.219-.576a3 3 0 0 1-1.825-1.37L8 3.15 6.874 5.044a3 3 0 0 1-1.825 1.371l-2.218.576 1.54 1.916a3 3 0 0 1 .654 2.083l-.165 2.4 1.965-.836a3 3 0 0 1 2.348 0l1.965.836-.164-2.399zM7.61 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 14 14" id="status_canceled" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M5.2 3.8l4.9 4.9c.2.2.2.5 0 .7l-.7.7c-.2.2-.5.2-.7 0L3.8 5.2c-.2-.2-.2-.5 0-.7l.7-.7c.2-.2.5-.2.7 0"/></g></symbol><symbol viewBox="0 0 22 22" id="status_canceled_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M8.171 5.971l7.7 7.7a.76.76 0 0 1 0 1.1l-1.1 1.1a.76.76 0 0 1-1.1 0l-7.7-7.7a.76.76 0 0 1 0-1.1l1.1-1.1a.76.76 0 0 1 1.1 0"/></symbol><symbol viewBox="0 0 16 16" id="status_closed" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.83a1 1 0 0 1 1.414 1.416l-3.535 3.535a1 1 0 0 1-1.415.001l-2.12-2.12a1 1 0 1 1 1.413-1.415zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 14 14" id="status_created" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><circle cx="7" cy="7" r="3.25"/></g></symbol><symbol viewBox="0 0 22 22" id="status_created_borderless" xmlns="http://www.w3.org/2000/svg"><circle cx="11" cy="11" r="5.107"/></symbol><symbol viewBox="0 0 14 14" id="status_failed" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 5.969L5.599 4.568a.29.29 0 0 0-.413.004l-.614.614a.294.294 0 0 0-.004.413L5.968 7l-1.4 1.401a.29.29 0 0 0 .004.413l.614.614c.113.114.3.117.413.004L7 8.032l1.401 1.4a.29.29 0 0 0 .413-.004l.614-.614a.294.294 0 0 0 .004-.413L8.032 7l1.4-1.401a.29.29 0 0 0-.004-.413l-.614-.614a.294.294 0 0 0-.413-.004L7 5.968z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_failed_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 9.38L8.798 7.178a.455.455 0 0 0-.65.006l-.964.965a.462.462 0 0 0-.006.65L9.38 11l-2.202 2.202a.455.455 0 0 0 .006.65l.965.964a.462.462 0 0 0 .65.006L11 12.62l2.202 2.202a.455.455 0 0 0 .65-.006l.964-.965a.462.462 0 0 0 .006-.65L12.62 11l2.202-2.202a.455.455 0 0 0-.006-.65l-.965-.964a.462.462 0 0 0-.65-.006L11 9.38z"/></symbol><symbol viewBox="0 0 14 14" id="status_manual" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M10.5 7.63V6.37l-.787-.13c-.044-.175-.132-.349-.263-.61l.481-.652-.918-.913-.657.478a2.346 2.346 0 0 0-.612-.26L7.656 3.5H6.388l-.132.783c-.219.043-.394.13-.612.26l-.657-.478-.918.913.437.652c-.131.218-.175.392-.262.61l-.744.086v1.261l.787.13c.044.218.132.392.263.61l-.438.651.92.913.655-.434c.175.086.394.173.613.26l.131.783h1.313l.131-.783c.219-.043.394-.13.613-.26l.656.478.918-.913-.48-.652c.13-.218.218-.435.262-.61l.656-.13zM7 8.283a1.285 1.285 0 0 1-1.313-1.305c0-.739.57-1.304 1.313-1.304.744 0 1.313.565 1.313 1.304 0 .74-.57 1.305-1.313 1.305z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_manual_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M16.5 11.99v-1.98l-1.238-.206c-.068-.273-.206-.546-.412-.956l.756-1.025-1.444-1.435-1.03.752a3.686 3.686 0 0 0-.963-.41L12.03 5.5h-1.994l-.206 1.23c-.343.068-.618.205-.962.41l-1.031-.752-1.444 1.435.687 1.025c-.206.341-.275.615-.412.956L5.5 9.941v1.981l1.237.205c.07.342.207.615.413.957l-.688 1.025 1.444 1.434 1.032-.683c.274.137.618.274.962.41l.206 1.23h2.063l.206-1.23c.344-.068.619-.205.963-.41l1.03.752 1.444-1.435-.756-1.025c.207-.341.344-.683.413-.956l1.031-.205zM11 13.017c-1.169 0-2.063-.889-2.063-2.05 0-1.162.894-2.05 2.063-2.05s2.063.888 2.063 2.05c0 1.161-.894 2.05-2.063 2.05z"/></symbol><symbol viewBox="0 0 14 14" id="status_notfound" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M8.16 7.184c.519-.37.904-.857 1.07-1.477.384-1.427-.619-2.897-2.246-2.897-.732 0-1.327.26-1.766.692a2.163 2.163 0 0 0-.509.743.75.75 0 0 0 1.4.54.78.78 0 0 1 .16-.213c.168-.165.39-.262.715-.262.597 0 .936.496.798 1.007-.067.249-.235.462-.492.644-.231.165-.47.264-.601.3a.75.75 0 0 0-.556.724v1.421a.75.75 0 0 0 1.5 0v-.909a3.74 3.74 0 0 0 .526-.313z"/><ellipse cx="6.889" cy="10.634" rx="1" ry="1"/></symbol><symbol viewBox="0 0 22 22" id="status_notfound_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M12.822 11.29c.816-.581 1.421-1.348 1.683-2.322.603-2.243-.973-4.553-3.53-4.553-1.15 0-2.085.41-2.775 1.089-.42.413-.672.835-.8 1.167a1.179 1.179 0 0 0 2.2.847c.016-.043.1-.184.252-.334.264-.259.613-.412 1.123-.412.938 0 1.47.78 1.254 1.584-.105.39-.37.726-.773 1.012a3.25 3.25 0 0 1-.945.47 1.179 1.179 0 0 0-.874 1.138v2.234a1.179 1.179 0 1 0 2.358 0v-1.43a5.9 5.9 0 0 0 .827-.492z"/><ellipse cx="10.825" cy="16.711" rx="1.275" ry="1.322"/></symbol><symbol viewBox="0 0 14 14" id="status_open" xmlns="http://www.w3.org/2000/svg"><path d="M0 7c0-3.866 3.142-7 7-7 3.866 0 7 3.142 7 7 0 3.866-3.142 7-7 7-3.866 0-7-3.142-7-7z"/><path d="M1 7c0 3.309 2.69 6 6 6 3.309 0 6-2.69 6-6 0-3.309-2.69-6-6-6-3.309 0-6 2.69-6 6z" fill="#FFF"/><path d="M7 9.219a2.218 2.218 0 1 0 0-4.436A2.218 2.218 0 0 0 7 9.22zm0 1.12a3.338 3.338 0 1 1 0-6.676 3.338 3.338 0 0 1 0 6.676z"/></symbol><symbol viewBox="0 0 14 14" id="status_pending" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M4.7 5.3c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H5c-.2 0-.3-.1-.3-.3V5.3m3 0c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H8c-.2 0-.3-.1-.3-.3V5.3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_pending_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M7.386 8.329c0-.315.157-.472.471-.472h1.414c.315 0 .472.157.472.472v5.342c0 .315-.157.472-.472.472H7.857c-.314 0-.471-.157-.471-.472V8.33m4.714 0c0-.315.157-.472.471-.472h1.415c.314 0 .471.157.471.472v5.342c0 .315-.157.472-.471.472H12.57c-.314 0-.471-.157-.471-.472V8.33"/></symbol><symbol viewBox="0 0 14 14" id="status_running" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 3c2.2 0 4 1.8 4 4s-1.8 4-4 4c-1.3 0-2.5-.7-3.3-1.7L7 7V3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_running_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 4.714c3.457 0 6.286 2.829 6.286 6.286 0 3.457-2.829 6.286-6.286 6.286-2.043 0-3.929-1.1-5.186-2.672L11 11V4.714"/></symbol><symbol viewBox="0 0 14 14" id="status_skipped" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M6.415 7.04L4.579 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L5.341 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L6.415 7.04zm2.54 0L7.119 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L7.881 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L8.955 7.04z"/></symbol><symbol viewBox="0 0 22 22" id="status_skipped_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M14.072 11.063l-2.82 2.82a.46.46 0 0 0-.001.652l.495.495a.457.457 0 0 0 .653-.001l3.7-3.7a.46.46 0 0 0 .001-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.479-3.479a.464.464 0 0 0-.654.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/><path d="M10.08 11.063l-2.819 2.82a.46.46 0 0 0-.002.652l.496.495a.457.457 0 0 0 .652-.001l3.7-3.7a.46.46 0 0 0 .002-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.48-3.479a.464.464 0 0 0-.653.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/></symbol><symbol viewBox="0 0 14 14" id="status_success" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6.278 7.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_success_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.866 12.095l-1.95-1.95a.462.462 0 0 0-.647.01l-.964.964a.46.46 0 0 0-.01.646l3.013 3.014a.787.787 0 0 0 1.106.008l.425-.425 4.854-4.853a.462.462 0 0 0 .002-.659l-.964-.964a.468.468 0 0 0-.658.002l-4.207 4.207z"/></symbol><symbol viewBox="0 0 14 14" id="status_success_solid" xmlns="http://www.w3.org/2000/svg"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7zm6.278.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 14 14" id="status_warning" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6 3.5c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v4c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-4m0 6c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v1c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-1"/></g></symbol><symbol viewBox="0 0 22 22" id="status_warning_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.429 5.5c0-.471.314-.786.785-.786h1.572c.471 0 .785.315.785.786v6.286c0 .471-.314.785-.785.785h-1.572c-.471 0-.785-.314-.785-.785V5.5m0 9.429c0-.472.314-.786.785-.786h1.572c.471 0 .785.314.785.786V16.5c0 .471-.314.786-.785.786h-1.572c-.471 0-.785-.315-.785-.786v-1.571"/></symbol><symbol viewBox="0 0 16 16" id="stop" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 0h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="task-done" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="template" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm.8 2h2.4a.8.8 0 0 1 .8.8v1.4a.8.8 0 0 1-.8.8H3.8a.8.8 0 0 1-.8-.8V4.8a.8.8 0 0 1 .8-.8zm4.7 0h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm0 2h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm-5 3h9a.5.5 0 1 1 0 1h-9a.5.5 0 0 1 0-1zm0 2h9a.5.5 0 1 1 0 1h-9a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="terminal" xmlns="http://www.w3.org/2000/svg"><path d="M7 8a.997.997 0 0 1-.293.707l-1.414 1.414a1 1 0 1 1-1.414-1.414L4.586 8l-.707-.707a1 1 0 1 1 1.414-1.414l1.414 1.414A.997.997 0 0 1 7 8zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H4zm5 7h2a1 1 0 0 1 0 2H9a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 11h5.282a2 2 0 0 0 1.963-2.38l-.563-2.905a3 3 0 0 0-.243-.732l-1.103-2.286A3 3 0 0 0 10.964 1H7a3 3 0 0 0-3 3v6.3a2 2 0 0 0 .436 1.247l3.11 3.9a.632.632 0 0 0 .941.053l.137-.137a1 1 0 0 0 .28-.87L8.329 11zM1 10h2V3H1a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 5h5.282a2 2 0 0 1 1.963 2.38l-.563 2.905a3 3 0 0 1-.243.732l-1.103 2.286A3 3 0 0 1 10.964 15H7a3 3 0 0 1-3-3V5.7a2 2 0 0 1 .436-1.247l3.11-3.9A.632.632 0 0 1 8.487.5l.137.137a1 1 0 0 1 .28.87L8.329 5zM1 6h2v7H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="thumbtack" xmlns="http://www.w3.org/2000/svg"><path d="M7.125 9h-2.19a.5.5 0 0 1-.417-.777L6 6V2L5.362.724A.5.5 0 0 1 5.809 0h4.382a.5.5 0 0 1 .447.724L10 2v4l1.482 2.223a.5.5 0 0 1-.416.777H8.875L8 16l-.875-7z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 16 16" id="timer" xmlns="http://www.w3.org/2000/svg"><path d="M12.022 3.27l.77-.77a1 1 0 0 1 1.415 1.414l-.728.729a7 7 0 1 1-1.456-1.372zM8 14A5 5 0 1 0 8 4a5 5 0 0 0 0 10zm0-9a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zM6 0h4a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-add" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 4V2a1 1 0 0 1 2 0v2h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0V6H8a1 1 0 1 1 0-2h2zm2 7a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-done" xmlns="http://www.w3.org/2000/svg"><path d="M8.243 7.485l4.95-4.95a1 1 0 1 1 1.414 1.415L8.95 9.607a.997.997 0 0 1-1.414 0L4.707 6.778a1 1 0 0 1 1.414-1.414l2.122 2.121zM12 11a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="token" xmlns="http://www.w3.org/2000/svg"><path d="M3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H3zm1 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="unapproval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11.95 8.536l1.06-1.061a1 1 0 0 1 1.415 1.414l-1.061 1.06 1.06 1.061a1 1 0 0 1-1.414 1.415l-1.06-1.061-1.06 1.06a1 1 0 1 1-1.415-1.414l1.06-1.06-1.06-1.06a1 1 0 0 1 1.414-1.415l1.06 1.06zm-3.768-.33c.006.503.201 1.006.586 1.39l.353.354-.353.353a2 2 0 1 0 2.828 2.829l.354-.354.047.048C11.964 14.363 11.527 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.834 0 1.557.074 2.182.205zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="unassignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11 5h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="unlink" xmlns="http://www.w3.org/2000/svg"><path d="M11.295 8.845l-.659-1.664a1.78 1.78 0 0 0 .04-.04l1.415-1.414c.586-.586.654-1.468.152-1.97s-1.384-.434-1.97.152L8.859 5.323a1.781 1.781 0 0 0-.04.04l-1.664-.658c.141-.208.305-.408.491-.594l1.415-1.414c1.366-1.367 3.424-1.525 4.596-.354 1.171 1.172 1.013 3.23-.354 4.596L11.89 8.354c-.186.186-.386.35-.594.491zm-2.45 2.45a4.075 4.075 0 0 1-.491.594l-1.415 1.414c-1.366 1.367-3.424 1.525-4.596.354-1.171-1.172-1.013-3.23.354-4.596L4.11 7.646c.186-.186.386-.35.594-.491l.659 1.664a1.781 1.781 0 0 0-.04.04l-1.415 1.414c-.586.586-.654 1.468-.152 1.97s1.384.434 1.97-.152l1.414-1.414a1.78 1.78 0 0 0 .04-.04l1.664.658zm3.812-2.088h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-.05a.5.5 0 0 1 .5-.5zm-.384 2.116l1.415 1.414a.5.5 0 0 1 0 .708l-.037.036a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 0-.707l.036-.037a.5.5 0 0 1 .707 0zm-2.823 1.09a.5.5 0 0 1 .5-.5h.052a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9.95a.5.5 0 0 1-.5-.5v-2zm-2.748-9.16a.5.5 0 0 1-.5.5h-.05a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h.05a.5.5 0 0 1 .5.5v2zm-2.116.383a.5.5 0 0 1 0 .707l-.036.036a.5.5 0 0 1-.707 0L2.428 2.965a.5.5 0 0 1 0-.707l.037-.036a.5.5 0 0 1 .707 0l1.414 1.414zm-1.09 2.823h-2a.5.5 0 0 1-.5-.5v-.051a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5z"/></symbol><symbol viewBox="0 0 16 16" id="unstaged" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="user" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 8c-6.888 0-6.976-.78-6.976-2.52S2.144 8 8 8s6.976 2.692 6.976 4.48c0 1.788-.088 2.52-6.976 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="users" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.521 8.01C15.103 8.19 16 10.755 16 12.48c0 1.533-.056 2.29-3.808 2.475.609-.54.808-1.331.808-2.475 0-1.911-.804-3.503-2.479-4.47zm-1.67-1.228A3.987 3.987 0 0 0 9.976 4a3.987 3.987 0 0 0-1.125-2.782 3 3 0 1 1 0 5.563zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="volume-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 5h1v6H1a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1zm2 0l4.445-2.964A1 1 0 0 1 9 2.87v10.26a1 1 0 0 1-1.555.833L3 11V5zm10.283 7.89a.5.5 0 0 1-.66-.752A5.485 5.485 0 0 0 14.5 8c0-1.601-.687-3.09-1.865-4.128a.5.5 0 0 1 .661-.75A6.484 6.484 0 0 1 15.5 8a6.485 6.485 0 0 1-2.217 4.89zm-2.002-2.236a.5.5 0 1 1-.652-.758c.55-.472.871-1.157.871-1.896 0-.732-.315-1.411-.856-1.883a.5.5 0 0 1 .658-.753A3.492 3.492 0 0 1 12.5 8c0 1.033-.45 1.994-1.219 2.654z"/></symbol><symbol viewBox="0 0 16 16" id="warning" xmlns="http://www.w3.org/2000/svg"><path d="M15.572 10.506c.867 1.42.375 3.247-1.098 4.082a3.184 3.184 0 0 1-1.57.412h-9.81C1.387 15 0 13.665 0 12.018a2.9 2.9 0 0 1 .427-1.512L5.332 2.47C6.2 1.05 8.096.577 9.57 1.412c.453.257.831.622 1.098 1.059l4.905 8.035zM8.89 3.479a1.014 1.014 0 0 0-.366-.353 1.053 1.053 0 0 0-1.412.353l-4.905 8.035a.967.967 0 0 0-.143.504c0 .549.462.994 1.032.994h9.81c.184 0 .364-.048.523-.137a.974.974 0 0 0 .366-1.361L8.889 3.479zM8 5a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zm0 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="work" xmlns="http://www.w3.org/2000/svg"><path d="M12 3h1a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h1V2a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1zM6 2v1h4V2H6zM3 5a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H3zm1.5 1a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm7 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol></svg> \ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol viewBox="0 0 16 16" id="abuse" xmlns="http://www.w3.org/2000/svg"><path d="M11.408.328l4.029 3.222A1.5 1.5 0 0 1 16 4.72v6.555a1.5 1.5 0 0 1-.563 1.171l-4.026 3.224a1.5 1.5 0 0 1-.937.329H5.529a1.5 1.5 0 0 1-.937-.328L.563 12.45A1.5 1.5 0 0 1 0 11.28V4.724a1.5 1.5 0 0 1 .563-1.171L4.589.329A1.5 1.5 0 0 1 5.526 0h4.945c.34 0 .67.116.937.328zM10.296 2H5.702L2 4.964v6.074L5.704 14h4.594L14 11.036V4.962L10.296 2zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="account" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.195 9.965l-.568-.875a.25.25 0 0 1 .015-.294l.405-.5a.25.25 0 0 1 .283-.075l.938.36c.257-.183.543-.325.851-.42l.322-.988A.25.25 0 0 1 11.679 7h.642a.25.25 0 0 1 .238.173l.322.988c.308.095.594.237.851.42l.938-.36a.25.25 0 0 1 .283.076l.405.5a.25.25 0 0 1 .015.293l-.568.875c.113.297.18.616.193.95l.898.54a.25.25 0 0 1 .115.27l-.144.626a.25.25 0 0 1-.222.193l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.281a.25.25 0 0 1-.29-.05l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.904a.25.25 0 0 1-.289.051l-.577-.281a.25.25 0 0 1-.138-.26l.165-1.18a3.015 3.015 0 0 1-.512-.607l-1.115-.098a.25.25 0 0 1-.222-.193l-.144-.626a.25.25 0 0 1 .115-.27l.898-.54c.013-.334.08-.653.193-.95zM6.789 8.023A12.845 12.845 0 0 0 6 8c-5.036 0-6 2.74-6 4.48C0 14.22.076 15 6 15c.553 0 1.055-.006 1.51-.02A5.977 5.977 0 0 1 6 11c0-1.083.287-2.1.79-2.977zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM12 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="admin" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.162 2.5a3.5 3.5 0 0 1-3.163 5.479L6.08 14.766a1.5 1.5 0 0 1-2.598-1.5L7.4 6.479A3.5 3.5 0 0 1 10.564 1L8.9 3.88l2.599 1.5 1.663-2.88zm-8.63 11.949a.5.5 0 1 0 .5-.866.5.5 0 0 0-.5.866z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.414 7.95l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 1 0 1.414-1.415L10.414 7.95zm-7 0l4.243-4.243a1 1 0 0 0-1.414-1.414l-4.95 4.95a.997.997 0 0 0 0 1.414l4.95 4.95a1 1 0 0 0 1.414-1.415L3.414 7.95z"/></symbol><symbol viewBox="0 0 16 16" id="angle-double-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.536 7.95L1.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 1 1-1.414-1.415L5.536 7.95zm7 0L8.293 3.707a1 1 0 0 1 1.414-1.414l4.95 4.95a.997.997 0 0 1 0 1.414l-4.95 4.95a1 1 0 0 1-1.414-1.415l4.243-4.242z"/></symbol><symbol viewBox="0 0 16 16" id="angle-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 10.243l-4.95-4.95a1 1 0 0 0-1.414 1.414l5.657 5.657a.997.997 0 0 0 1.414 0l5.657-5.657a1 1 0 0 0-1.414-1.414L8 10.243z"/></symbol><symbol viewBox="0 0 16 16" id="angle-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.757 8l4.95-4.95a1 1 0 1 0-1.414-1.414L3.636 7.293a.997.997 0 0 0 0 1.414l5.657 5.657a1 1 0 0 0 1.414-1.414L5.757 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.243 8l-4.95-4.95a1 1 0 0 1 1.414-1.414l5.657 5.657a.997.997 0 0 1 0 1.414l-5.657 5.657a1 1 0 0 1-1.414-1.414L10.243 8z"/></symbol><symbol viewBox="0 0 16 16" id="angle-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 6.757l-4.95 4.95a1 1 0 1 1-1.414-1.414l5.657-5.657a.997.997 0 0 1 1.414 0l5.657 5.657a1 1 0 0 1-1.414 1.414L8 6.757z"/></symbol><symbol viewBox="0 0 16 16" id="appearance" xmlns="http://www.w3.org/2000/svg"><path d="M11.161 12.456l.232.121c.1.053.175.094.249.137.53.318.844.75.857 1.402.012 1.397-1.116 1.756-3.12 1.858a23.85 23.85 0 0 1-1.38.026A8 8 0 0 1 0 8a8 8 0 0 1 8-8c4.417 0 7.998 3.582 7.998 7.977.06 2.621-1.312 3.586-4.48 3.648-.602.008-1.068.043-1.4.104.228.192.598.47 1.043.727zm-3.287-.943c-.019-1.495 1.228-1.856 3.611-1.888C13.67 9.582 14.028 9.33 13.998 8A6 6 0 1 0 8 14c.603 0 .91-.004 1.277-.023a9.7 9.7 0 0 0 .478-.035c-1.172-.738-1.868-1.47-1.88-2.43zM6 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-2-3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM4 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="applications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 1v2h2V1H7zm0 5h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm6-6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm0 6h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm0 1v2h2V7h-2zM1 12h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm0 1v2h2v-2H1zm6-1h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm6 0h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="approval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.536 10.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 1 1 9.12 9.243l1.415 1.414zM7.632 8.109A2 2 0 0 0 7 11.364l2.121 2.121a1.996 1.996 0 0 0 2.807.021C11.686 14.554 10.627 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.6 0 1.142.038 1.632.109zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-down" xmlns="http://www.w3.org/2000/svg"><path d="M10.472 7.282a.862.862 0 0 1 1.26-.006c.357.364.357.958 0 1.285L8.627 11.73A.886.886 0 0 1 8 12a.849.849 0 0 1-.627-.27L4.275 8.561a.904.904 0 0 1-.013-1.285.861.861 0 0 1 1.26-.007l2.486 2.527z"/></symbol><symbol viewBox="0 0 16 16" id="arrow-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 6H2a2 2 0 1 0 0 4h7v2.586a1 1 0 0 0 1.707.707l4.586-4.586a1 1 0 0 0 0-1.414l-4.586-4.586A1 1 0 0 0 9 3.414V6z"/></symbol><symbol viewBox="0 0 16 16" id="assignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 5V4a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V7h-1a1 1 0 0 1 0-2h1zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="blame" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 4h3a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm9 3h3a1 1 0 0 1 0 2h-3a1 1 0 0 1 0-2zm-9 3h3a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2zm9 0h3a1 1 0 0 1 0 2h-3a1 1 0 0 1 0-2zm0-6h3a1 1 0 0 1 0 2h-3a1 1 0 0 1 0-2zM2 7h3a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm6-6a1 1 0 0 1 1 1v12a1 1 0 0 1-2 0V2a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="bold" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4 12.5v-9A1.5 1.5 0 0 1 5.5 2h2.104c2.182 0 3.879.681 3.879 2.982 0 1.067-.517 2.227-1.374 2.595v.073C11.176 7.963 12 8.865 12 10.466 12 12.914 10.19 14 7.911 14H5.5A1.5 1.5 0 0 1 4 12.5zm2.376-5.696H7.49c1.164 0 1.665-.552 1.665-1.417 0-.94-.534-1.289-1.649-1.289h-1.13v2.706zm0 5.098h1.341c1.293 0 1.956-.515 1.956-1.62 0-1.049-.647-1.472-1.956-1.472H6.376v3.092z"/></symbol><symbol viewBox="0 0 16 16" id="book" xmlns="http://www.w3.org/2000/svg"><path d="M7 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2v4.191a.5.5 0 0 1-.724.447l-1.052-.526a.5.5 0 0 0-.448 0l-1.052.526A.5.5 0 0 1 7 6.191V2zM5 0h6a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="bookmark" xmlns="http://www.w3.org/2000/svg"><path d="M6.746 10.505a2 2 0 0 1 2.508 0L11 11.911V3H5v8.91l1.746-1.405zM5 1h6a2 2 0 0 1 2 2v10.999a1 1 0 0 1-1.627.779L8 12.064l-3.373 2.714A1 1 0 0 1 3 13.998V3a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="branch" xmlns="http://www.w3.org/2000/svg"><path d="M6 11.978v.29a2 2 0 1 1-2 0V3.732a2 2 0 1 1 2 0v3.849c.592-.491 1.31-.854 2.15-1.081 1.308-.353 1.875-.882 1.893-1.743a2 2 0 1 1 2.002-.051C12.053 6.54 10.857 7.84 8.67 8.43 7.056 8.867 6.195 9.98 6 11.978zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm6 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="bullhorn" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.143 10H7V4H3a3 3 0 1 0 0 6h.143l.734 5.141a1 1 0 0 0 .99.859h1.556a.5.5 0 0 0 .495-.57L6.143 10zM8 4c1.034.02 2.039-.274 3.014-.883.727-.455 1.836-1.334 3.328-2.637A1 1 0 0 1 16 1.233v10.764a1 1 0 0 1-1.595.803c-1.658-1.227-2.788-1.992-3.392-2.294-.781-.39-1.785-.559-3.013-.506V4z"/></symbol><symbol viewBox="0 0 16 16" id="calendar" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12 2h2a2 2 0 0 1 2 2H0a2 2 0 0 1 2-2h2V1a1 1 0 1 1 2 0v1h4V1a1 1 0 1 1 2 0v1zM0 4h16v9a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4zm2 2.5V13a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6.5a.5.5 0 0 0-.5-.5h-11a.5.5 0 0 0-.5.5zM5 8h2a1 1 0 1 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="cancel" xmlns="http://www.w3.org/2000/svg"><path d="M3.11 4.523a6 6 0 0 0 8.367 8.367L3.109 4.524zM4.522 3.11l8.368 8.368A6 6 0 0 0 4.524 3.11zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 16 16" id="chart" xmlns="http://www.w3.org/2000/svg"><path d="M15 14a1 1 0 0 1 0 2H2a2 2 0 0 1-2-2V1a1 1 0 1 1 2 0v13h13zM3.142 8.735l2.502-2.561a.5.5 0 0 1 .714-.003L8 7.833l3.592-4.553a.5.5 0 0 1 .796.015l2.516 3.454a.5.5 0 0 1 .096.295V12.5a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5V9.085a.5.5 0 0 1 .142-.35z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.078 8.2l3.535-3.536a2 2 0 0 1 2.828 2.828l-4.949 4.95c-.39.39-.902.586-1.414.586a1.994 1.994 0 0 1-1.414-.586l-4.95-4.95a2 2 0 1 1 2.828-2.828l3.536 3.535z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-left" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.977 7.998l3.535-3.535a2 2 0 1 0-2.828-2.828l-4.95 4.949c-.39.39-.586.902-.586 1.414 0 .512.196 1.024.586 1.414l4.95 4.95a2 2 0 1 0 2.828-2.828L7.977 7.998z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-right" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.22 7.998L4.683 4.463a2 2 0 0 1 2.828-2.828l4.95 4.949c.39.39.586.902.586 1.414a1.99 1.99 0 0 1-.586 1.414l-4.95 4.95a2 2 0 0 1-2.828-2.828l3.535-3.536z"/></symbol><symbol viewBox="0 0 16 16" id="chevron-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.778 8.957l3.535 3.535a2 2 0 1 0 2.828-2.828l-4.949-4.95a1.994 1.994 0 0 0-1.414-.586c-.512 0-1.024.196-1.414.586l-4.95 4.95a2 2 0 1 0 2.828 2.828l3.536-3.535z"/></symbol><symbol viewBox="0 0 16 16" id="clock" xmlns="http://www.w3.org/2000/svg"><path d="M9 7h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V5a1 1 0 1 1 2 0v2zm-1 9A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9.414 8l4.95-4.95a1 1 0 0 0-1.414-1.414L8 6.586l-4.95-4.95A1 1 0 0 0 1.636 3.05L6.586 8l-4.95 4.95a1 1 0 1 0 1.414 1.414L8 9.414l4.95 4.95a1 1 0 1 0 1.414-1.414L9.414 8z"/></symbol><symbol viewBox="0 0 16 16" id="code" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M15.871 8.243a.997.997 0 0 0-.293-.707L12.75 4.707a1 1 0 0 0-1.414 1.414l2.12 2.122-2.12 2.121a1 1 0 0 0 1.414 1.414l2.828-2.828a.997.997 0 0 0 .293-.707zm-13.243 0L4.75 6.12a1 1 0 1 0-1.414-1.414L.507 7.536a.997.997 0 0 0 0 1.414l2.829 2.828a1 1 0 1 0 1.414-1.414L2.628 8.243zm6.407-4.107a1 1 0 0 1 .707 1.225L8.19 11.157a1 1 0 1 1-1.931-.518L7.81 4.843a1 1 0 0 1 1.224-.707z"/></symbol><symbol viewBox="0 0 9 13" id="collapse"><path d="M.084.25C.01.18-.015.12.008.071.031.024.093 0 .194 0h8.521c.1 0 .162.024.185.072.023.048-.002.107-.075.177l-4.11 3.935a.372.372 0 0 1-.11.072h-.301a.508.508 0 0 1-.11-.072L.084.249zM.377 6.88a.364.364 0 0 1-.26-.105.334.334 0 0 1-.11-.25v-.709c0-.096.036-.179.11-.249a.364.364 0 0 1 .26-.105h8.15c.101 0 .188.035.261.105.074.07.11.153.11.25v.709c0 .096-.036.179-.11.249a.364.364 0 0 1-.26.105H.377zM.084 12.132c-.074.07-.099.129-.076.177.023.048.085.072.186.072h8.521c.1 0 .162-.024.185-.072.023-.048-.002-.107-.075-.177l-4.11-3.935a.372.372 0 0 0-.11-.072h-.301a.508.508 0 0 0-.11.072l-4.11 3.935z"/></symbol><symbol viewBox="0 0 16 16" id="comment" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comment-dots" xmlns="http://www.w3.org/2000/svg"><path d="M1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586zM5 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="comment-next" xmlns="http://www.w3.org/2000/svg"><path d="M8 5V4a.5.5 0 0 1 .8-.4l2.667 2a.5.5 0 0 1 0 .8L8.8 8.4A.5.5 0 0 1 8 8V7H6a1 1 0 1 1 0-2h2zM1.707 15.707C1.077 16.337 0 15.891 0 15V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5.414l-3.707 3.707zM2 12.586l2.293-2.293A1 1 0 0 1 5 10h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v9.586z"/></symbol><symbol viewBox="0 0 16 16" id="comments" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.75 10L0 13V3a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H3.75zM13 5h1a2 2 0 0 1 2 2v8l-2.667-2H8a2 2 0 0 1-2-2h4a3 3 0 0 0 3-3V5z"/></symbol><symbol viewBox="0 0 16 16" id="commit" xmlns="http://www.w3.org/2000/svg"><path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3.876-1.008a4.002 4.002 0 0 1-7.752 0A1.01 1.01 0 0 1 4 9H1a1 1 0 1 1 0-2h3c.042 0 .083.003.124.008a4.002 4.002 0 0 1 7.752 0A1.01 1.01 0 0 1 12 7h3a1 1 0 0 1 0 2h-3a1.01 1.01 0 0 1-.124-.008z"/></symbol><symbol viewBox="0 0 16 16" id="compress" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.587 12.707l-1.414 1.415a1 1 0 0 1-1.414-1.415l1.414-1.414-1.386-1.386a.5.5 0 0 1 .299-.85l4.708-.523a.5.5 0 0 1 .553.552l-.524 4.709a.5.5 0 0 1-.85.298l-1.386-1.386zm6.859-9.687l1.414-1.414a1 1 0 0 1 1.414 1.414L12.86 4.434l1.386 1.386a.5.5 0 0 1-.299.85l-4.708.524a.5.5 0 0 1-.553-.552l.524-4.71a.5.5 0 0 1 .85-.297l1.386 1.385z"/></symbol><symbol viewBox="0 0 16 16" id="credit-card" xmlns="http://www.w3.org/2000/svg"><path d="M14 5a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1h12zm0 3H2v3a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V8zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm6.5 8h3a.5.5 0 1 1 0 1h-3a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="cut" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="2" y="7" fill-rule="evenodd" rx="1"/></symbol><symbol viewBox="0 0 16 16" id="dashboard" xmlns="http://www.w3.org/2000/svg"><path d="M7.709 10.021l.696-2.6a.5.5 0 0 1 .966.26l-.657 2.45A2 2 0 0 1 10 12H6a2 2 0 0 1 1.709-1.979zM0 8.9a8 8 0 0 1 15.998 0H16v3.6a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5V8.9zM14 9A6 6 0 1 0 2 9v3.5a.5.5 0 0 0 .5.5h11a.5.5 0 0 0 .5-.5V9zM3.5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm9 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-7-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm5 0a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1z"/></symbol><symbol viewBox="0 0 16 16" id="disk" xmlns="http://www.w3.org/2000/svg"><path d="M16 11.764V3a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3v8.764A2.989 2.989 0 0 1 2 11V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v8c.768 0 1.47.289 2 .764zM2 12h12a2 2 0 1 1 0 4H2a2 2 0 1 1 0-4zm10 1a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="doc_code" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zm1.036 7.607a.498.498 0 0 1-.147.354l-1.414 1.414a.5.5 0 0 1-.707-.707l1.06-1.06-1.06-1.061a.5.5 0 0 1 .707-.707l1.414 1.414a.498.498 0 0 1 .147.353zm-4.822 0l1.06 1.061a.5.5 0 0 1-.706.707l-1.414-1.414a.498.498 0 0 1 0-.707l1.414-1.414a.5.5 0 1 1 .707.707l-1.06 1.06zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"/></symbol><symbol viewBox="0 0 16 16" id="doc_image" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM7.333 9.667l1.313-1.313a.5.5 0 0 1 .708 0L12 11H4l2.188-1.75a.5.5 0 0 1 .624 0l.521.417zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 8a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4 11h8v.7a.3.3 0 0 1-.3.3H4.3a.3.3 0 0 1-.3-.3V11z"/></symbol><symbol viewBox="0 0 16 16" id="doc_text" xmlns="http://www.w3.org/2000/svg"><path d="M8 2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V7h-3a2 2 0 0 1-2-2V2zm2 .414V5h2.586L10 2.414zM5 0h4.586A2 2 0 0 1 11 .586L14.414 4A2 2 0 0 1 15 5.414V12a4 4 0 0 1-4 4H5a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm.5 11h5a.5.5 0 1 1 0 1h-5a.5.5 0 1 1 0-1zm0-2h5a.5.5 0 1 1 0 1h-5a.5.5 0 0 1 0-1zm0-2h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z"/></symbol><symbol viewBox="0 0 105 26" id="double-headed-arrow" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.018 11.089L15.138.614c1.23-.911 3.086-.795 4.147.26.461.46.715 1.045.715 1.651v20.95C20 24.869 18.684 26 17.06 26a3.238 3.238 0 0 1-1.921-.614L1.019 14.911C-.212 14-.347 12.405.714 11.35c.094-.094.195-.18.303-.261zm102.964 0c.108.08.21.167.303.26 1.061 1.056.925 2.65-.303 3.562l-14.12 10.475A3.238 3.238 0 0 1 87.94 26C86.316 26 85 24.87 85 23.475V2.525c0-.606.254-1.192.715-1.65 1.061-1.056 2.917-1.172 4.146-.26l14.12 10.474zM35 17a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm18 0a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="download" xmlns="http://www.w3.org/2000/svg"><path d="M9 12h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0l-2-2.667A.5.5 0 0 1 6 12h1V8a1 1 0 1 1 2 0v4zM4 9a1 1 0 1 1 0 2 4 4 0 0 1-1.971-7.481 4 4 0 0 1 6.633-2.505 3.999 3.999 0 0 1 3.82 2.014A4 4 0 0 1 12 11a1 1 0 0 1 0-2 2 2 0 1 0 0-4h-1a2 2 0 0 0-3.112-1.662A2 2 0 1 0 4.268 5H4a2 2 0 1 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M14 10h-3a1 1 0 0 1-1-1V6H8.527A.527.527 0 0 0 8 6.527V13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-3zm-4-7H8.527c-.18 0-.355.013-.527.04V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2v2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3zM8.527 4h2.323a.5.5 0 0 1 .35.143l4.65 4.551a.5.5 0 0 1 .15.357V13a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V6.527A2.527 2.527 0 0 1 8.527 4z"/></symbol><symbol viewBox="0 0 16 16" id="earth" xmlns="http://www.w3.org/2000/svg"><path d="M8.7 2.04l-.082.177c.283.223.422.413.417.571-.008.237-.311.057-.444.274-.133.218.038.542-.112.637-.15.096-.398-.386-.479-.46-.054-.049-.166-.257-.336-.625l-.216-.225a.844.844 0 0 0-.418-.035c-.177.038-.075.1-.035.132.04.032.32.037.452.2.132.164.03.224-.05.298-.054.05-.157.062-.31.035H5.952l-.402.398.03.325.229.455.324-.463c.008-.206.058-.342.15-.41.14-.1.342-.15.534-.085.191.066-.057.218.011.271.068.053.204-.098.313-.02.11.08.07.155.104.322.036.167.254.114.398.328.144.215.19.29.147.483-.043.195-.168.26-.305.232-.138-.028-.107-.246-.275-.348-.168-.102-.266-.114-.386-.054-.12.06-.016.129.023.235.04.106.274.321.224.43-.05.107-.108.116-.42 0-.21-.077-.414-.007-.615.212l-.76.722c-.153.715-.3 1.13-.44 1.243-.211.17-.177-.483-.483-.656-.306-.174-.494-.047-.8-.07-.307-.023-.42.65-.38.873a.434.434 0 0 0 .221.321c.236-.141.39-.184.465-.128.11.084-.144.267-.074.425.07.158.314.069.386.283.073.213.084.48-.05.706-.135.227-.275.178-.4.053-.127-.126-.033-.375-.255-.704-.223-.329-.381-.337-.63-.787-.158-.287-.35-.743-.575-1.366a6 6 0 0 0 3.21 7.198l.001-.075c0-.577-.004-.944-.012-1.102-.011-.236-.95-.945-1.104-1.2-.154-.256-.34-.595-.355-.746-.016-.151.185-.232.344-.325.16-.093-.11-.367.028-.626.137-.258.395-.438.496-.356.101.081.058.228.267.333.209.104.077-.213.456-.178.38.035.143.201.252.216.11.016.113-.127.299-.143.186-.015.282.445.471.622.19.178.452.008.611.043.159.034.267.09.402.255.136.166-.03.352.073.557.103.205 1.07.22 1.433.255.364.034.371.011.371.324s-.166.314-.453.507c-.286.193-.166.462-.38.762-.212.3-.316.062-.622.14-.306.077-.413.382-.452.568-.039.186-.386.094-.877.232-.29.082-.429.144-.569.204a6.002 6.002 0 0 0 7.682-4.3c-.094-.384-.18-.63-.258-.74-.213-.297-.36.21-.924.49-.564.278-.57-.288-.81-.49-.16-.133-.212-.44-.158-.92-.005-.478.02-.828.077-1.049.057-.221.126-.543.207-.965.351-.373.606-.572.764-.595.237-.034.336.374.658.3a.315.315 0 0 0 .035-.01 5.993 5.993 0 0 0-.475-.824l-.309-.043a.646.646 0 0 0-.332-.117c-.205-.02-.025.128-.089.24-.064.112-.235.724-.437.685-.201-.039-.204-.374-.17-.668.036-.294-.077-.35-.2-.412-.124-.062-.325-.213-.556-.295-.232-.082-.123-.175-.093-.274.03-.1.208-.015.193-.058-.014-.044-.313-.135-.266-.167.03-.02.2-.02.506.003l.216-.012.293-.163a.58.58 0 0 0-.376-.22c-.233-.036-.513-.034-.73-.142-.205-.103-.458-.36-.643-.638A5.965 5.965 0 0 0 8.7 2.04zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/></symbol><symbol viewBox="0 0 1600 1600" id="ellipsis_v" xmlns="http://www.w3.org/2000/svg"><path d="M1088 1248v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V736q0-40 28-68t68-28h192q40 0 68 28t28 68zm0-512v192q0 40-28 68t-68 28H800q-40 0-68-28t-28-68V224q0-40 28-68t68-28h192q40 0 68 28t28 68z"/></symbol><symbol viewBox="0 0 18 18" id="emoji_slightly_smiling_face" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369.721.721 0 0 1 .568.047.715.715 0 0 1 .37.445 2.91 2.91 0 0 0 1.084 1.518A2.93 2.93 0 0 0 9 12.75a2.93 2.93 0 0 0 1.775-.58 2.913 2.913 0 0 0 1.084-1.518.711.711 0 0 1 .375-.445.737.737 0 0 1 .575-.047c.195.063.34.186.433.37.094.183.11.372.047.568zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smile" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568zM14 6.37c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm-6.5 0c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm9 2.63a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 18 18" id="emoji_smiley" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568h.001zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6c.92.397 1.91.6 2.912.598a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39c.397-.92.6-1.91.598-2.912zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z"/></symbol><symbol viewBox="0 0 16 16" id="epic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.985 8.044l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637A2 2 0 0 0 1.618 9h11.661a2 2 0 0 0 1.706-.956zm0 3l-.757 2.272a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l.318-.637a2 2 0 0 0 .576.084h11.661a2 2 0 0 0 1.706-.956zM3.618 2h10.995a1 1 0 0 1 .948 1.316l-1.333 4a1 1 0 0 1-.949.684H1.618a1 1 0 0 1-.894-1.447l2-4A1 1 0 0 1 3.618 2zm-.382 4h9.322l.667-2H4.236l-1 2z"/></symbol><symbol viewBox="0 0 16 16" id="error" xmlns="http://www.w3.org/2000/svg"><title>error</title><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0-2A5 5 0 1 0 8 3a5 5 0 0 0 0 10zm0-9a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="expand" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.435 10.092l1.414-1.414a1 1 0 1 1 1.414 1.414L5.85 11.507l1.386 1.385a.5.5 0 0 1-.299.85l-4.709.524a.5.5 0 0 1-.552-.552L2.2 9.005a.5.5 0 0 1 .85-.298l1.386 1.385zm7.283-4.455l-1.414 1.415A1 1 0 1 1 8.89 5.637l1.414-1.414-1.386-1.386a.5.5 0 0 1 .299-.85l4.708-.523a.5.5 0 0 1 .553.552l-.524 4.709a.5.5 0 0 1-.85.298l-1.386-1.386z"/></symbol><symbol viewBox="0 0 16 16" id="external-link" xmlns="http://www.w3.org/2000/svg"><path d="M13.121 4.177l-4.95 4.95a1 1 0 1 1-1.414-1.414l4.95-4.95-1.386-1.386a.5.5 0 0 1 .299-.85l4.709-.524a.5.5 0 0 1 .552.552l-.523 4.71a.5.5 0 0 1-.851.297l-1.386-1.385zM12 8.884a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-4z"/></symbol><symbol viewBox="0 0 16 16" id="eye" xmlns="http://www.w3.org/2000/svg"><path d="M8 14C4.816 14 2.253 12.284.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2s5.747 1.716 7.607 5.019a2 2 0 0 1 0 1.962C13.747 12.284 11.184 14 8 14zm0-2c2.41 0 4.338-1.29 5.864-4C12.338 5.29 10.411 4 8 4 5.59 4 3.662 5.29 2.136 8 3.662 10.71 5.589 12 8 12zm0-1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm1-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="eye-slash" xmlns="http://www.w3.org/2000/svg"><path d="M13.618 2.62L1.62 14.619a1 1 0 0 1-.985-1.668l1.525-1.526C1.516 10.742.926 9.927.393 8.981a2 2 0 0 1 0-1.962C2.253 3.716 4.816 2 8 2c1.074 0 2.076.195 3.006.58l.944-.944a1 1 0 0 1 1.668.985zM8.068 11a3 3 0 0 0 2.931-2.932l-2.931 2.931zm-3.02-2.462a3 3 0 0 1 3.49-3.49l.884-.884A6.044 6.044 0 0 0 8 4C5.59 4 3.662 5.29 2.136 8c.445.79.924 1.46 1.439 2.011l1.473-1.473zm.421 5.06l1.658-1.658c.283.04.575.06.873.06 2.41 0 4.338-1.29 5.864-4a11.023 11.023 0 0 0-1.133-1.664l1.418-1.418a12.799 12.799 0 0 1 1.458 2.1 2 2 0 0 1 0 1.963C13.747 12.284 11.184 14 8 14a7.883 7.883 0 0 1-2.53-.402z"/></symbol><symbol viewBox="0 0 16 16" id="file-addition" xmlns="http://www.w3.org/2000/svg"><path d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3z"/></symbol><symbol viewBox="0 0 16 16" id="file-deletion" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm2 6h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="file-modified" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm5 4a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/></symbol><symbol viewBox="0 0 16 16" id="filter" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 6v9l-3.724-1.862A.5.5 0 0 1 6 12.691V6L1.854 1.854A.5.5 0 0 1 2.207 1h11.586a.5.5 0 0 1 .353.854L10 6z"/></symbol><symbol viewBox="0 0 16 16" id="folder" xmlns="http://www.w3.org/2000/svg"><path d="M13 3a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="folder-o" xmlns="http://www.w3.org/2000/svg"><path d="M13 5l-4.365-.005a2 2 0 0 1-1.882-1.33A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1zm0-2a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.81a3 3 0 0 1 2.827 1.995L13 3z"/></symbol><symbol viewBox="0 0 16 16" id="folder-open" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14.59 5.464a2.998 2.998 0 0 1 1.096 3.845l-1.666 3.436A4 4 0 0 1 10.46 15H3a3 3 0 0 1-3-3V3a2 2 0 0 1 2-2h3.558a2 2 0 0 1 1.898 1.368l.21.632h4.973a2 2 0 0 1 2 2 2 2 0 0 1-.027.329l-.023.135zM5.285 7a1 1 0 0 0-.9.564l-1.939 4a1 1 0 0 0 .9 1.436h7.074a2 2 0 0 0 1.8-1.128l1.665-3.436a1 1 0 0 0-.9-1.436h-7.7z"/></symbol><symbol viewBox="0 0 16 16" id="fork" xmlns="http://www.w3.org/2000/svg"><path d="M9 12.268a2 2 0 1 1-2 0V8.874A4.002 4.002 0 0 1 4 5V3.732a2 2 0 1 1 2 0V5a2 2 0 1 0 4 0V3.732a2 2 0 1 1 2 0V5a4.002 4.002 0 0 1-3 3.874v3.394zM11 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm3 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="geo-nodes" xmlns="http://www.w3.org/2000/svg"><path d="M9.7 13.1l-.2.2c-.7.8-2 .9-2.8.1-.1 0-.1-.1-.1-.1l-.2-.2c-2 .2-3.4.7-3.4 1.4 0 .8 2.2 1.5 5 1.5s5-.7 5-1.5c0-.7-1.4-1.2-3.3-1.4M7.3 12.7c.4.4 1 .3 1.4-.1C11.6 9.5 13 7 13 5.3 13 2.4 10.8 0 8 0S3 2.4 3 5.3C3 7 4.4 9.5 7.3 12.7M8 2c1.6 0 3 1.4 3 3.3 0 1-1 2.8-3 5.2-2-2.4-3-4.2-3-5.2C5 3.4 6.4 2 8 2"/><circle cx="8" cy="5" r="1"/></symbol><symbol viewBox="0 0 16 16" id="git-merge" xmlns="http://www.w3.org/2000/svg"><path d="M11 12.268V5a1 1 0 0 0-1-1v1a.5.5 0 0 1-.8.4l-2.667-2a.5.5 0 0 1 0-.8L9.2.6a.5.5 0 0 1 .8.4v1a3 3 0 0 1 3 3v7.268a2 2 0 1 1-2 0zm-6 0a2 2 0 1 1-2 0V4.732a2 2 0 1 1 2 0v7.536zM4 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="go-back" xmlns="http://www.w3.org/2000/svg"><path d="M4.9 7V6a.5.5 0 0 0-.8-.4l-2.667 2a.5.5 0 0 0 0 .8l2.667 2a.5.5 0 0 0 .8-.4V9h4a1 1 0 1 0 0-2h-4zM7 12a1 1 0 0 0-2 0 3 3 0 0 0 3 3h3a4 4 0 0 0 4-4V5a4 4 0 0 0-4-4H8a3 3 0 0 0-3 3 1 1 0 1 0 2 0 1 1 0 0 1 1-1h3a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H8a1 1 0 0 1-1-1z"/></symbol><symbol viewBox="0 0 16 16" id="group" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3.048 11.997C-.377 11.975.013 11.782.013 10.56.013 9.235.653 8 4 8c.444 0 .84.022 1.194.062.164.435.426.82.76 1.132-1.786.389-2.721 1.353-2.906 2.803zm2.94-7.222a2.993 2.993 0 0 0-.976 1.95 2 2 0 1 1 .975-1.95zm6.964 7.222c-.185-1.45-1.12-2.414-2.906-2.803.334-.311.596-.697.76-1.132C11.16 8.022 11.556 8 12 8c3.346 0 3.987 1.235 3.987 2.56 0 1.222.39 1.415-3.035 1.437zm-1.964-5.272a2.993 2.993 0 0 0-.976-1.95 2 2 0 1 1 .976 1.95zM8 9a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 5c-2.177 0-3.987-.115-3.987-1.44S4.653 10 8 10c3.346 0 3.987 1.235 3.987 2.56S10.177 14 8 14z"/></symbol><symbol viewBox="0 0 16 16" id="history" xmlns="http://www.w3.org/2000/svg"><path d="M2.868 3.24a7 7 0 1 1-.043 9.475 1 1 0 0 1 1.478-1.348 5 5 0 1 0 .124-6.865l.796.645a.5.5 0 0 1-.193.873l-3.232.814a.5.5 0 0 1-.622-.504L1.3 3a.5.5 0 0 1 .814-.37l.754.61zM9 8h1a1 1 0 0 1 0 2H8a.997.997 0 0 1-1-1V6a1 1 0 1 1 2 0v2z"/></symbol><symbol viewBox="0 0 16 16" id="home" xmlns="http://www.w3.org/2000/svg"><path d="M9 13h3v-3H4v3h3v-1a1 1 0 0 1 2 0v1zm5-3v3.659c0 .729-.657 1.341-1.5 1.341h-9c-.843 0-1.5-.612-1.5-1.341V10h-.88C.502 10 0 9.486 0 8.853c0-.307.12-.601.333-.816l6.405-6.463a1.56 1.56 0 0 1 2.374-.052L15.66 8.03c.444.441.455 1.167.024 1.622a1.108 1.108 0 0 1-.804.348H14zM7.95 3.273l-4.595 4.64h9.264l-4.67-4.64z"/></symbol><symbol viewBox="0 0 16 16" id="hook" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1h4zm0 1H6v1a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V4zM7 8a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3v4a2 2 0 1 0 4 0h-.44a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H15a4 4 0 0 1-7 2.646A4 4 0 0 1 1 12H.56a.3.3 0 0 1-.25-.466l1.44-2.16a.3.3 0 0 1 .5 0l1.44 2.16a.3.3 0 0 1-.25.466H3a2 2 0 1 0 4 0V8z"/></symbol><symbol viewBox="0 0 16 16" id="hourglass" xmlns="http://www.w3.org/2000/svg"><path d="M10.331 4.889A2.988 2.988 0 0 0 11 3V2H5v1c0 .362.064.709.182 1.03l5.15.859zM3 14v-1c0-1.78.93-3.342 2.33-4.228.447-.327.67-.582.67-.764 0-.19-.242-.46-.725-.815A4.996 4.996 0 0 1 3 3V2H2a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2h-1v1a4.997 4.997 0 0 1-2.39 4.266c-.407.3-.61.545-.61.734 0 .19.203.434.61.734A4.997 4.997 0 0 1 13 13v1h1a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2h1zm8 0v-1a3 3 0 0 0-6 0v1h6z"/></symbol><symbol viewBox="0 0 38 38" id="image-comment-dark" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="19" cy="19" r="18" fill="#1F78D1"/><path fill="#FFF" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-2c9.389 0 17-7.611 17-17S28.389 2 19 2 2 9.611 2 19s7.611 17 17 17zm-6.293-8.293c-.63.63-1.707.184-1.707-.707V15a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-7.586l-3.707 3.707zM13 24.586l2.293-2.293A1 1 0 0 1 16 22h8a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1H14a1 1 0 0 0-1 1v9.586z"/></g></symbol><symbol viewBox="0 0 38 38" id="image-comment-light" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="19" cy="19" r="18" fill="#FFF"/><path fill="#1F78D1" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-2c9.389 0 17-7.611 17-17S28.389 2 19 2 2 9.611 2 19s7.611 17 17 17zm-6.293-8.293c-.63.63-1.707.184-1.707-.707V15a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-7.586l-3.707 3.707zM13 24.586l2.293-2.293A1 1 0 0 1 16 22h8a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1H14a1 1 0 0 0-1 1v9.586z"/></g></symbol><symbol viewBox="0 0 16 16" id="import" xmlns="http://www.w3.org/2000/svg"><path d="M9 8h1a.5.5 0 0 1 .4.8l-2 2.667a.5.5 0 0 1-.8 0L5.6 8.8A.5.5 0 0 1 6 8h1V1a1 1 0 1 1 2 0v7zM0 8a1 1 0 1 1 2 0 6 6 0 1 0 12 0 1 1 0 0 1 2 0A8 8 0 1 1 0 8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-block" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.803 8a5.97 5.97 0 0 0-.462 1H4.5a.5.5 0 0 1 0-1h1.303zM4.5 5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1zm7.5.083a6.04 6.04 0 0 0-2 0V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2.083a5.96 5.96 0 0 0 .72 2H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h6a3 3 0 0 1 3 3v2.083zm1.121 3.796zM11 16a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm-1.293-2.292a3 3 0 0 0 4.001-4.001l-4.001 4zm-1.415-1.415l4.001-4a3 3 0 0 0-4.001 4.001z"/></symbol><symbol viewBox="0 0 16 16" id="issue-child" xmlns="http://www.w3.org/2000/svg"><path d="M11 8H5v1h1a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h2V7a.997.997 0 0 1 1-1h3V4H4.5a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9v2h3a.997.997 0 0 1 1 1v2h2a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm-9 3v2h3v-2H2zm9 0v2h3v-2h-3z"/></symbol><symbol viewBox="0 0 16 16" id="issue-close" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-duplicate" xmlns="http://www.w3.org/2000/svg"><path d="M10.874 2H12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-2c-.918 0-1.74-.413-2.29-1.063a3.987 3.987 0 0 0 1.988-.984A1 1 0 0 0 10 14h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-1V3c0-.345-.044-.68-.126-1zM4 0h3a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-external" xmlns="http://www.w3.org/2000/svg"><path d="M11 4a5.99 5.99 0 0 0-2 .341V3a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h2.528a6.003 6.003 0 0 0 2.705 1.736A2.99 2.99 0 0 1 8 16H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h4a3 3 0 0 1 3 3v1zM8.212 8.97l-.568-.876A.25.25 0 0 1 7.66 7.8l.404-.5a.25.25 0 0 1 .284-.076l.938.36c.256-.182.543-.325.85-.42l.323-.988a.25.25 0 0 1 .237-.173h.643a.25.25 0 0 1 .238.173l.321.989c.308.094.595.237.852.418l.937-.359a.25.25 0 0 1 .284.076l.404.5a.25.25 0 0 1 .016.293l-.568.875c.113.297.18.616.192.95l.9.54a.25.25 0 0 1 .114.27l-.145.627a.25.25 0 0 1-.221.192l-1.115.098a3.015 3.015 0 0 1-.512.608l.165 1.18a.25.25 0 0 1-.138.259l-.577.282a.25.25 0 0 1-.29-.051l-.874-.905a3.035 3.035 0 0 1-.608 0l-.875.905a.25.25 0 0 1-.29.05l-.577-.281a.25.25 0 0 1-.138-.26L9 12.254a3.015 3.015 0 0 1-.512-.607l-1.114-.098a.25.25 0 0 1-.222-.192l-.145-.627a.25.25 0 0 1 .115-.27l.899-.54c.012-.334.08-.653.192-.95zm2.806 2.034a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="issue-new" xmlns="http://www.w3.org/2000/svg"><path d="M10 2V1a1 1 0 0 1 2 0v1h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0V4H9a1 1 0 1 1 0-2h1zm0 6a1 1 0 0 1 2 0v5a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h1a1 1 0 1 1 0 2H5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V8z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm0-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="issue-open-m" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="issue-parent" xmlns="http://www.w3.org/2000/svg"><path d="M11 11H5v1h1.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H3v-2a.997.997 0 0 1 1-1h3V7H5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H9v2h3a.997.997 0 0 1 1 1v2h2.5a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-6a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5H11v-1zM6 3v2h4V3H6z"/></symbol><symbol viewBox="0 0 16 16" id="issues" xmlns="http://www.w3.org/2000/svg"><path d="M10.458 15.012l.311.055a3 3 0 0 0 3.476-2.433l1.389-7.879A3 3 0 0 0 13.2 1.28L11.23.933a3.002 3.002 0 0 0-.824-.031c.364.59.58 1.28.593 2.02l1.854.328a1 1 0 0 1 .811 1.158l-1.389 7.879a1 1 0 0 1-1.158.81l-.118-.02a3.98 3.98 0 0 1-.541 1.935zM3 0h4a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="italic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.5 12l2-8H6a1 1 0 1 1 0-2h6a1 1 0 0 1 0 2h-1.5l-2 8H10a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2h1.5z"/></symbol><symbol viewBox="0 0 16 16" id="key" xmlns="http://www.w3.org/2000/svg"><path d="M7.575 6.689a4.002 4.002 0 0 1 6.274-4.86 4 4 0 0 1-4.86 6.274l-2.21 2.21.706.708a1 1 0 1 1-1.414 1.414l-.707-.707-.707.707.707.707a1 1 0 1 1-1.414 1.414l-.707-.707a1 1 0 0 1-1.414-1.414l5.746-5.746zm2.032-.618a2 2 0 1 0 2.828-2.828A2 2 0 0 0 9.607 6.07z"/></symbol><symbol viewBox="0 0 16 16" id="key-2" xmlns="http://www.w3.org/2000/svg"><path d="M5.172 14.157l-.344.344-2.485.133a.462.462 0 0 1-.497-.503l.14-2.24a.599.599 0 0 1 .177-.382l5.155-5.155a4 4 0 1 1 2.828 2.828l-1.439 1.44-1.06-.354-.708.707.354 1.06-.707.708-1.06-.354-.708.707.354 1.06zm6.01-8.839a1 1 0 1 0 1.414-1.414 1 1 0 0 0-1.414 1.414z"/></symbol><symbol viewBox="0 0 16 16" id="label" xmlns="http://www.w3.org/2000/svg"><path d="M11.782 14.718a3 3 0 0 1-4.242 0L1.652 8.829a2 2 0 0 1-.565-1.702l.54-3.703a2 2 0 0 1 1.69-1.69l3.703-.54a2 2 0 0 1 1.703.564l5.888 5.888a3 3 0 0 1 0 4.243l-2.829 2.829zm1.415-5.657L7.309 3.173l-3.703.54-.54 3.702 5.888 5.888a1 1 0 0 0 1.414 0l2.829-2.828a1 1 0 0 0 0-1.414zM5.732 5.525A1 1 0 1 1 7.146 6.94a1 1 0 0 1-1.414-1.414z"/></symbol><symbol viewBox="0 0 16 16" id="labels" xmlns="http://www.w3.org/2000/svg"><path d="M9.424 2.254l2.08-.905a1 1 0 0 1 1.206.326l3.013 4.12a1 1 0 0 1 .16.849l-1.947 7.264a3 3 0 0 1-3.675 2.122l-.5-.135a3.999 3.999 0 0 0 1.082-1.782 1 1 0 0 0 1.16-.722l1.823-6.802-2.258-3.087-.687.299a2 2 0 0 0-.628-.88l-.829-.667zM.377 3.7L4.4.498a1 1 0 0 1 1.25.003L9.627 3.7a1 1 0 0 1 .373.78V13a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4.482A1 1 0 0 1 .377 3.7zM2 13a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V4.958L5.02 2.561 2 4.964V13zm3-6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="leave" xmlns="http://www.w3.org/2000/svg"><path d="M11 7V5.883a.5.5 0 0 1 .757-.429l3.528 2.117a.5.5 0 0 1 0 .858l-3.528 2.117a.5.5 0 0 1-.757-.43V9H7a1 1 0 1 1 0-2h4zm-2 6.256a1 1 0 0 1 2 0A2.744 2.744 0 0 1 8.256 16H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h5.19A2.81 2.81 0 0 1 11 2.81a1 1 0 0 1-2 0A.81.81 0 0 0 8.19 2H3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h5.256c.41 0 .744-.333.744-.744z"/></symbol><symbol viewBox="0 0 16 16" id="level-up" xmlns="http://www.w3.org/2000/svg"><path fill="#2E2E2E" fill-rule="evenodd" d="M7 6h3.489a.5.5 0 0 0 .373-.832L6.374.117a.5.5 0 0 0-.748 0l-4.488 5.05A.5.5 0 0 0 1.51 6H5v7a3 3 0 0 0 3 3h6a1 1 0 0 0 0-2H8a1 1 0 0 1-1-1V6z"/></symbol><symbol viewBox="0 0 16 16" id="license" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M12.56 8.9l2.66 4.606a.3.3 0 0 1-.243.45l-1.678.094a.1.1 0 0 0-.078.044l-.953 1.432a.3.3 0 0 1-.51-.016L9.097 10.9a5.994 5.994 0 0 0 3.464-2zm-5.23 2.063L4.707 15.51a.3.3 0 0 1-.51.016l-.953-1.432a.1.1 0 0 0-.078-.044l-1.678-.094a.3.3 0 0 1-.243-.45l2.48-4.297a5.983 5.983 0 0 0 3.607 1.754zM8 10A5 5 0 1 1 8 0a5 5 0 0 1 0 10zm0-2a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-1a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="link" xmlns="http://www.w3.org/2000/svg"><path d="M6.986 3.35l2.12-2.122a4 4 0 0 1 5.657 5.657l-2.828 2.829a4 4 0 0 1-5.657 0 1 1 0 0 1 1.414-1.415 2 2 0 0 0 2.829 0l2.828-2.828a2 2 0 1 0-2.828-2.828l-1.001 1a5.018 5.018 0 0 0-2.534-.294zm2.12 9.192l-2.12 2.121a4 4 0 1 1-5.658-5.656l2.829-2.829a4 4 0 0 1 5.657 0 1 1 0 1 1-1.415 1.414 2 2 0 0 0-2.828 0l-2.828 2.829a2 2 0 1 0 2.828 2.828l1.001-1.001a5.018 5.018 0 0 0 2.534.294z"/></symbol><symbol viewBox="0 0 16 16" id="list-bulleted" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-7h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 5h10a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm-4 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4-2h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="list-numbered" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 2h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm0 5h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2zM1.156 5v-.828h.816V2.204h-.72v-.636c.432-.084.708-.192.996-.372h.756v2.976h.684V5H1.156zm-.18 5v-.588c.9-.828 1.596-1.464 1.596-1.98 0-.342-.192-.504-.468-.504-.252 0-.444.18-.624.36l-.552-.552c.396-.42.756-.612 1.32-.612.768 0 1.308.492 1.308 1.248 0 .612-.576 1.284-1.092 1.812.192-.024.468-.048.636-.048h.636V10H.976zm1.26 5.072c-.618 0-1.068-.204-1.356-.54l.468-.648c.234.216.51.36.78.36.336 0 .552-.12.552-.36 0-.288-.15-.456-.948-.456v-.72c.636 0 .828-.168.828-.432 0-.228-.138-.348-.396-.348-.252 0-.432.108-.672.312l-.516-.624c.372-.312.768-.492 1.236-.492.84 0 1.38.384 1.38 1.074 0 .366-.204.642-.612.822v.024c.432.132.732.432.732.912 0 .72-.684 1.116-1.476 1.116z"/></symbol><symbol viewBox="0 0 16 16" id="location" xmlns="http://www.w3.org/2000/svg"><path d="M8.755 15.144a1 1 0 0 1-1.51 0C3.748 11.114 2 8.065 2 6a6 6 0 1 1 12 0c0 2.065-1.748 5.113-5.245 9.144zM12 6a4 4 0 1 0-8 0c0 1.314 1.312 3.71 4 6.944C10.688 9.71 12 7.314 12 6zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="location-dot" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.314 13.087C4.382 13.295 3 13.85 3 14.5c0 .828 2.239 1.5 5 1.5s5-.672 5-1.5c0-.65-1.382-1.205-3.314-1.413l-.202.225a2 2 0 0 1-2.968 0l-.202-.225zm2.428-.445a1 1 0 0 1-1.484 0C4.419 9.5 3 7.037 3 5.252 3 2.353 5.239 0 8 0s5 2.352 5 5.253c0 1.784-1.42 4.247-4.258 7.389zM11 5.252C11 3.436 9.634 2 8 2S5 3.435 5 5.253c0 1.027.974 2.824 3 5.203 2.026-2.38 3-4.176 3-5.203zM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="lock" xmlns="http://www.w3.org/2000/svg"><path d="M10 5V4h2v1a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V8a3 3 0 0 1 3-3V4h2v1h4zM4 7a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H4zm0-3a4 4 0 1 1 8 0h-2a2 2 0 1 0-4 0H4z"/></symbol><symbol viewBox="0 0 16 16" id="lock-open" xmlns="http://www.w3.org/2000/svg"><path d="M4.044 4a4 4 0 0 1 6.99-2.658 1 1 0 1 1-1.495 1.33A2 2 0 0 0 6.044 4a.998.998 0 0 1-.07.367v.701H12a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3v-5a3 3 0 0 1 2.974-3V4h.07zM4 7.07a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H4z"/></symbol><symbol viewBox="0 0 16 16" id="log" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H4zm1 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0 3a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-5h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm0 3h3a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zm-3 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm3-2h3a1 1 0 0 1 0 2H8a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="mail" xmlns="http://www.w3.org/2000/svg"><path d="M14 5.6L9.338 9.796a2 2 0 0 1-2.676 0L2 5.6V11a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5.6zM3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm.212 2L8 8.31 12.788 4H3.212z"/></symbol><symbol viewBox="0 0 16 16" id="menu" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1.143 2h13.714C15.488 2 16 2.448 16 3s-.512 1-1.143 1H1.143C.512 4 0 3.552 0 3s.512-1 1.143-1zm0 5h13.714C15.488 7 16 7.448 16 8s-.512 1-1.143 1H1.143C.512 9 0 8.552 0 8s.512-1 1.143-1zm0 5h13.714c.631 0 1.143.448 1.143 1s-.512 1-1.143 1H1.143C.512 14 0 13.552 0 13s.512-1 1.143-1z"/></symbol><symbol viewBox="0 0 16 16" id="merge-request-close" xmlns="http://www.w3.org/2000/svg"><path d="M9.414 8l1.414 1.414a1 1 0 1 1-1.414 1.414L8 9.414l-1.414 1.414a1 1 0 1 1-1.414-1.414L6.586 8 5.172 6.586a1 1 0 1 1 1.414-1.414L8 6.586l1.414-1.414a1 1 0 1 1 1.414 1.414L9.414 8zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 16 16" id="messages" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-.98-1.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM4.464 2.464L5.88 3.88a3 3 0 0 0 0 4.242L4.464 9.536a5 5 0 0 1 0-7.072zm7.072 7.072L10.12 8.12a3 3 0 0 0 0-4.242l1.415-1.415a5 5 0 0 1 0 7.072zM2.343.343l1.414 1.414a6 6 0 0 0 0 8.486l-1.414 1.414a8 8 0 0 1 0-11.314zm11.314 11.314l-1.414-1.414a6 6 0 0 0 0-8.486L13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="mobile-issue-close" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5.657 10.728L2.12 7.192A1 1 0 1 0 .707 8.607l4.243 4.242a.997.997 0 0 0 1.414 0l8.485-8.485a1 1 0 1 0-1.414-1.414l-7.778 7.778z"/></symbol><symbol viewBox="0 0 16 16" id="monitor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 13v1h3a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2h3v-1H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3h-3zM3 2a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm5.723 6.416l-2.66-1.773-1.71 1.71a.5.5 0 1 1-.707-.707l2-2a.5.5 0 0 1 .631-.062l2.66 1.773 2.71-2.71a.5.5 0 0 1 .707.707l-3 3a.5.5 0 0 1-.631.062z"/></symbol><symbol viewBox="0 0 16 16" id="monitor-lines" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 12v1h3a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2h3v-1H4a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3h-2zM4 3a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H4zm1.5 2h5a.5.5 0 1 1 0 1h-5a.5.5 0 0 1 0-1zm0 2h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="more" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 4a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="notifications" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 14H2.435a2 2 0 0 1-1.761-2.947c.962-1.788 1.521-3.065 1.68-3.832.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024c3.755.528 4.375 4.27 4.761 6.043.188.86.742 2.188 1.661 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0zm5.805-6.468c-.325-1.492-.37-1.674-.61-2.288C10.6 3.716 9.742 3 8.07 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.208 1.012-.827 2.424-1.877 4.375H13.64c-.993-1.937-1.6-3.396-1.835-4.468z"/></symbol><symbol viewBox="0 0 16 16" id="notifications-off" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.26 5.089c.243.757.382 1.478.5 2.017.187.86.74 2.188 1.66 3.982A2 2 0 0 1 13.64 14H10a2 2 0 1 1-4 0H4.35l2-2h7.29c-.993-1.937-1.6-3.396-1.835-4.468-.07-.326-.129-.59-.178-.81l1.634-1.633zM10.943 1.75l-1.48 1.48C9.07 3.076 8.612 3 8.069 3c-1.608 0-2.49.718-3.103 2.197-.28.676-.356.982-.654 2.428-.065.317-.17.673-.317 1.073L.45 12.242a1.99 1.99 0 0 1 .224-1.19c.962-1.787 1.521-3.064 1.68-3.831.322-1.566.947-5.501 4.65-6.134a1 1 0 1 1 1.994-.024 4.867 4.867 0 0 1 1.944.688zm2.932-.105a1 1 0 0 1 0 1.415L2.561 14.374a1 1 0 1 1-1.415-1.414L12.46 1.646a1 1 0 0 1 1.414 0z"/></symbol><symbol viewBox="0 0 16 16" id="overview" xmlns="http://www.w3.org/2000/svg"><path d="M2 0h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 2v3h3V2h-3zM2 9h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3H2zm9-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm0 2v3h3v-3h-3z"/></symbol><symbol viewBox="0 0 16 16" id="pencil" xmlns="http://www.w3.org/2000/svg"><path d="M13.02 1.293l1.414 1.414a1 1 0 0 1 0 1.414L4.119 14.436a1 1 0 0 1-.704.293l-2.407.008L1 12.316a1 1 0 0 1 .293-.71L11.605 1.292a1 1 0 0 1 1.414 0zm-1.416 1.415l-.707.707L12.31 4.83l.707-.707-1.414-1.415zM3.411 13.73l1.123-1.122H3.12v-1.415L2 12.312l.005 1.422 1.406-.005z"/></symbol><symbol viewBox="0 0 16 16" id="pencil-square" xmlns="http://www.w3.org/2000/svg"><path d="M12 9a1 1 0 0 1 2 0v4a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h4a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V9zm.778-7.179l1.414 1.415-6.476 6.476a1 1 0 0 1-.498.27l-1.51.325.323-1.512a1 1 0 0 1 .27-.497l6.477-6.477zM15.607.407a1 1 0 0 1 0 1.414l-.708.707-1.414-1.414.707-.707a1 1 0 0 1 1.415 0z"/></symbol><symbol viewBox="0 0 16 16" id="pipeline" xmlns="http://www.w3.org/2000/svg"><path d="M8.969 7.25a2 2 0 1 1-1.938 0A1.002 1.002 0 0 1 7 7V5.083a.2.2 0 0 1 .06-.142l.877-.87a.1.1 0 0 1 .141 0l.864.87A.2.2 0 0 1 9 5.083V7c0 .086-.01.17-.031.25zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm4.5-4a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-5 9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-9a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm-2 6a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zm0-3a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1zM8 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="play" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.765 15.835c-.545.321-1.258.159-1.593-.363A1.075 1.075 0 0 1 1 14.89V1.11C1 .496 1.518 0 2.158 0c.214 0 .424.057.607.165l11.684 6.89c.544.321.714 1.005.38 1.526a1.135 1.135 0 0 1-.38.364l-11.684 6.89z"/></symbol><symbol viewBox="0 0 16 16" id="plus" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7H2a1 1 0 1 0 0 2h5v5a1 1 0 0 0 2 0V9h5a1 1 0 0 0 0-2H9V2a1 1 0 1 0-2 0v5z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 7V4a1 1 0 1 0-2 0v3H4a1 1 0 1 0 0 2h3v3a1 1 0 0 0 2 0V9h3a1 1 0 0 0 0-2H9zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3z"/></symbol><symbol viewBox="0 0 16 16" id="plus-square-o" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7 7V5a1 1 0 1 1 2 0v2h2a1 1 0 0 1 0 2H9v2a1 1 0 0 1-2 0V9H5a1 1 0 1 1 0-2h2zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="podcast" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.588 8.942l1.173 5.862a1 1 0 0 1-.785 1.177A1 1 0 0 1 8.78 16H7.22a1 1 0 0 1-1-1 1 1 0 0 1 .02-.196l1.172-5.862a3.014 3.014 0 0 0 1.176 0zM8 7.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zM4.464 2.464A1 1 0 0 1 5.88 3.88a3 3 0 0 0 0 4.242 1 1 0 0 1-1.415 1.415 5 5 0 0 1 0-7.072zm7.072 7.072A1 1 0 0 1 10.12 8.12a3 3 0 0 0 0-4.242 1 1 0 0 1 1.415-1.415 5 5 0 0 1 0 7.072zM2.343.343a1 1 0 1 1 1.414 1.414 6 6 0 0 0 0 8.486 1 1 0 1 1-1.414 1.414 8 8 0 0 1 0-11.314zm11.314 11.314a1 1 0 1 1-1.414-1.414 6 6 0 0 0 0-8.486A1 1 0 0 1 13.657.343a8 8 0 0 1 0 11.314z"/></symbol><symbol viewBox="0 0 16 16" id="preferences" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M5 12h10a1 1 0 0 1 0 2H5a1 1 0 0 1-2 0v-2a1 1 0 0 1 2 0zm-3 0H1a1 1 0 0 0 0 2h1v-2zm11-5h2a1 1 0 0 1 0 2h-2a1 1 0 0 1-2 0V7a1 1 0 0 1 2 0zm-3 0H1a1 1 0 1 0 0 2h9V7zM6 2h9a1 1 0 0 1 0 2H6a1 1 0 1 1-2 0V2a1 1 0 1 1 2 0zM3 2H1a1 1 0 1 0 0 2h2V2z"/></symbol><symbol viewBox="0 0 16 16" id="profile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-4.274-3.404C4.412 9.709 5.694 9 8 9c2.313 0 3.595.7 4.28 1.586A4.997 4.997 0 0 1 8 13a4.997 4.997 0 0 1-4.274-2.404zM8 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></symbol><symbol viewBox="0 0 16 16" id="project" xmlns="http://www.w3.org/2000/svg"><path d="M8.462 2.177l-.038.044a.505.505 0 0 0 .038-.044zm-.787 0a.5.5 0 0 0 .038.043l-.038-.043zM3.706 7h8.725L8.069 2.585 3.706 7zM7 13.369V12a1 1 0 0 1 2 0v1.369h3V9H4v4.369h3zM14 9v4.836c0 .833-.657 1.533-1.5 1.533h-9c-.843 0-1.5-.7-1.5-1.533V9h-.448a1.1 1.1 0 0 1-.783-1.873L6.934.887a1.5 1.5 0 0 1 2.269 0l6.165 6.24A1.1 1.1 0 0 1 14.585 9H14z"/></symbol><symbol viewBox="0 0 16 16" id="push-rules" xmlns="http://www.w3.org/2000/svg"><path d="M6.268 9a2 2 0 0 1 3.464 0H11a1 1 0 0 1 0 2H9.732a2 2 0 0 1-3.464 0H5a1 1 0 0 1 0-2h1.268zM7 2H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1h-1v3.515a.3.3 0 0 1-.434.268l-1.432-.716a.3.3 0 0 0-.268 0l-1.432.716A.3.3 0 0 1 7 5.515V2zM4 0h8a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm4 11a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="question" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm-1.46-5.602h2.233a3.97 3.97 0 0 1 .051-.558c.029-.17.073-.326.133-.469.06-.143.14-.28.242-.41.102-.13.228-.263.38-.399.26-.24.504-.467.733-.683a5.03 5.03 0 0 0 .598-.668c.17-.23.302-.477.399-.742a2.66 2.66 0 0 0 .144-.907c0-.505-.083-.95-.25-1.335a2.55 2.55 0 0 0-.723-.97 3.2 3.2 0 0 0-1.152-.589 5.441 5.441 0 0 0-1.531-.2c-.516 0-.998.063-1.445.188a3.19 3.19 0 0 0-1.168.59c-.331.268-.594.61-.79 1.027-.195.417-.295.917-.3 1.5h2.64c.006-.224.04-.416.102-.578.062-.161.142-.293.238-.394a.921.921 0 0 1 .332-.227 1.04 1.04 0 0 1 .39-.074c.34 0 .593.095.763.285.169.19.254.488.254.895 0 .328-.106.63-.317.906-.21.276-.499.565-.863.867-.214.182-.39.374-.531.574-.141.2-.253.42-.336.657a3.656 3.656 0 0 0-.176.777 7.89 7.89 0 0 0-.05.937zm-.321 2.375c0 .188.035.362.105.524.07.161.17.3.301.418.13.117.284.21.46.277.178.068.376.102.595.102.218 0 .416-.034.593-.102.178-.068.331-.16.461-.277a1.2 1.2 0 0 0 .301-.418c.07-.162.106-.336.106-.524a1.3 1.3 0 0 0-.106-.523 1.2 1.2 0 0 0-.3-.418 1.461 1.461 0 0 0-.462-.277 1.651 1.651 0 0 0-.593-.102c-.22 0-.417.034-.594.102a1.46 1.46 0 0 0-.461.277 1.2 1.2 0 0 0-.3.418 1.284 1.284 0 0 0-.106.523z"/></symbol><symbol viewBox="0 0 16 16" id="question-o" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-.778-4.151c0-.301.014-.575.044-.82a3.2 3.2 0 0 1 .154-.68c.073-.208.17-.4.294-.575.123-.176.278-.343.465-.503a4.81 4.81 0 0 0 .755-.758c.185-.242.277-.506.277-.793 0-.356-.074-.617-.222-.783-.148-.166-.37-.25-.667-.25a.92.92 0 0 0-.342.065.806.806 0 0 0-.29.199 1.04 1.04 0 0 0-.209.345 1.5 1.5 0 0 0-.088.506H5.082c.005-.51.092-.948.263-1.313.171-.364.401-.664.69-.899.29-.234.63-.406 1.023-.516a4.66 4.66 0 0 1 1.264-.164c.497 0 .944.058 1.34.174.397.117.733.289 1.008.517.276.227.487.51.633.847.146.337.218.727.218 1.17 0 .295-.042.56-.126.792a2.52 2.52 0 0 1-.349.65 4.4 4.4 0 0 1-.523.584c-.2.19-.414.389-.642.598a2.73 2.73 0 0 0-.332.349c-.089.114-.16.233-.212.359a1.868 1.868 0 0 0-.116.41 3.39 3.39 0 0 0-.044.489H7.222zm-.28 2.078c0-.164.03-.317.092-.458a1.05 1.05 0 0 1 .263-.366c.114-.103.248-.183.403-.243a1.45 1.45 0 0 1 .52-.089c.191 0 .364.03.52.09.154.059.289.14.403.242.114.103.201.224.263.366.061.141.092.294.092.458 0 .164-.03.316-.092.458a1.05 1.05 0 0 1-.263.365 1.278 1.278 0 0 1-.404.243 1.43 1.43 0 0 1-.52.089c-.19 0-.364-.03-.519-.089-.155-.06-.29-.14-.403-.243a1.05 1.05 0 0 1-.263-.365 1.135 1.135 0 0 1-.093-.458z"/></symbol><symbol viewBox="0 0 16 16" id="quote" xmlns="http://www.w3.org/2000/svg"><path d="M15 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9h-2a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1zM7 3v8a3 3 0 0 1-3 3 1 1 0 0 1 0-2 1 1 0 0 0 1-1V9H3a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h3a1 1 0 0 1 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="redo" xmlns="http://www.w3.org/2000/svg"><path d="M4.625 4.423A4.897 4.897 0 0 1 8.079 3c2.73 0 4.944 2.239 4.944 5s-2.214 5-4.944 5c-1.41 0-2.723-.6-3.655-1.633a.98.98 0 0 0-1.397-.066 1.008 1.008 0 0 0-.064 1.413A6.87 6.87 0 0 0 8.079 15C11.9 15 15 11.866 15 8s-3.099-7-6.921-7A6.866 6.866 0 0 0 3.08 3.158L1.833 2.137a.49.49 0 0 0-.695.074.504.504 0 0 0-.11.311L1 7.26a.497.497 0 0 0 .6.492l4.576-1.013a.5.5 0 0 0 .206-.877L4.625 4.423z"/></symbol><symbol viewBox="0 0 16 16" id="remove" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3a1 1 0 1 1 0-2h12a1 1 0 0 1 0 2v10a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V3zm3-2a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1H5zM4 3v10a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3H4zm2.5 2a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm3 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 16 16" id="repeat" xmlns="http://www.w3.org/2000/svg"><path d="M11.375 4.423A4.897 4.897 0 0 0 7.921 3c-2.73 0-4.944 2.239-4.944 5s2.214 5 4.944 5c1.41 0 2.723-.6 3.655-1.633a.98.98 0 0 1 1.397-.066c.403.373.432 1.005.064 1.413A6.87 6.87 0 0 1 7.921 15C4.1 15 1 11.866 1 8s3.099-7 6.921-7c1.915 0 3.706.792 4.999 2.158l1.247-1.021a.49.49 0 0 1 .695.074c.07.088.11.198.11.311L15 7.26a.497.497 0 0 1-.6.492L9.824 6.739a.5.5 0 0 1-.206-.877l1.757-1.439z"/></symbol><symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.114 6.958a4 4 0 0 0 5.283 4.775 1 1 0 1 1 .712 1.87A6 6 0 0 1 2.182 6.44l-.741-.2a.5.5 0 0 1-.12-.915l2.195-1.268a.5.5 0 0 1 .683.183l1.268 2.196a.5.5 0 0 1-.563.733l-.79-.212zm7.777 2.084a4 4 0 0 0-5.284-4.775 1 1 0 0 1-.712-1.87 6 6 0 0 1 7.927 7.162l.742.2a.5.5 0 0 1 .12.915l-2.196 1.268a.5.5 0 0 1-.683-.183l-1.267-2.196a.5.5 0 0 1 .562-.733l.79.212z"/></symbol><symbol viewBox="0 0 16 16" id="scale" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.99 9a.792.792 0 0 0-.078-.231L13 7l-.912 1.769a.791.791 0 0 0-.077.231h1.978zm-10 0a.792.792 0 0 0-.078-.231L3 7l-.912 1.769A.791.791 0 0 0 2.011 9h1.978zM2 0h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm3 14h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zM8 4a1 1 0 0 1 1 1v9H7V5a1 1 0 0 1 1-1zm-4.53-.714l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 3 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158L2.53 3.286a.53.53 0 0 1 .94 0zm10 0l2.265 4.735c.68 1.42.006 3.091-1.504 3.73A3.161 3.161 0 0 1 13 12c-1.657 0-3-1.263-3-2.821 0-.4.09-.794.264-1.158l2.266-4.735a.53.53 0 0 1 .94 0z"/></symbol><symbol viewBox="0 0 16 16" id="screen-full" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M14 14v-2a1 1 0 0 1 2 0v3a.997.997 0 0 1-1 1h-3a1 1 0 0 1 0-2h2zM2 14v-2a1 1 0 0 0-2 0v3a1 1 0 0 0 1 1h3a1 1 0 0 0 0-2H2zM15.707.293A.997.997 0 0 1 16 1v3a1 1 0 0 1-2 0V2h-2a1 1 0 0 1 0-2h3c.276 0 .526.112.707.293zM2 2v2a1 1 0 1 1-2 0V1a.997.997 0 0 1 1-1h3a1 1 0 1 1 0 2H2zm4 4h4a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="screen-normal" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 3V1a1 1 0 1 1 2 0v3a.997.997 0 0 1-1 1H1a1 1 0 1 1 0-2h2zm10 0h2a1 1 0 0 1 0 2h-3a.997.997 0 0 1-1-1V1a1 1 0 0 1 2 0v2zM3 13H1a1 1 0 0 1 0-2h3a.997.997 0 0 1 1 1v3a1 1 0 0 1-2 0v-2zm10 0v2a1 1 0 0 1-2 0v-3a.997.997 0 0 1 1-1h3a1 1 0 0 1 0 2h-2zM6.5 7h3a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5z"/></symbol><symbol viewBox="0 0 12 16" id="scroll_down" xmlns="http://www.w3.org/2000/svg"><path class="fhfirst-triangle" d="M1.048 14.155a.508.508 0 0 0-.32.105c-.091.07-.136.154-.136.25v.71c0 .095.045.178.135.249.09.07.197.105.321.105h10.043a.51.51 0 0 0 .321-.105c.09-.07.136-.154.136-.25v-.71c0-.095-.045-.178-.136-.249a.508.508 0 0 0-.32-.105"/><path class="fhsecond-triangle" d="M.687 8.027c-.09-.087-.122-.16-.093-.22.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 12.91a.458.458 0 0 1-.136.089h-.37a.626.626 0 0 1-.136-.09"/><path class="fhthird-triangle" d="M.687 1.027C.597.94.565.867.594.807c.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 5.91a.458.458 0 0 1-.136.09h-.37a.626.626 0 0 1-.136-.09"/></symbol><symbol viewBox="0 0 12 16" id="scroll_up" xmlns="http://www.w3.org/2000/svg"><path d="M1.048 1.845a.508.508 0 0 1-.32-.105c-.091-.07-.136-.154-.136-.25V.78c0-.095.045-.178.135-.249a.508.508 0 0 1 .321-.105h10.043a.51.51 0 0 1 .321.105c.09.07.136.154.136.25v.71c0 .095-.045.178-.136.249a.508.508 0 0 1-.32.105M.687 7.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 3.09A.458.458 0 0 0 6.257 3h-.37a.626.626 0 0 0-.136.09M.687 14.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 10.09a.458.458 0 0 0-.136-.09h-.37a.626.626 0 0 0-.136.09"/></symbol><symbol viewBox="0 0 16 16" id="search" xmlns="http://www.w3.org/2000/svg"><path d="M8.853 8.854a3.5 3.5 0 1 0-4.95-4.95 3.5 3.5 0 0 0 4.95 4.95zm.207 2.328a5.5 5.5 0 1 1 2.121-2.121l3.329 3.328a1.5 1.5 0 0 1-2.121 2.121L9.06 11.182z"/></symbol><symbol viewBox="0 0 16 16" id="settings" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2.415 5.803L1.317 4.084A.5.5 0 0 1 1.35 3.5l.805-.994a.5.5 0 0 1 .564-.153l1.878.704a5.975 5.975 0 0 1 1.65-.797L6.885.342A.5.5 0 0 1 7.36 0h1.28a.5.5 0 0 1 .474.342l.639 1.918a5.97 5.97 0 0 1 1.65.797l1.877-.704a.5.5 0 0 1 .565.153l.805.994a.5.5 0 0 1 .032.584l-1.097 1.719c.217.551.354 1.143.399 1.76l1.731 1.058a.5.5 0 0 1 .227.54l-.288 1.246a.5.5 0 0 1-.44.385l-2.008.19a6.026 6.026 0 0 1-1.142 1.431l.265 1.995a.5.5 0 0 1-.277.516l-1.15.56a.5.5 0 0 1-.576-.1l-1.424-1.452a6.047 6.047 0 0 1-1.804 0l-1.425 1.453a.5.5 0 0 1-.576.1l-1.15-.561a.5.5 0 0 1-.276-.516l.265-1.995a6.026 6.026 0 0 1-1.143-1.43l-2.008-.191a.5.5 0 0 1-.44-.385L.058 9.16a.5.5 0 0 1 .226-.539l1.732-1.058a5.968 5.968 0 0 1 .399-1.76zM8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="shield" xmlns="http://www.w3.org/2000/svg"><path d="M4 0h8c1.657 0 3 1.373 3 3.067v7.346c0 1.065-.54 2.053-1.426 2.611l-4 2.52a2.944 2.944 0 0 1-3.148 0l-4-2.52A3.083 3.083 0 0 1 1 10.414V3.066C1 1.373 2.343 0 4 0zm0 2.045c-.552 0-1 .457-1 1.022v7.346c0 .355.18.685.475.87l4 2.52a.981.981 0 0 0 1.05 0l4-2.52c.295-.185.475-.515.475-.87V3.067c0-.565-.448-1.022-1-1.022H4zm0 1.533c0-.282.224-.511.5-.511h4V12.1a.52.52 0 0 1-.069.258.494.494 0 0 1-.684.183l-3.5-2.098a.513.513 0 0 1-.247-.44V3.577z"/></symbol><symbol viewBox="0 0 16 16" id="slight-frown" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zm-2.163-3.275a2.499 2.499 0 0 1 4.343.03.5.5 0 0 1-.871.49 1.5 1.5 0 0 0-2.607-.018.5.5 0 1 1-.865-.502zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="slight-smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-5.163 2.254a.5.5 0 1 1 .865-.502 1.499 1.499 0 0 0 2.607-.018.5.5 0 1 1 .871.49 2.499 2.499 0 0 1-4.343.03z"/></symbol><symbol viewBox="0 0 16 16" id="smile" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM6.18 6.27a.5.5 0 0 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zm6 0a.5.5 0 1 1-.873.487.5.5 0 0 0-.872-.003.5.5 0 1 1-.87-.495 1.5 1.5 0 0 1 2.616.012zM5 9a3 3 0 0 0 6 0H5z"/></symbol><symbol viewBox="0 0 16 16" id="smiley" xmlns="http://www.w3.org/2000/svg"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12zM5 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm6 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM5 9h6a3 3 0 0 1-6 0z"/></symbol><symbol viewBox="0 0 16 16" id="snippet" xmlns="http://www.w3.org/2000/svg"><path d="M10.67 9.31a3.001 3.001 0 0 1 2.062 5.546 3 3 0 0 1-3.771-4.559 1.007 1.007 0 0 1-.095-.137l-4.5-7.794a1 1 0 0 1 1.732-1l4.5 7.794c.028.05.052.1.071.15zm-3.283.35l-.289.5c-.028.05-.06.095-.095.137a3.001 3.001 0 0 1-3.77 4.56A3 3 0 0 1 5.294 9.31c.02-.051.043-.102.071-.15l.866-1.5 1.155 2zm2.31-4l-1.156-2 1.325-2.294a1 1 0 0 1 1.732 1L9.696 5.66zm-5.465 7.464a1 1 0 1 0 1-1.732 1 1 0 0 0-1 1.732zm7.5 0a1 1 0 1 0-1-1.732 1 1 0 0 0 1 1.732z"/></symbol><symbol viewBox="0 0 16 16" id="soft-unwrap" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6.5 11v-.598a.5.5 0 0 1 .765-.424l2.557 1.598a.5.5 0 0 1 0 .848l-2.557 1.598a.5.5 0 0 1-.765-.424V13H2a1 1 0 0 1 0-2h4.5zM2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm10 4h2a1 1 0 0 1 0 2h-2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="soft-wrap" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.5 13v.598a.5.5 0 0 1-.765.424l-2.557-1.598a.5.5 0 0 1 0-.848l2.557-1.598a.5.5 0 0 1 .765.424V11H12a1 1 0 0 0 0-2H2a1 1 0 1 1 0-2h10a3 3 0 0 1 0 6h-1.5zM2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 8h3a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="spam" xmlns="http://www.w3.org/2000/svg"><path d="M8.75.433l5.428 3.134a1.5 1.5 0 0 1 .75 1.299v6.268a1.5 1.5 0 0 1-.75 1.299L8.75 15.567a1.5 1.5 0 0 1-1.5 0l-5.428-3.134a1.5 1.5 0 0 1-.75-1.299V4.866a1.5 1.5 0 0 1 .75-1.299L7.25.433a1.5 1.5 0 0 1 1.5 0zM3.072 5.155v5.69L8 13.691l4.928-2.846v-5.69L8 2.309 3.072 5.155zM8 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 14 14" id="spinner" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle cx="7" cy="7" r="6" stroke="#000" stroke-opacity=".1" stroke-width="2"/><path fill="#000" fill-opacity=".1" fill-rule="nonzero" d="M7 0a7 7 0 0 1 7 7h-2a5 5 0 0 0-5-5V0z"/></g></symbol><symbol viewBox="0 0 16 16" id="staged" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3h4a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm9 6a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM2 7h4a1 1 0 1 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="star" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.609 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 16 16" id="star-o" xmlns="http://www.w3.org/2000/svg"><path d="M10.975 10.99a3 3 0 0 1 .655-2.083l1.54-1.916-2.219-.576a3 3 0 0 1-1.825-1.37L8 3.15 6.874 5.044a3 3 0 0 1-1.825 1.371l-2.218.576 1.54 1.916a3 3 0 0 1 .654 2.083l-.165 2.4 1.965-.836a3 3 0 0 1 2.348 0l1.965.836-.164-2.399zM7.61 14.394l-3.465 1.473a1 1 0 0 1-1.39-.989l.276-4.024a1 1 0 0 0-.219-.694L.303 7.037A1 1 0 0 1 .83 5.443l3.715-.964a1 1 0 0 0 .609-.457L7.14.682a1 1 0 0 1 1.72 0l1.985 3.34a1 1 0 0 0 .609.457l3.715.964a1 1 0 0 1 .528 1.594L13.19 10.16a1 1 0 0 0-.219.694l.275 4.024a1 1 0 0 1-1.389.989l-3.465-1.473a1 1 0 0 0-.782 0z"/></symbol><symbol viewBox="0 0 14 14" id="status_canceled" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M5.2 3.8l4.9 4.9c.2.2.2.5 0 .7l-.7.7c-.2.2-.5.2-.7 0L3.8 5.2c-.2-.2-.2-.5 0-.7l.7-.7c.2-.2.5-.2.7 0"/></g></symbol><symbol viewBox="0 0 22 22" id="status_canceled_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M8.171 5.971l7.7 7.7a.76.76 0 0 1 0 1.1l-1.1 1.1a.76.76 0 0 1-1.1 0l-7.7-7.7a.76.76 0 0 1 0-1.1l1.1-1.1a.76.76 0 0 1 1.1 0"/></symbol><symbol viewBox="0 0 16 16" id="status_closed" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.83a1 1 0 0 1 1.414 1.416l-3.535 3.535a1 1 0 0 1-1.415.001l-2.12-2.12a1 1 0 1 1 1.413-1.415zM8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm0-2A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"/></symbol><symbol viewBox="0 0 14 14" id="status_created" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><circle cx="7" cy="7" r="3.25"/></g></symbol><symbol viewBox="0 0 22 22" id="status_created_borderless" xmlns="http://www.w3.org/2000/svg"><circle cx="11" cy="11" r="5.107"/></symbol><symbol viewBox="0 0 14 14" id="status_failed" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 5.969L5.599 4.568a.29.29 0 0 0-.413.004l-.614.614a.294.294 0 0 0-.004.413L5.968 7l-1.4 1.401a.29.29 0 0 0 .004.413l.614.614c.113.114.3.117.413.004L7 8.032l1.401 1.4a.29.29 0 0 0 .413-.004l.614-.614a.294.294 0 0 0 .004-.413L8.032 7l1.4-1.401a.29.29 0 0 0-.004-.413l-.614-.614a.294.294 0 0 0-.413-.004L7 5.968z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_failed_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 9.38L8.798 7.178a.455.455 0 0 0-.65.006l-.964.965a.462.462 0 0 0-.006.65L9.38 11l-2.202 2.202a.455.455 0 0 0 .006.65l.965.964a.462.462 0 0 0 .65.006L11 12.62l2.202 2.202a.455.455 0 0 0 .65-.006l.964-.965a.462.462 0 0 0 .006-.65L12.62 11l2.202-2.202a.455.455 0 0 0-.006-.65l-.965-.964a.462.462 0 0 0-.65-.006L11 9.38z"/></symbol><symbol viewBox="0 0 14 14" id="status_manual" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M10.5 7.63V6.37l-.787-.13c-.044-.175-.132-.349-.263-.61l.481-.652-.918-.913-.657.478a2.346 2.346 0 0 0-.612-.26L7.656 3.5H6.388l-.132.783c-.219.043-.394.13-.612.26l-.657-.478-.918.913.437.652c-.131.218-.175.392-.262.61l-.744.086v1.261l.787.13c.044.218.132.392.263.61l-.438.651.92.913.655-.434c.175.086.394.173.613.26l.131.783h1.313l.131-.783c.219-.043.394-.13.613-.26l.656.478.918-.913-.48-.652c.13-.218.218-.435.262-.61l.656-.13zM7 8.283a1.285 1.285 0 0 1-1.313-1.305c0-.739.57-1.304 1.313-1.304.744 0 1.313.565 1.313 1.304 0 .74-.57 1.305-1.313 1.305z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_manual_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M16.5 11.99v-1.98l-1.238-.206c-.068-.273-.206-.546-.412-.956l.756-1.025-1.444-1.435-1.03.752a3.686 3.686 0 0 0-.963-.41L12.03 5.5h-1.994l-.206 1.23c-.343.068-.618.205-.962.41l-1.031-.752-1.444 1.435.687 1.025c-.206.341-.275.615-.412.956L5.5 9.941v1.981l1.237.205c.07.342.207.615.413.957l-.688 1.025 1.444 1.434 1.032-.683c.274.137.618.274.962.41l.206 1.23h2.063l.206-1.23c.344-.068.619-.205.963-.41l1.03.752 1.444-1.435-.756-1.025c.207-.341.344-.683.413-.956l1.031-.205zM11 13.017c-1.169 0-2.063-.889-2.063-2.05 0-1.162.894-2.05 2.063-2.05s2.063.888 2.063 2.05c0 1.161-.894 2.05-2.063 2.05z"/></symbol><symbol viewBox="0 0 14 14" id="status_notfound" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M8.16 7.184c.519-.37.904-.857 1.07-1.477.384-1.427-.619-2.897-2.246-2.897-.732 0-1.327.26-1.766.692a2.163 2.163 0 0 0-.509.743.75.75 0 0 0 1.4.54.78.78 0 0 1 .16-.213c.168-.165.39-.262.715-.262.597 0 .936.496.798 1.007-.067.249-.235.462-.492.644-.231.165-.47.264-.601.3a.75.75 0 0 0-.556.724v1.421a.75.75 0 0 0 1.5 0v-.909a3.74 3.74 0 0 0 .526-.313z"/><ellipse cx="6.889" cy="10.634" rx="1" ry="1"/></symbol><symbol viewBox="0 0 22 22" id="status_notfound_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M12.822 11.29c.816-.581 1.421-1.348 1.683-2.322.603-2.243-.973-4.553-3.53-4.553-1.15 0-2.085.41-2.775 1.089-.42.413-.672.835-.8 1.167a1.179 1.179 0 0 0 2.2.847c.016-.043.1-.184.252-.334.264-.259.613-.412 1.123-.412.938 0 1.47.78 1.254 1.584-.105.39-.37.726-.773 1.012a3.25 3.25 0 0 1-.945.47 1.179 1.179 0 0 0-.874 1.138v2.234a1.179 1.179 0 1 0 2.358 0v-1.43a5.9 5.9 0 0 0 .827-.492z"/><ellipse cx="10.825" cy="16.711" rx="1.275" ry="1.322"/></symbol><symbol viewBox="0 0 14 14" id="status_open" xmlns="http://www.w3.org/2000/svg"><path d="M0 7c0-3.866 3.142-7 7-7 3.866 0 7 3.142 7 7 0 3.866-3.142 7-7 7-3.866 0-7-3.142-7-7z"/><path d="M1 7c0 3.309 2.69 6 6 6 3.309 0 6-2.69 6-6 0-3.309-2.69-6-6-6-3.309 0-6 2.69-6 6z" fill="#FFF"/><path d="M7 9.219a2.218 2.218 0 1 0 0-4.436A2.218 2.218 0 0 0 7 9.22zm0 1.12a3.338 3.338 0 1 1 0-6.676 3.338 3.338 0 0 1 0 6.676z"/></symbol><symbol viewBox="0 0 14 14" id="status_pending" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M4.7 5.3c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H5c-.2 0-.3-.1-.3-.3V5.3m3 0c0-.2.1-.3.3-.3h.9c.2 0 .3.1.3.3v3.4c0 .2-.1.3-.3.3H8c-.2 0-.3-.1-.3-.3V5.3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_pending_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M7.386 8.329c0-.315.157-.472.471-.472h1.414c.315 0 .472.157.472.472v5.342c0 .315-.157.472-.472.472H7.857c-.314 0-.471-.157-.471-.472V8.33m4.714 0c0-.315.157-.472.471-.472h1.415c.314 0 .471.157.471.472v5.342c0 .315-.157.472-.471.472H12.57c-.314 0-.471-.157-.471-.472V8.33"/></symbol><symbol viewBox="0 0 14 14" id="status_running" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M7 3c2.2 0 4 1.8 4 4s-1.8 4-4 4c-1.3 0-2.5-.7-3.3-1.7L7 7V3"/></g></symbol><symbol viewBox="0 0 22 22" id="status_running_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M11 4.714c3.457 0 6.286 2.829 6.286 6.286 0 3.457-2.829 6.286-6.286 6.286-2.043 0-3.929-1.1-5.186-2.672L11 11V4.714"/></symbol><symbol viewBox="0 0 14 14" id="status_skipped" xmlns="http://www.w3.org/2000/svg"><path d="M7 14A7 7 0 1 1 7 0a7 7 0 0 1 0 14z"/><path d="M7 13A6 6 0 1 0 7 1a6 6 0 0 0 0 12z" fill="#FFF"/><path d="M6.415 7.04L4.579 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L5.341 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L6.415 7.04zm2.54 0L7.119 5.203a.295.295 0 0 1 .004-.416l.349-.349a.29.29 0 0 1 .416-.004l2.214 2.214a.289.289 0 0 1 .019.021l.132.133c.11.11.108.291 0 .398L7.881 9.573a.282.282 0 0 1-.398 0l-.331-.331a.285.285 0 0 1 0-.399L8.955 7.04z"/></symbol><symbol viewBox="0 0 22 22" id="status_skipped_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M14.072 11.063l-2.82 2.82a.46.46 0 0 0-.001.652l.495.495a.457.457 0 0 0 .653-.001l3.7-3.7a.46.46 0 0 0 .001-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.479-3.479a.464.464 0 0 0-.654.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/><path d="M10.08 11.063l-2.819 2.82a.46.46 0 0 0-.002.652l.496.495a.457.457 0 0 0 .652-.001l3.7-3.7a.46.46 0 0 0 .002-.653l-.196-.196a.453.453 0 0 0-.03-.033l-3.48-3.479a.464.464 0 0 0-.653.007l-.548.548a.463.463 0 0 0-.007.654l2.886 2.886z"/></symbol><symbol viewBox="0 0 14 14" id="status_success" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6.278 7.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z"/></g></symbol><symbol viewBox="0 0 22 22" id="status_success_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.866 12.095l-1.95-1.95a.462.462 0 0 0-.647.01l-.964.964a.46.46 0 0 0-.01.646l3.013 3.014a.787.787 0 0 0 1.106.008l.425-.425 4.854-4.853a.462.462 0 0 0 .002-.659l-.964-.964a.468.468 0 0 0-.658.002l-4.207 4.207z"/></symbol><symbol viewBox="0 0 14 14" id="status_success_solid" xmlns="http://www.w3.org/2000/svg"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7zm6.278.697L5.045 6.464a.296.296 0 0 0-.42-.002l-.613.614a.298.298 0 0 0 .002.42l1.91 1.909a.5.5 0 0 0 .703.005l.265-.265L9.997 6.04a.291.291 0 0 0-.009-.408l-.614-.614a.29.29 0 0 0-.408-.009L6.278 7.697z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 14 14" id="status_warning" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M6 3.5c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v4c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-4m0 6c0-.3.2-.5.5-.5h1c.3 0 .5.2.5.5v1c0 .3-.2.5-.5.5h-1c-.3 0-.5-.2-.5-.5v-1"/></g></symbol><symbol viewBox="0 0 22 22" id="status_warning_borderless" xmlns="http://www.w3.org/2000/svg"><path d="M9.429 5.5c0-.471.314-.786.785-.786h1.572c.471 0 .785.315.785.786v6.286c0 .471-.314.785-.785.785h-1.572c-.471 0-.785-.314-.785-.785V5.5m0 9.429c0-.472.314-.786.785-.786h1.572c.471 0 .785.314.785.786V16.5c0 .471-.314.786-.785.786h-1.572c-.471 0-.785-.315-.785-.786v-1.571"/></symbol><symbol viewBox="0 0 16 16" id="stop" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 0h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2z"/></symbol><symbol viewBox="0 0 16 16" id="task-done" xmlns="http://www.w3.org/2000/svg"><path d="M7.536 8.657l2.828-2.829a1 1 0 0 1 1.414 1.415l-3.535 3.535a.997.997 0 0 1-1.415 0l-2.12-2.121A1 1 0 0 1 6.12 7.243l1.415 1.414zM3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3z"/></symbol><symbol viewBox="0 0 16 16" id="template" xmlns="http://www.w3.org/2000/svg"><path d="M3 0h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm.8 2h2.4a.8.8 0 0 1 .8.8v1.4a.8.8 0 0 1-.8.8H3.8a.8.8 0 0 1-.8-.8V4.8a.8.8 0 0 1 .8-.8zm4.7 0h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm0 2h4a.5.5 0 1 1 0 1h-4a.5.5 0 0 1 0-1zm-5 3h9a.5.5 0 1 1 0 1h-9a.5.5 0 0 1 0-1zm0 2h9a.5.5 0 1 1 0 1h-9a.5.5 0 1 1 0-1z"/></symbol><symbol viewBox="0 0 16 16" id="terminal" xmlns="http://www.w3.org/2000/svg"><path d="M7 8a.997.997 0 0 1-.293.707l-1.414 1.414a1 1 0 1 1-1.414-1.414L4.586 8l-.707-.707a1 1 0 1 1 1.414-1.414l1.414 1.414A.997.997 0 0 1 7 8zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H4zm5 7h2a1 1 0 0 1 0 2H9a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-down" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 11h5.282a2 2 0 0 0 1.963-2.38l-.563-2.905a3 3 0 0 0-.243-.732l-1.103-2.286A3 3 0 0 0 10.964 1H7a3 3 0 0 0-3 3v6.3a2 2 0 0 0 .436 1.247l3.11 3.9a.632.632 0 0 0 .941.053l.137-.137a1 1 0 0 0 .28-.87L8.329 11zM1 10h2V3H1a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1z"/></symbol><symbol viewBox="0 0 16 16" id="thumb-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.33 5h5.282a2 2 0 0 1 1.963 2.38l-.563 2.905a3 3 0 0 1-.243.732l-1.103 2.286A3 3 0 0 1 10.964 15H7a3 3 0 0 1-3-3V5.7a2 2 0 0 1 .436-1.247l3.11-3.9A.632.632 0 0 1 8.487.5l.137.137a1 1 0 0 1 .28.87L8.329 5zM1 6h2v7H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></symbol><symbol viewBox="0 0 16 16" id="thumbtack" xmlns="http://www.w3.org/2000/svg"><path d="M7.125 9h-2.19a.5.5 0 0 1-.417-.777L6 6V2L5.362.724A.5.5 0 0 1 5.809 0h4.382a.5.5 0 0 1 .447.724L10 2v4l1.482 2.223a.5.5 0 0 1-.416.777H8.875L8 16l-.875-7z" fill-rule="evenodd"/></symbol><symbol viewBox="0 0 16 16" id="time-out" xmlns="http://www.w3.org/2000/svg"><path d="M12 13.36l-1.36 1.358a.961.961 0 1 1-1.358-1.359L10.64 12l-1.36-1.36a.961.961 0 0 1 1.36-1.358L12 10.64l1.36-1.36a.961.961 0 1 1 1.358 1.36L13.36 12l1.36 1.36a.961.961 0 1 1-1.36 1.358L12 13.36zM8 9H5a1 1 0 1 1 0-2h2V5a1 1 0 1 1 2 0v3a1 1 0 0 1-1 1zm0 6a7 7 0 1 1 7-7 4.976 4.976 0 0 0-2.084-.916A5.002 5.002 0 0 0 3 8a5.002 5.002 0 0 0 4.084 4.916c.143.772.462 1.48.916 2.084z"/></symbol><symbol viewBox="0 0 16 16" id="timer" xmlns="http://www.w3.org/2000/svg"><path d="M12.022 3.27l.77-.77a1 1 0 0 1 1.415 1.414l-.728.729a7 7 0 1 1-1.456-1.372zM8 14A5 5 0 1 0 8 4a5 5 0 0 0 0 10zm0-9a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zM6 0h4a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-add" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 4V2a1 1 0 0 1 2 0v2h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0V6H8a1 1 0 1 1 0-2h2zm2 7a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="todo-done" xmlns="http://www.w3.org/2000/svg"><path d="M8.243 7.485l4.95-4.95a1 1 0 1 1 1.414 1.415L8.95 9.607a.997.997 0 0 1-1.414 0L4.707 6.778a1 1 0 0 1 1.414-1.414l2.122 2.121zM12 11a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></symbol><symbol viewBox="0 0 16 16" id="token" xmlns="http://www.w3.org/2000/svg"><path d="M3 2h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H3zm1 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm4 0a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="unapproval" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11.95 8.536l1.06-1.061a1 1 0 0 1 1.415 1.414l-1.061 1.06 1.06 1.061a1 1 0 0 1-1.414 1.415l-1.06-1.061-1.06 1.06a1 1 0 1 1-1.415-1.414l1.06-1.06-1.06-1.06a1 1 0 0 1 1.414-1.415l1.06 1.06zm-3.768-.33c.006.503.201 1.006.586 1.39l.353.354-.353.353a2 2 0 1 0 2.828 2.829l.354-.354.047.048C11.964 14.363 11.527 15 6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8c.834 0 1.557.074 2.182.205zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol viewBox="0 0 16 16" id="unassignee" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M11 5h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="unlink" xmlns="http://www.w3.org/2000/svg"><path d="M11.295 8.845l-.659-1.664a1.78 1.78 0 0 0 .04-.04l1.415-1.414c.586-.586.654-1.468.152-1.97s-1.384-.434-1.97.152L8.859 5.323a1.781 1.781 0 0 0-.04.04l-1.664-.658c.141-.208.305-.408.491-.594l1.415-1.414c1.366-1.367 3.424-1.525 4.596-.354 1.171 1.172 1.013 3.23-.354 4.596L11.89 8.354c-.186.186-.386.35-.594.491zm-2.45 2.45a4.075 4.075 0 0 1-.491.594l-1.415 1.414c-1.366 1.367-3.424 1.525-4.596.354-1.171-1.172-1.013-3.23.354-4.596L4.11 7.646c.186-.186.386-.35.594-.491l.659 1.664a1.781 1.781 0 0 0-.04.04l-1.415 1.414c-.586.586-.654 1.468-.152 1.97s1.384.434 1.97-.152l1.414-1.414a1.78 1.78 0 0 0 .04-.04l1.664.658zm3.812-2.088h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-.05a.5.5 0 0 1 .5-.5zm-.384 2.116l1.415 1.414a.5.5 0 0 1 0 .708l-.037.036a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 0-.707l.036-.037a.5.5 0 0 1 .707 0zm-2.823 1.09a.5.5 0 0 1 .5-.5h.052a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5H9.95a.5.5 0 0 1-.5-.5v-2zm-2.748-9.16a.5.5 0 0 1-.5.5h-.05a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h.05a.5.5 0 0 1 .5.5v2zm-2.116.383a.5.5 0 0 1 0 .707l-.036.036a.5.5 0 0 1-.707 0L2.428 2.965a.5.5 0 0 1 0-.707l.037-.036a.5.5 0 0 1 .707 0l1.414 1.414zm-1.09 2.823h-2a.5.5 0 0 1-.5-.5v-.051a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v.05a.5.5 0 0 1-.5.5z"/></symbol><symbol viewBox="0 0 16 16" id="unstaged" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M2 3h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 1 1 0-2zm0 4h12a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/></symbol><symbol viewBox="0 0 16 16" id="user" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 8c-6.888 0-6.976-.78-6.976-2.52S2.144 8 8 8s6.976 2.692 6.976 4.48c0 1.788-.088 2.52-6.976 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="users" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.521 8.01C15.103 8.19 16 10.755 16 12.48c0 1.533-.056 2.29-3.808 2.475.609-.54.808-1.331.808-2.475 0-1.911-.804-3.503-2.479-4.47zm-1.67-1.228A3.987 3.987 0 0 0 9.976 4a3.987 3.987 0 0 0-1.125-2.782 3 3 0 1 1 0 5.563zM5.976 7a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM6 15c-5.924 0-6-.78-6-2.52S.964 8 6 8s6 2.692 6 4.48c0 1.788-.076 2.52-6 2.52z"/></symbol><symbol viewBox="0 0 16 16" id="volume-up" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M1 5h1v6H1a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1zm2 0l4.445-2.964A1 1 0 0 1 9 2.87v10.26a1 1 0 0 1-1.555.833L3 11V5zm10.283 7.89a.5.5 0 0 1-.66-.752A5.485 5.485 0 0 0 14.5 8c0-1.601-.687-3.09-1.865-4.128a.5.5 0 0 1 .661-.75A6.484 6.484 0 0 1 15.5 8a6.485 6.485 0 0 1-2.217 4.89zm-2.002-2.236a.5.5 0 1 1-.652-.758c.55-.472.871-1.157.871-1.896 0-.732-.315-1.411-.856-1.883a.5.5 0 0 1 .658-.753A3.492 3.492 0 0 1 12.5 8c0 1.033-.45 1.994-1.219 2.654z"/></symbol><symbol viewBox="0 0 16 16" id="warning" xmlns="http://www.w3.org/2000/svg"><path d="M15.572 10.506c.867 1.42.375 3.247-1.098 4.082a3.184 3.184 0 0 1-1.57.412h-9.81C1.387 15 0 13.665 0 12.018a2.9 2.9 0 0 1 .427-1.512L5.332 2.47C6.2 1.05 8.096.577 9.57 1.412c.453.257.831.622 1.098 1.059l4.905 8.035zM8.89 3.479a1.014 1.014 0 0 0-.366-.353 1.053 1.053 0 0 0-1.412.353l-4.905 8.035a.967.967 0 0 0-.143.504c0 .549.462.994 1.032.994h9.81c.184 0 .364-.048.523-.137a.974.974 0 0 0 .366-1.361L8.889 3.479zM8 5a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1zm0 7a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/></symbol><symbol viewBox="0 0 16 16" id="work" xmlns="http://www.w3.org/2000/svg"><path d="M12 3h1a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h1V2a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v1zM6 2v1h4V2H6zM3 5a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H3zm1.5 1a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5zm7 0a.5.5 0 0 1 .5.5v6a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .5-.5z"/></symbol></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/canceled-job_empty.svg b/app/assets/images/illustrations/canceled-job_empty.svg
new file mode 100644
index 00000000000..e4a7c244f56
--- /dev/null
+++ b/app/assets/images/illustrations/canceled-job_empty.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="430" height="172" viewBox="0 0 430 172"><g fill="none" fill-rule="evenodd"><path fill="#EEE" fill-rule="nonzero" d="M187 121a2 2 0 1 1 0-4c2.542 0 5.042-.305 7.463-.904a2 2 0 1 1 .96 3.884A35.075 35.075 0 0 1 187 121zm18.21-5.105a2 2 0 1 1-2.083-3.414 31.143 31.143 0 0 0 5.896-4.664 2 2 0 1 1 2.842 2.815 35.143 35.143 0 0 1-6.654 5.263zm12.895-13.835a2 2 0 0 1-3.552-1.838 30.77 30.77 0 0 0 2.612-7.042 2 2 0 1 1 3.892.922 34.77 34.77 0 0 1-2.952 7.958zm3.816-18.433a2 2 0 1 1-3.991.268 30.873 30.873 0 0 0-1.407-7.38 2 2 0 0 1 3.808-1.223 34.873 34.873 0 0 1 1.59 8.335zm-6.346-17.842a2 2 0 0 1-3.264 2.312 31.188 31.188 0 0 0-5.054-5.564 2 2 0 0 1 2.615-3.027 35.188 35.188 0 0 1 5.703 6.279zm-14.68-11.918a2 2 0 0 1-1.59 3.67 30.758 30.758 0 0 0-7.206-2.12 2 2 0 1 1 .653-3.946 34.758 34.758 0 0 1 8.143 2.396zm-18.632-2.549a2 2 0 0 1 .537 3.964c-2.505.339-4.94.98-7.266 1.907a2 2 0 1 1-1.48-3.716 34.774 34.774 0 0 1 8.209-2.155zm-17.356 7.535a2 2 0 0 1 2.527 3.1 31.196 31.196 0 0 0-5.213 5.416 2 2 0 0 1-3.196-2.406 35.196 35.196 0 0 1 5.882-6.11zm-10.918 15.49a2 2 0 0 1 3.772 1.331 30.82 30.82 0 0 0-1.619 7.337 2 2 0 1 1-3.982-.38 34.82 34.82 0 0 1 1.829-8.289zm-1.27 18.744a2 2 0 1 1 3.917-.806 30.757 30.757 0 0 0 2.4 7.118 2 2 0 1 1-3.605 1.73 34.757 34.757 0 0 1-2.713-8.042zm8.675 16.774a2 2 0 0 1 2.926-2.728 31.167 31.167 0 0 0 5.751 4.841 2 2 0 1 1-2.187 3.349 35.167 35.167 0 0 1-6.49-5.462zm16.245 9.873a2 2 0 1 1 1.067-3.855 30.979 30.979 0 0 0 7.434 1.11 2 2 0 1 1-.11 3.998 34.979 34.979 0 0 1-8.391-1.253z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M187 104c-9.941 0-18-8.059-18-18s8.059-18 18-18 18 8.059 18 18-8.059 18-18 18zm0-4c7.732 0 14-6.268 14-14s-6.268-14-14-14-14 6.268-14 14 6.268 14 14 14z"/><path fill="#6B4FBB" d="M189 84h5a2 2 0 1 1 0 4h-7a2 2 0 0 1-2-2v-8a2 2 0 1 1 4 0v6z"/><g transform="translate(261 16)"><path fill="#F9F9F9" d="M115.575 132.895C114.333 137.006 110.516 140 106 140H10c-5.523 0-10-4.477-10-10V15a10 10 0 0 1 5.884-9.116A9.964 9.964 0 0 0 5 10v114c0 5.523 4.477 10 10 10h96a9.957 9.957 0 0 0 4.575-1.105z"/><rect width="116" height="134" x="5" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M15 2a8 8 0 0 0-8 8v114a8 8 0 0 0 8 8h96a8 8 0 0 0 8-8V10a8 8 0 0 0-8-8H15zm0-4h96c6.627 0 12 5.373 12 12v114c0 6.627-5.373 12-12 12H15c-6.627 0-12-5.373-12-12V10C3 3.373 8.373-2 15-2z"/><g transform="translate(23 23)"><rect width="16" height="4" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="32" y="12" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="44" fill="#EEE" rx="2"/><rect width="16" height="4" x="12" y="24" fill="#E1DBF1" rx="2"/><rect width="16" height="4" x="64" y="36" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="20" fill="#FEE1D3" rx="2"/><rect width="8" height="4" x="32" y="36" fill="#FC6D26" rx="2"/><rect width="8" height="4" x="52" y="12" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="64" fill="#FEF0E8" rx="2"/><rect width="12" height="4" x="16" y="48" fill="#E1DBF1" rx="2"/><rect width="8" height="4" x="44" y="36" fill="#FC6D26" rx="2"/><rect width="4" height="4" x="56" y="36" fill="#E1DBF1" rx="2"/><rect width="4" height="4" x="64" y="60" fill="#E1DBF1" rx="2"/><rect width="4" height="4" x="72" y="60" fill="#FC6D26" rx="2"/><rect width="8" height="4" x="32" fill="#FC6D26" rx="2"/><rect width="28" height="4" y="36" fill="#EEE" rx="2"/><rect width="28" height="4" x="44" y="48" fill="#EEE" rx="2"/><rect width="28" height="4" x="32" y="60" fill="#EFEDF8" rx="2"/><rect width="28" height="4" y="12" fill="#6B4FBB" rx="2"/><rect width="28" height="4" x="32" y="24" fill="#C3B8E3" rx="2"/><rect width="8" height="4" y="24" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="32" y="48" fill="#6B4FBB" rx="2"/><rect width="12" height="4" y="48" fill="#FC6D26" rx="2"/><rect width="12" height="4" y="60" fill="#FEF0E8" rx="2"/><rect width="12" height="4" x="16" y="60" fill="#FEF0E8" rx="2"/></g><g transform="translate(23 95)"><rect width="16" height="4" fill="#EFEDF8" rx="2"/><rect width="16" height="4" x="18" y="12" fill="#FC6D26" rx="2"/><rect width="16" height="4" x="44" fill="#6B4FBB" rx="2"/><rect width="8" height="4" x="20" fill="#FEE1D3" rx="2"/><rect width="8" height="4" x="38" y="12" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="64" fill="#FEF0E8" rx="2"/><rect width="8" height="4" x="32" fill="#FC6D26" rx="2"/><rect width="14" height="4" y="12" fill="#EEE" rx="2"/></g></g><path fill="#FFF" d="M80 117c17.12 0 31-13.88 31-31 0-17.12-13.88-31-31-31-17.12 0-31 13.88-31 31 0 17.12 13.88 31 31 31z"/><path fill="#EEE" fill-rule="nonzero" d="M80 121c-19.33 0-35-15.67-35-35s15.67-35 35-35 35 15.67 35 35-15.67 35-35 35zm0-4c17.12 0 31-13.88 31-31 0-17.12-13.88-31-31-31-17.12 0-31 13.88-31 31 0 17.12 13.88 31 31 31z"/><g transform="translate(61 67)"><path fill="#CCC" fill-rule="nonzero" d="M19 38C8.507 38 0 29.493 0 19S8.507 0 19 0s19 8.507 19 19-8.507 19-19 19zm0-4c8.284 0 15-6.716 15-15 0-8.284-6.716-15-15-15-8.284 0-15 6.716-15 15 0 8.284 6.716 15 15 15z"/><rect width="18" height="4" x="10" y="17" fill="#2E2E2E" rx="2" transform="rotate(45 19 19)"/></g><path fill="#E5E5E5" fill-rule="nonzero" d="M122 88c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.994 1.994 0 0 1 122 88zm14 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.994 1.994 0 0 1 136 88zm93 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.994 1.994 0 0 1 229 88zm14 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.994 1.994 0 0 1 243 88z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/epics.svg b/app/assets/images/illustrations/epics.svg
index 1a37e6bba5f..be6c3fb76a5 100644
--- a/app/assets/images/illustrations/epics.svg
+++ b/app/assets/images/illustrations/epics.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="430" height="300" viewBox="0 0 430 300"><g fill="none" fill-rule="evenodd"><g transform="translate(75 53)"><rect width="284" height="208" y="5" fill="#F9F9F9" rx="10"/><rect width="284" height="208" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M10 4a6 6 0 0 0-6 6v188a6 6 0 0 0 6 6h264a6 6 0 0 0 6-6V10a6 6 0 0 0-6-6H10zm0-4h264c5.523 0 10 4.477 10 10v188c0 5.523-4.477 10-10 10H10c-5.523 0-10-4.477-10-10V10C0 4.477 4.477 0 10 0z"/><path fill="#EEE" fill-rule="nonzero" d="M25.168 153.995c3.837-.215 7.173.028 10.119.691a3 3 0 1 0 1.318-5.853c-3.509-.79-7.4-1.074-11.773-.828a3 3 0 1 0 .336 5.99zm19.043 4.66c2.401 1.704 4.388 3.61 7.569 7.083a3 3 0 0 0 4.424-4.054c-3.448-3.763-5.686-5.911-8.522-7.923a3 3 0 1 0-3.471 4.894zm15.575 15.173c3.181 2.675 6.52 4.665 10.397 6.039a3 3 0 0 0 2.004-5.655c-3.162-1.121-5.884-2.743-8.54-4.976a3 3 0 1 0-3.861 4.592zm22.133 8.148c1.02.037 2.067.045 3.143.023a72.664 72.664 0 0 0 8.346-.638 3 3 0 1 0-.812-5.945c-2.442.334-4.996.53-7.658.585a48.55 48.55 0 0 1-2.796-.021 3 3 0 0 0-.223 5.996zm22.778-3.286c3.9-1.37 7.427-3.15 10.54-5.305a3 3 0 0 0-3.415-4.933c-2.665 1.845-5.712 3.382-9.114 4.578a3 3 0 0 0 1.989 5.66zm19.156-13.62a33.752 33.752 0 0 0 5.276-10.817 3 3 0 1 0-5.773-1.633 27.753 27.753 0 0 1-4.341 8.9 3 3 0 1 0 4.838 3.55zm6.577-22.657c-.187-3.817-.926-7.71-2.204-11.596a3 3 0 0 0-5.7 1.874c1.113 3.384 1.75 6.745 1.91 10.016a3 3 0 1 0 5.994-.294zm-7.097-22.26c-1.897-3.2-4.152-6.325-6.748-9.344a3 3 0 0 0-4.55 3.913c2.372 2.756 4.421 5.597 6.136 8.49a3 3 0 0 0 5.162-3.06zm-11.546-17.793c-.938-3.025-1.402-6.42-1.365-9.976a3 3 0 0 0-6-.063c-.043 4.163.506 8.177 1.634 11.816a3 3 0 1 0 5.731-1.777zm.053-20.107c.905-3.341 2.22-6.538 3.904-9.448a3 3 0 0 0-5.194-3.004c-1.948 3.368-3.463 7.048-4.501 10.884a3 3 0 1 0 5.791 1.568zm10.134-17.305c2.475-2.28 5.265-4.09 8.335-5.374a3 3 0 1 0-2.314-5.536c-3.725 1.558-7.105 3.75-10.086 6.497a3 3 0 1 0 4.065 4.413zm18.177-7.586c3.202-.18 6.599.092 10.18.843a3 3 0 0 0 1.23-5.872c-4.086-.857-8.009-1.172-11.747-.962a3 3 0 1 0 .337 5.99zm20.047 3.95c3.068 1.268 6.232 2.842 9.487 4.728a3 3 0 0 0 3.009-5.191c-3.48-2.017-6.883-3.71-10.204-5.083a3 3 0 1 0-2.292 5.545zm19.578 9.955c3.711 1.586 7.376 2.77 10.997 3.565a3 3 0 0 0 1.286-5.86c-3.248-.713-6.555-1.782-9.925-3.222a3 3 0 1 0-2.358 5.517zm22.591 4.789c3.94-.04 7.808-.553 11.61-1.513a3 3 0 1 0-1.468-5.817 43.358 43.358 0 0 1-10.203 1.33 3 3 0 0 0 .061 6zm22.52-5.558c3.335-1.637 6.607-3.613 9.845-5.916a3 3 0 1 0-3.477-4.89c-2.984 2.122-5.98 3.931-9.011 5.42a3 3 0 1 0 2.643 5.386zm18.678-13.054a3 3 0 0 1-4.02-4.454 130.547 130.547 0 0 0 5.31-5.088 3 3 0 1 1 4.265 4.22 136.507 136.507 0 0 1-5.555 5.322zm-48.722 25.641a3 3 0 1 1 4.314-4.17c3.056 3.16 5.075 6.744 6.172 10.754a3 3 0 0 1-5.787 1.584c-.834-3.047-2.35-5.739-4.699-8.168zm5.347 18.049a3 3 0 1 1 5.978.52c-.282 3.232-.805 6.273-1.832 11.206a3 3 0 0 1-5.874-1.222c.981-4.717 1.473-7.572 1.728-10.504zm-3.777 21.555a3 3 0 0 1 5.953.747c-.5 3.988-.397 7.09.399 9.67a3 3 0 1 1-5.733 1.769c-1.087-3.52-1.217-7.426-.62-12.186zm7.393 22.444a3 3 0 0 1 4.461-4.013c2.703 3.005 5.224 5.296 7.594 6.947a3 3 0 0 1-3.429 4.924c-2.775-1.932-5.632-4.53-8.626-7.858zm20.352 12.28a3 3 0 1 1 .334-5.99c2.77.154 5.453-.554 9.224-2.254a3 3 0 0 1 2.466 5.47c-4.57 2.06-8.103 2.993-12.024 2.775zm21.784-7.058a3 3 0 0 1-1.815-5.719c4.227-1.342 8.24-1.61 12.496-.572a3 3 0 0 1-1.421 5.83c-3.116-.76-6.025-.566-9.26.46zM106.53 56.038a3 3 0 1 1-3.45 4.909c-1.074-.755-6.723-6.044-8.083-7.204a68.019 68.019 0 0 0-.332-.281 3 3 0 1 1 3.865-4.59l.362.306c1.643 1.402 6.971 6.391 7.638 6.86zM88.536 42.422a3 3 0 0 1-2.285 5.548c-3.14-1.293-5.78-1.34-8.105-.05a3 3 0 0 1-2.91-5.247c4.087-2.266 8.597-2.187 13.3-.25zM66.698 48.73a3 3 0 0 1 2.029 5.647c-4.432 1.592-8.786.835-13.166-1.88a3 3 0 1 1 3.16-5.1c2.93 1.816 5.425 2.25 7.977 1.333zm-15.636-8.038a3 3 0 0 1-4.352 4.13c-.911-.96-1.85-1.98-3.061-3.32-.295-.325-2.437-2.703-3.07-3.4-.47-.518-.9-.988-1.313-1.436a3 3 0 0 1 4.41-4.068c.425.46.866.942 1.346 1.47.642.709 2.79 3.092 3.076 3.41a180.865 180.865 0 0 0 2.964 3.214z"/><path fill="#E1DBF1" d="M254.66 72.196l2-3.464a2 2 0 1 0-3.464-2l-2 3.464-3.464-2a2 2 0 0 0-2 3.464l3.464 2-2 3.464a2 2 0 0 0 3.464 2l2-3.464 3.464 2a2 2 0 1 0 2-3.464l-3.464-2zm-151.904 78.732l2.829-2.828a2 2 0 0 0-2.829-2.829l-2.828 2.829-2.828-2.829a2 2 0 0 0-2.829 2.829l2.829 2.828-2.829 2.829a2 2 0 1 0 2.829 2.828l2.828-2.828 2.828 2.828a2 2 0 1 0 2.829-2.828l-2.829-2.829z"/><path fill="#6B4FBB" d="M210.66 173.66l3.464-2a2 2 0 1 0-2-3.464l-3.464 2-2-3.464a2 2 0 0 0-3.464 2l2 3.464-3.464 2a2 2 0 1 0 2 3.464l3.464-2 2 3.464a2 2 0 1 0 3.464-2l-2-3.464z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M27 181a8 8 0 1 1 0-16 8 8 0 0 1 0 16zm0-4a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M138 85a7 7 0 1 1 0-14 7 7 0 0 1 0 14zm0-4a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M200 57a7 7 0 1 1 0-14 7 7 0 0 1 0 14zm0-4a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/><path fill="#FC6D26" fill-rule="nonzero" d="M222.647 121.647v5h5v-5h-5zm0-4h5a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4h-5a4 4 0 0 1-4-4v-5a4 4 0 0 1 4-4z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M103.647 28.647v5h5v-5h-5zm0-4h5a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4h-5a4 4 0 0 1-4-4v-5a4 4 0 0 1 4-4z"/><path fill="#FC6D26" fill-rule="nonzero" d="M85 103.488L81.841 108h6.318L85 103.488zm6.436 2.218A4 4 0 0 1 88.159 112H81.84a4 4 0 0 1-3.277-6.294l3.16-4.512a4 4 0 0 1 6.553 0l3.159 4.512z"/></g><path fill="#F9F9F9" d="M334.376 99.43A48.805 48.805 0 0 0 366 111c27.062 0 49-21.938 49-49s-21.938-49-49-49-49 21.938-49 49c0 9.454 2.677 18.283 7.315 25.77l-3.05 11.306a2.5 2.5 0 0 0 3.064 3.065l10.047-2.71z"/><path fill="#FFF" d="M339.376 94.43A48.805 48.805 0 0 0 371 106c27.062 0 49-21.938 49-49S398.062 8 371 8s-49 21.938-49 49c0 9.454 2.677 18.283 7.315 25.77l-3.05 11.306a2.5 2.5 0 0 0 3.064 3.065l10.047-2.71z"/><path fill="#EEE" fill-rule="nonzero" d="M329.85 99.072a4.5 4.5 0 0 1-5.516-5.517l2.827-10.48C322.501 75.258 320 66.31 320 57c0-28.167 22.833-51 51-51s51 22.833 51 51-22.833 51-51 51c-11.859 0-23.096-4.064-32.102-11.37l-9.048 2.442zm10.817-6.169C349.091 100.027 359.737 104 371 104c25.957 0 47-21.043 47-47s-21.043-47-47-47-47 21.043-47 47c0 8.859 2.453 17.351 7.016 24.716l.456.737-3.277 12.144c.072.527.347.685.613.613l11.059-2.984.8.677z"/><g transform="translate(354 34)"><path fill="#E1DBF1" fill-rule="nonzero" d="M13 4a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-8zm0-4h8a5 5 0 0 1 5 5v1a5 5 0 0 1-5 5h-8a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M5 11a1 1 0 0 0 0 2h24a1 1 0 0 0 0-2H5zm0-4h24a5 5 0 0 1 0 10H5A5 5 0 0 1 5 7z"/><rect width="12" height="4" x="11" y="31" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="19" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="37" fill="#E1DBF1" rx="2"/><rect width="12" height="4" x="11" y="43" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="25" fill="#E1DBF1" rx="2"/></g><path fill="#F9F9F9" d="M344.238 225.072A38.83 38.83 0 0 1 368 217c21.54 0 39 17.46 39 39s-17.46 39-39 39-39-17.46-39-39a38.84 38.84 0 0 1 4.001-17.227l-3.737-13.85a2.5 2.5 0 0 1 3.065-3.064l11.91 3.213z"/><path fill="#FFF" d="M348.238 221.072A38.83 38.83 0 0 1 372 213c21.54 0 39 17.46 39 39s-17.46 39-39 39-39-17.46-39-39a38.84 38.84 0 0 1 4.001-17.227l-3.737-13.85a2.5 2.5 0 0 1 3.065-3.064l11.91 3.213z"/><path fill="#EEE" fill-rule="nonzero" d="M336.85 215.928a4.5 4.5 0 0 0-5.516 5.517l3.543 13.13A40.848 40.848 0 0 0 331 252c0 22.644 18.356 41 41 41s41-18.356 41-41-18.356-41-41-41a40.82 40.82 0 0 0-24.182 7.887l-10.968-2.96zm12.608 6.73A36.824 36.824 0 0 1 372 215c20.435 0 37 16.565 37 37s-16.565 37-37 37-37-16.565-37-37c0-5.747 1.31-11.304 3.795-16.343l.334-.677-3.934-14.577a.5.5 0 0 1 .613-.613l12.865 3.471.785-.604z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M356.097 255.962a7 7 0 0 0 8.81 10.88l1.093-.885v1.454a7 7 0 1 0 14 0v-1.454l1.092.885a7 7 0 1 0 8.81-10.88l-1.185-.96 1.455-.337a7 7 0 1 0-3.15-13.64l-1.4.323.623-1.278a7 7 0 0 0-12.583-6.137l-.662 1.356-.662-1.356a7 7 0 0 0-12.583 6.137l.623 1.278-1.4-.324a7 7 0 1 0-3.15 13.641l1.455.336-1.186.96zm5.464-.913a11.914 11.914 0 0 1-.444-1.95l-.19-1.362-4.2-.97a3 3 0 0 1 1.35-5.845l4.178.964.768-1.145c.373-.557.793-1.082 1.254-1.57l.95-1.006-1.877-3.849a3 3 0 0 1 5.393-2.63l1.892 3.879 1.363-.113a12.188 12.188 0 0 1 2.004 0l1.363.113 1.892-3.879a3 3 0 0 1 5.393 2.63l-1.877 3.849.95 1.006c.461.488.88 1.013 1.254 1.57l.768 1.145 4.178-.964a3 3 0 1 1 1.35 5.846l-4.2.97-.19 1.36a11.914 11.914 0 0 1-.444 1.95l-.413 1.302 3.36 2.72a3 3 0 1 1-3.776 4.663l-3.32-2.688-1.196.706a11.94 11.94 0 0 1-1.808.873l-1.286.492v4.295a3 3 0 1 1-6 0v-4.295l-1.286-.492a11.94 11.94 0 0 1-1.808-.873l-1.196-.706-3.32 2.688a3 3 0 1 1-3.776-4.663l3.36-2.72-.413-1.301z"/><path fill="#FC6D26" fill-rule="nonzero" d="M373 245.411a6 6 0 1 0 0 12 6 6 0 0 0 0-12zm0 4a2 2 0 1 1 0 4 2 2 0 0 1 0-4z"/><g><path fill="#F9F9F9" d="M94.624 162.43A48.805 48.805 0 0 1 63 174c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49c0 9.454-2.677 18.283-7.315 25.77l3.05 11.306a2.5 2.5 0 0 1-3.064 3.065l-10.047-2.71z"/><path fill="#FFF" stroke="#EEE" stroke-width="4" d="M89.624 157.43A48.805 48.805 0 0 1 58 169c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49c0 9.454-2.677 18.283-7.315 25.77l3.05 11.306a2.5 2.5 0 0 1-3.064 3.065l-10.047-2.71z"/><path fill="#EEE" fill-rule="nonzero" d="M99.15 162.072a4.5 4.5 0 0 0 5.516-5.517l-2.827-10.48C106.499 138.258 109 129.31 109 120c0-28.167-22.833-51-51-51S7 91.833 7 120s22.833 51 51 51c11.859 0 23.096-4.064 32.102-11.37l9.048 2.442zm-10.817-6.169C79.909 163.027 69.263 167 58 167c-25.957 0-47-21.043-47-47s21.043-47 47-47 47 21.043 47 47c0 8.859-2.453 17.351-7.016 24.716l-.456.737 3.277 12.144c-.072.527-.347.685-.613.613l-11.059-2.984-.8.677z"/><g fill-rule="nonzero"><path fill="#FEE1D3" d="M55.47 94.47l-16.148 6.688a4 4 0 0 0-2.164 2.164l-6.689 16.147a4 4 0 0 0 0 3.062l6.689 16.147a4 4 0 0 0 2.164 2.164l16.147 6.689a4 4 0 0 0 3.062 0l16.147-6.689a4 4 0 0 0 2.164-2.164l6.689-16.147a4 4 0 0 0 0-3.062l-6.689-16.147a4 4 0 0 0-2.164-2.164L58.53 94.469a4 4 0 0 0-3.062 0zM57 98.164l16.147 6.688L79.835 121l-6.688 16.147L57 143.835l-16.147-6.688L34.165 121l6.688-16.147L57 98.165zM57 107a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm12 4a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-4 11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-12 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-12-6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-4-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm12 20c6.075 0 11-4.925 11-11s-4.925-11-11-11-11 4.925-11 11 4.925 11 11 11zm0-4a7 7 0 1 1 0-14 7 7 0 0 1 0 14z"/><path fill="#FC6D26" d="M57 126.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0-3a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5z"/></g></g></g></svg> \ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="430" height="300" viewBox="0 0 430 300"><defs><rect id="a" width="280" height="180" x="77" y="60" rx="10"/><rect id="c" width="100" height="48" rx="10"/><filter id="b" width="105%" height="120.8%" x="-2.5%" y="-5.2%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="e" width="84" height="76" rx="10"/><filter id="d" width="106%" height="113.2%" x="-3%" y="-3.3%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="g" width="52" height="76" rx="10"/><filter id="f" width="109.6%" height="113.2%" x="-4.8%" y="-3.3%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="i" width="36" height="132" rx="10"/><filter id="h" width="113.9%" height="107.6%" x="-6.9%" y="-1.9%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="k" width="52" height="48" rx="10"/><filter id="j" width="109.6%" height="120.8%" x="-4.8%" y="-5.2%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h430v300H0z"/><use fill="#FFF" xlink:href="#a"/><rect width="276" height="176" x="79" y="62" stroke="#EEE" stroke-width="4" rx="10"/><rect width="8" height="20" x="244" y="141" fill="#EEE" rx="4"/><rect width="8" height="20" x="311" y="103" fill="#EEE" rx="4"/><rect width="8" height="20" x="272" y="166" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="257" y="203" fill="#EEE" rx="4"/><rect width="8" height="20" x="169" y="77" fill="#EEE" rx="4"/><rect width="8" height="20" x="191" y="104" fill="#FFF" rx="4"/><rect width="8" height="20" x="140" y="157" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="154" y="119" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="163" y="205" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="294" y="186" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="327" y="73" fill="#FEE1D3" rx="4"/><g transform="translate(197 79)"><use fill="#000" filter="url(#b)" xlink:href="#c"/><use fill="#FFF" xlink:href="#c"/><rect width="96" height="44" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="62" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="78" y="14" fill="#FDC4A8" rx="4"/><rect width="8" height="20" x="46" y="14" fill="#FC6D26" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#EEE" rx="4"/></g><g transform="translate(57 30)"><use fill="#000" filter="url(#d)" xlink:href="#e"/><use fill="#FFF" xlink:href="#e"/><rect width="80" height="72" x="2" y="2" stroke="#E1DBF1" stroke-width="4" rx="10"/><rect width="8" height="20" x="62" y="42" fill="#6B4FBB" rx="4"/><rect width="8" height="20" x="46" y="42" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="30" y="42" fill="#C3B8E3" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="62" y="14" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="46" y="14" fill="#C3B8E3" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#EEE" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#C3B8E3" rx="4"/></g><g transform="translate(317 133)"><use fill="#000" filter="url(#f)" xlink:href="#g"/><use fill="#FFF" xlink:href="#g"/><rect width="48" height="72" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="14" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#FC6D26" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#EEE" rx="4"/><rect width="8" height="20" x="30" y="42" fill="#FDC4A8" rx="4"/></g><g transform="translate(89 133)"><use fill="#000" filter="url(#h)" xlink:href="#i"/><use fill="#FFF" xlink:href="#i"/><rect width="32" height="128" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="14" y="14" fill="#FDC4A8" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#EEE" rx="4"/><rect width="8" height="20" x="14" y="70" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="98" fill="#FC6D26" rx="4"/></g><g transform="translate(181 161)"><use fill="#000" filter="url(#j)" xlink:href="#k"/><use fill="#FFF" xlink:href="#k"/><rect width="48" height="44" x="2" y="2" stroke="#E1DBF1" stroke-width="4" rx="10"/><rect width="8" height="20" x="30" y="14" fill="#6B4FBB" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#C3B8E3" rx="4"/></g></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/epics/list.svg b/app/assets/images/illustrations/epics/list.svg
new file mode 100644
index 00000000000..be6c3fb76a5
--- /dev/null
+++ b/app/assets/images/illustrations/epics/list.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="430" height="300" viewBox="0 0 430 300"><defs><rect id="a" width="280" height="180" x="77" y="60" rx="10"/><rect id="c" width="100" height="48" rx="10"/><filter id="b" width="105%" height="120.8%" x="-2.5%" y="-5.2%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="e" width="84" height="76" rx="10"/><filter id="d" width="106%" height="113.2%" x="-3%" y="-3.3%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="g" width="52" height="76" rx="10"/><filter id="f" width="109.6%" height="113.2%" x="-4.8%" y="-3.3%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="i" width="36" height="132" rx="10"/><filter id="h" width="113.9%" height="107.6%" x="-6.9%" y="-1.9%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter><rect id="k" width="52" height="48" rx="10"/><filter id="j" width="109.6%" height="120.8%" x="-4.8%" y="-5.2%" filterUnits="objectBoundingBox"><feOffset dy="5" in="SourceAlpha" result="shadowOffsetOuter1"/><feComposite in="shadowOffsetOuter1" in2="SourceAlpha" operator="out" result="shadowOffsetOuter1"/><feColorMatrix in="shadowOffsetOuter1" values="0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 0 0.976470588 0 0 0 1 0"/></filter></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h430v300H0z"/><use fill="#FFF" xlink:href="#a"/><rect width="276" height="176" x="79" y="62" stroke="#EEE" stroke-width="4" rx="10"/><rect width="8" height="20" x="244" y="141" fill="#EEE" rx="4"/><rect width="8" height="20" x="311" y="103" fill="#EEE" rx="4"/><rect width="8" height="20" x="272" y="166" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="257" y="203" fill="#EEE" rx="4"/><rect width="8" height="20" x="169" y="77" fill="#EEE" rx="4"/><rect width="8" height="20" x="191" y="104" fill="#FFF" rx="4"/><rect width="8" height="20" x="140" y="157" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="154" y="119" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="163" y="205" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="294" y="186" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="327" y="73" fill="#FEE1D3" rx="4"/><g transform="translate(197 79)"><use fill="#000" filter="url(#b)" xlink:href="#c"/><use fill="#FFF" xlink:href="#c"/><rect width="96" height="44" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="62" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="78" y="14" fill="#FDC4A8" rx="4"/><rect width="8" height="20" x="46" y="14" fill="#FC6D26" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#EEE" rx="4"/></g><g transform="translate(57 30)"><use fill="#000" filter="url(#d)" xlink:href="#e"/><use fill="#FFF" xlink:href="#e"/><rect width="80" height="72" x="2" y="2" stroke="#E1DBF1" stroke-width="4" rx="10"/><rect width="8" height="20" x="62" y="42" fill="#6B4FBB" rx="4"/><rect width="8" height="20" x="46" y="42" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="30" y="42" fill="#C3B8E3" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="62" y="14" fill="#E1DBF1" rx="4"/><rect width="8" height="20" x="46" y="14" fill="#C3B8E3" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#EEE" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#C3B8E3" rx="4"/></g><g transform="translate(317 133)"><use fill="#000" filter="url(#f)" xlink:href="#g"/><use fill="#FFF" xlink:href="#g"/><rect width="48" height="72" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="14" y="14" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#FC6D26" rx="4"/><rect width="8" height="20" x="30" y="14" fill="#EEE" rx="4"/><rect width="8" height="20" x="30" y="42" fill="#FDC4A8" rx="4"/></g><g transform="translate(89 133)"><use fill="#000" filter="url(#h)" xlink:href="#i"/><use fill="#FFF" xlink:href="#i"/><rect width="32" height="128" x="2" y="2" stroke="#FEE1D3" stroke-width="4" rx="10"/><rect width="8" height="20" x="14" y="14" fill="#FDC4A8" rx="4"/><rect width="8" height="20" x="14" y="42" fill="#EEE" rx="4"/><rect width="8" height="20" x="14" y="70" fill="#FEE1D3" rx="4"/><rect width="8" height="20" x="14" y="98" fill="#FC6D26" rx="4"/></g><g transform="translate(181 161)"><use fill="#000" filter="url(#j)" xlink:href="#k"/><use fill="#FFF" xlink:href="#k"/><rect width="48" height="44" x="2" y="2" stroke="#E1DBF1" stroke-width="4" rx="10"/><rect width="8" height="20" x="30" y="14" fill="#6B4FBB" rx="4"/><rect width="8" height="20" x="14" y="14" fill="#C3B8E3" rx="4"/></g></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/epics/roadmap.svg b/app/assets/images/illustrations/epics/roadmap.svg
new file mode 100644
index 00000000000..a14f14b91c9
--- /dev/null
+++ b/app/assets/images/illustrations/epics/roadmap.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="415" height="289" viewBox="0 0 415 289"><g fill="none" fill-rule="evenodd"><path d="M-9-5h430v300H-9z"/><g transform="translate(68 47)"><rect width="284" height="208" y="5" fill="#F9F9F9" fill-rule="nonzero" rx="10"/><rect width="284" height="208" fill="#FFF" fill-rule="nonzero" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M10 4a6 6 0 0 0-6 6v188a6 6 0 0 0 6 6h264a6 6 0 0 0 6-6V10a6 6 0 0 0-6-6H10zm0-4h264c5.523 0 10 4.477 10 10v188c0 5.523-4.477 10-10 10H10c-5.523 0-10-4.477-10-10V10C0 4.477 4.477 0 10 0z"/><path fill="#E1DBF1" d="M25.168 153.995c3.837-.215 7.173.028 10.119.691a3 3 0 1 0 1.318-5.853c-3.509-.79-7.4-1.074-11.773-.828a3 3 0 1 0 .336 5.99z"/><path fill="#C3B8E3" d="M44.211 158.655c2.401 1.704 4.388 3.61 7.569 7.083a3 3 0 1 0 4.424-4.054c-3.448-3.763-5.686-5.911-8.522-7.923a3 3 0 1 0-3.471 4.894z"/><path fill="#E1DBF1" d="M59.786 173.828c3.181 2.675 6.52 4.665 10.397 6.039a3 3 0 0 0 2.004-5.655c-3.162-1.121-5.884-2.743-8.54-4.976a3 3 0 1 0-3.861 4.592zm22.133 8.148c1.02.037 2.067.045 3.143.023a72.664 72.664 0 0 0 8.346-.638 3 3 0 0 0-.812-5.945c-2.442.334-4.996.53-7.658.585a48.55 48.55 0 0 1-2.796-.021 3 3 0 1 0-.223 5.996z"/><path fill="#C3B8E3" d="M104.697 178.69c3.9-1.37 7.427-3.15 10.54-5.305a3 3 0 0 0-3.415-4.933c-2.665 1.845-5.712 3.382-9.114 4.578a3 3 0 0 0 1.989 5.66z"/><path fill="#E1DBF1" d="M123.853 165.07a33.752 33.752 0 0 0 5.276-10.817 3 3 0 1 0-5.773-1.633 27.753 27.753 0 0 1-4.341 8.9 3 3 0 0 0 4.838 3.55zm6.577-22.657c-.187-3.817-.926-7.71-2.204-11.596a3 3 0 1 0-5.7 1.874c1.113 3.384 1.75 6.745 1.91 10.016a3 3 0 1 0 5.994-.294z"/><path fill="#C3B8E3" d="M123.333 120.153c-1.897-3.2-4.152-6.325-6.748-9.344a3 3 0 0 0-4.55 3.913c2.372 2.756 4.421 5.597 6.136 8.49a3 3 0 1 0 5.162-3.06v.001z"/><path fill="#E1DBF1" d="M111.787 102.36c-.938-3.025-1.402-6.42-1.365-9.976a3 3 0 1 0-6-.063c-.043 4.163.506 8.177 1.634 11.816a3 3 0 1 0 5.731-1.777z"/><path fill="#C3B8E3" d="M111.84 82.253c.905-3.341 2.22-6.538 3.904-9.448a3 3 0 0 0-5.194-3.004c-1.948 3.368-3.463 7.048-4.501 10.884a3 3 0 1 0 5.791 1.568z"/><path fill="#E1DBF1" d="M121.974 64.948c2.475-2.28 5.265-4.09 8.335-5.374a3 3 0 1 0-2.314-5.536c-3.725 1.558-7.105 3.75-10.086 6.497a3 3 0 1 0 4.065 4.413zm18.177-7.586c3.202-.18 6.599.092 10.18.843a3 3 0 0 0 1.23-5.872c-4.086-.857-8.009-1.172-11.747-.962a3 3 0 1 0 .337 5.99v.001z"/><path fill="#C3B8E3" d="M160.198 61.312c3.068 1.268 6.232 2.842 9.487 4.728a3 3 0 1 0 3.009-5.191c-3.48-2.017-6.883-3.71-10.204-5.083a3 3 0 0 0-2.292 5.545v.001z"/><path fill="#E1DBF1" d="M179.776 71.267c3.711 1.586 7.376 2.77 10.997 3.565a3 3 0 0 0 1.286-5.86c-3.248-.713-6.555-1.782-9.925-3.222a3 3 0 1 0-2.358 5.517zm22.591 4.789c3.94-.04 7.808-.553 11.61-1.513a3 3 0 1 0-1.468-5.817 43.358 43.358 0 0 1-10.203 1.33 3 3 0 0 0 .061 6z"/><path fill="#C3B8E3" d="M224.887 70.498c3.335-1.637 6.607-3.613 9.845-5.916a3 3 0 0 0-3.477-4.89c-2.984 2.122-5.98 3.931-9.011 5.42a3 3 0 1 0 2.643 5.386z"/><path fill="#E1DBF1" d="M243.565 57.444a3 3 0 0 1-4.02-4.454 130.547 130.547 0 0 0 5.31-5.088 3 3 0 1 1 4.265 4.22 136.506 136.506 0 0 1-5.555 5.322z"/><path fill="#FDC4A8" d="M194.843 83.085a3 3 0 1 1 4.314-4.17c3.056 3.16 5.075 6.744 6.172 10.754a3 3 0 0 1-5.787 1.584c-.834-3.047-2.35-5.739-4.699-8.168z"/><path fill="#FEE1D3" d="M200.19 101.134a3 3 0 1 1 5.978.52c-.282 3.232-.805 6.273-1.832 11.206a3 3 0 0 1-5.874-1.222c.981-4.717 1.473-7.572 1.728-10.504z"/><path fill="#FDC4A8" d="M196.413 122.689a3 3 0 0 1 5.953.747c-.5 3.988-.397 7.09.399 9.67a3 3 0 1 1-5.733 1.769c-1.087-3.52-1.217-7.426-.62-12.186h.001z"/><path fill="#FEE1D3" d="M203.806 145.133a3 3 0 0 1 4.461-4.013c2.703 3.005 5.224 5.296 7.594 6.947a3 3 0 0 1-3.429 4.924c-2.775-1.932-5.632-4.53-8.626-7.858zm20.352 12.28a3 3 0 1 1 .334-5.99c2.77.154 5.453-.554 9.224-2.254a3 3 0 0 1 2.466 5.47c-4.57 2.06-8.103 2.993-12.024 2.775v-.001z"/><path fill="#FDC4A8" d="M245.942 150.355a3 3 0 0 1-1.815-5.719c4.227-1.342 8.24-1.61 12.496-.572a3 3 0 0 1-1.421 5.83c-3.116-.76-6.025-.566-9.26.46v.001zM106.53 56.038a3 3 0 0 1-3.45 4.909c-1.074-.755-6.723-6.044-8.083-7.204l-.332-.281a3 3 0 1 1 3.865-4.59l.362.306c1.643 1.402 6.971 6.391 7.638 6.86z"/><path fill="#FEE1D3" d="M88.536 42.422a3 3 0 0 1-2.285 5.548c-3.14-1.293-5.78-1.34-8.105-.05a3 3 0 0 1-2.91-5.247c4.087-2.266 8.597-2.187 13.3-.25v-.001z"/><path fill="#FDC4A8" d="M66.698 48.73a3 3 0 0 1 2.029 5.647c-4.432 1.592-8.786.835-13.166-1.88a3 3 0 1 1 3.16-5.1c2.93 1.816 5.425 2.25 7.977 1.333z"/><path fill="#FEE1D3" d="M51.062 40.692a3 3 0 0 1-4.352 4.13c-.911-.96-1.85-1.98-3.061-3.32-.295-.325-2.437-2.703-3.07-3.4-.47-.518-.9-.988-1.313-1.436a3 3 0 0 1 4.41-4.068c.425.46.866.942 1.346 1.47.642.709 2.79 3.092 3.076 3.41a180.865 180.865 0 0 0 2.964 3.214z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M254.66 72.196l2-3.464a2 2 0 1 0-3.464-2l-2 3.464-3.464-2a2 2 0 0 0-2 3.464l3.464 2-2 3.464a2 2 0 0 0 3.464 2l2-3.464 3.464 2a2 2 0 1 0 2-3.464l-3.464-2zm-151.904 78.732l2.829-2.828a2 2 0 1 0-2.829-2.829l-2.828 2.829-2.828-2.829a2 2 0 1 0-2.829 2.829l2.829 2.828-2.829 2.829a2 2 0 0 0 2.829 2.828l2.828-2.828 2.828 2.828a2 2 0 1 0 2.829-2.828l-2.829-2.829z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M210.66 173.66l3.464-2a2 2 0 1 0-2-3.464l-3.464 2-2-3.464a2 2 0 0 0-3.464 2l2 3.464-3.464 2a2 2 0 1 0 2 3.464l3.464-2 2 3.464a2 2 0 1 0 3.464-2l-2-3.464z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M27 181a8 8 0 1 1 0-16 8 8 0 0 1 0 16zm0-4a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M138 85a7 7 0 1 1 0-14 7 7 0 0 1 0 14zm0-4a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M200 57a7 7 0 1 1 0-14 7 7 0 0 1 0 14zm0-4a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/><path fill="#FC6D26" fill-rule="nonzero" d="M222.647 121.647v5h5v-5h-5zm0-4h5a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4h-5a4 4 0 0 1-4-4v-5a4 4 0 0 1 4-4z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M103.647 28.647v5h5v-5h-5zm0-4h5a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4h-5a4 4 0 0 1-4-4v-5a4 4 0 0 1 4-4z"/><path fill="#FC6D26" fill-rule="nonzero" d="M85 103.488L81.841 108h6.318L85 103.488zm6.436 2.218A4 4 0 0 1 88.159 112H81.84a4 4 0 0 1-3.277-6.294l3.16-4.512a4 4 0 0 1 6.553 0l3.159 4.512h.001z"/></g><path fill="#F9F9F9" fill-rule="nonzero" d="M327.376 93.43A48.805 48.805 0 0 0 359 105c27.062 0 49-21.938 49-49S386.062 7 359 7s-49 21.938-49 49c0 9.454 2.677 18.283 7.315 25.77l-3.05 11.306a2.5 2.5 0 0 0 3.064 3.065l10.047-2.71v-.001z"/><path fill="#FFF" fill-rule="nonzero" d="M332.376 88.43A48.805 48.805 0 0 0 364 100c27.062 0 49-21.938 49-49S391.062 2 364 2s-49 21.938-49 49c0 9.454 2.677 18.283 7.315 25.77l-3.05 11.306a2.5 2.5 0 0 0 3.064 3.065l10.047-2.71v-.001z"/><path fill="#EEE" fill-rule="nonzero" d="M322.85 93.072a4.5 4.5 0 0 1-5.516-5.517l2.827-10.48C315.501 69.258 313 60.31 313 51c0-28.167 22.833-51 51-51s51 22.833 51 51-22.833 51-51 51c-11.859 0-23.096-4.064-32.102-11.37l-9.048 2.442zm10.817-6.169C342.091 94.027 352.737 98 364 98c25.957 0 47-21.043 47-47S389.957 4 364 4s-47 21.043-47 47c0 8.859 2.453 17.351 7.016 24.716l.456.737-3.277 12.144c.072.527.347.685.613.613l11.059-2.984.8.677z"/><g fill-rule="nonzero" transform="translate(347 28)"><path fill="#E1DBF1" d="M13 4a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-8zm0-4h8a5 5 0 0 1 5 5v1a5 5 0 0 1-5 5h-8a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z"/><path fill="#6B4FBB" d="M5 11a1 1 0 0 0 0 2h24a1 1 0 0 0 0-2H5zm0-4h24a5 5 0 0 1 0 10H5A5 5 0 0 1 5 7z"/><rect width="12" height="4" x="11" y="31" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="19" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="37" fill="#E1DBF1" rx="2"/><rect width="12" height="4" x="11" y="43" fill="#C3B8E3" rx="2"/><rect width="12" height="4" x="11" y="25" fill="#E1DBF1" rx="2"/></g><g fill-rule="nonzero"><path fill="#F9F9F9" d="M337.238 219.072A38.83 38.83 0 0 1 361 211c21.54 0 39 17.46 39 39s-17.46 39-39 39-39-17.46-39-39a38.84 38.84 0 0 1 4.001-17.227l-3.737-13.85a2.5 2.5 0 0 1 3.065-3.064l11.91 3.213h-.001z"/><path fill="#FFF" d="M341.238 215.072A38.83 38.83 0 0 1 365 207c21.54 0 39 17.46 39 39s-17.46 39-39 39-39-17.46-39-39a38.84 38.84 0 0 1 4.001-17.227l-3.737-13.85a2.5 2.5 0 0 1 3.065-3.064l11.91 3.213h-.001z"/><path fill="#EEE" d="M329.85 209.928a4.5 4.5 0 0 0-5.516 5.517l3.543 13.13A40.848 40.848 0 0 0 324 246c0 22.644 18.356 41 41 41s41-18.356 41-41-18.356-41-41-41a40.82 40.82 0 0 0-24.182 7.887l-10.968-2.96v.001zm12.608 6.73A36.824 36.824 0 0 1 365 209c20.435 0 37 16.565 37 37s-16.565 37-37 37-37-16.565-37-37c0-5.747 1.31-11.304 3.795-16.343l.334-.677-3.934-14.577a.5.5 0 0 1 .613-.613l12.865 3.471.785-.604v.001z"/><path fill="#FEE1D3" d="M348.097 250.962a7 7 0 0 0 8.81 10.88l1.093-.885v1.454a7 7 0 0 0 14 0v-1.454l1.092.885a7 7 0 1 0 8.81-10.88l-1.185-.96 1.455-.337a7 7 0 1 0-3.15-13.64l-1.4.323.623-1.278a7 7 0 0 0-12.583-6.137l-.662 1.356-.662-1.356a7 7 0 0 0-12.583 6.137l.623 1.278-1.4-.324a7 7 0 1 0-3.15 13.641l1.455.336-1.186.96v.001zm5.464-.913a11.914 11.914 0 0 1-.444-1.95l-.19-1.362-4.2-.97a3 3 0 0 1 1.35-5.845l4.178.964.768-1.145c.373-.557.793-1.082 1.254-1.57l.95-1.006-1.877-3.849a3 3 0 0 1 5.393-2.63l1.892 3.879 1.363-.113a12.188 12.188 0 0 1 2.004 0l1.363.113 1.892-3.879a3 3 0 0 1 5.393 2.63l-1.877 3.849.95 1.006c.461.488.88 1.013 1.254 1.57l.768 1.145 4.178-.964a3 3 0 1 1 1.35 5.846l-4.2.97-.19 1.36a11.914 11.914 0 0 1-.444 1.95l-.413 1.302 3.36 2.72a3 3 0 1 1-3.776 4.663l-3.32-2.688-1.196.706a11.94 11.94 0 0 1-1.808.873l-1.286.492v4.295a3 3 0 0 1-6 0v-4.295l-1.286-.492a11.94 11.94 0 0 1-1.808-.873l-1.196-.706-3.32 2.688a3 3 0 0 1-3.776-4.663l3.36-2.72-.413-1.301z"/><path fill="#FC6D26" d="M365 240.411a6 6 0 1 0 0 12 6 6 0 0 0 0-12zm0 4a2 2 0 1 1 0 4 2 2 0 0 1 0-4z"/></g><g fill-rule="nonzero"><path fill="#F9F9F9" d="M87.624 156.43A48.805 48.805 0 0 1 56 168c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49c0 9.454-2.677 18.283-7.315 25.77l3.05 11.306a2.5 2.5 0 0 1-3.064 3.065l-10.047-2.71v-.001z"/><path fill="#FFF" stroke="#EEE" stroke-width="4" d="M82.624 151.43A48.805 48.805 0 0 1 51 163c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49c0 9.454-2.677 18.283-7.315 25.77l3.05 11.306a2.5 2.5 0 0 1-3.064 3.065l-10.047-2.71v-.001z"/><path fill="#EEE" d="M92.15 156.072a4.5 4.5 0 0 0 5.516-5.517l-2.827-10.48C99.499 132.258 102 123.31 102 114c0-28.167-22.833-51-51-51S0 85.833 0 114s22.833 51 51 51c11.859 0 23.096-4.064 32.102-11.37l9.048 2.442zm-10.817-6.169C72.909 157.027 62.263 161 51 161c-25.957 0-47-21.043-47-47s21.043-47 47-47 47 21.043 47 47c0 8.859-2.453 17.351-7.016 24.716l-.456.737 3.277 12.144c-.072.527-.347.685-.613.613l-11.059-2.984-.8.677z"/><path fill="#FEE1D3" d="M48.47 88.47l-16.148 6.688a4 4 0 0 0-2.164 2.164l-6.689 16.147a4 4 0 0 0 0 3.062l6.689 16.147a4 4 0 0 0 2.164 2.164l16.147 6.689a4 4 0 0 0 3.062 0l16.147-6.689a4 4 0 0 0 2.164-2.164l6.689-16.147a4 4 0 0 0 0-3.062l-6.689-16.147a4 4 0 0 0-2.164-2.164L51.53 88.469a4 4 0 0 0-3.062 0l.002.001zM50 92.164l16.147 6.688L72.835 115l-6.688 16.147L50 137.835l-16.147-6.688L27.165 115l6.688-16.147L50 92.165v-.001zM50 101a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm12 4a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-4 11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-12 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-12-6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-4-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm4-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm12 20c6.075 0 11-4.925 11-11s-4.925-11-11-11-11 4.925-11 11 4.925 11 11 11zm0-4a7 7 0 1 1 0-14 7 7 0 0 1 0 14z"/><path fill="#FC6D26" d="M50 120.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0-3a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5z"/></g></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/issue-dashboard_results-without-filiter.svg b/app/assets/images/illustrations/issue-dashboard_results-without-filiter.svg
new file mode 100644
index 00000000000..cd9070425b0
--- /dev/null
+++ b/app/assets/images/illustrations/issue-dashboard_results-without-filiter.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="104" height="104" viewBox="0 0 104 104"><g fill="none" fill-rule="evenodd"><path fill="#EEE" fill-rule="nonzero" d="M9.565 27.5a2 2 0 0 1 3.464 2C6.226 41.283 5.18 55.239 9.843 67.745a2 2 0 0 1-3.748 1.397C1.02 55.53 2.159 40.328 9.565 27.5zM27.5 94.435a2 2 0 0 1 2-3.464c9.19 5.306 19.725 7.137 29.97 5.406a2 2 0 1 1 .667 3.944A48.798 48.798 0 0 1 27.5 94.435zM94.435 76.5a2 2 0 0 1-3.464-2 44.808 44.808 0 0 0 5.261-30.78 2 2 0 0 1 3.932-.738A48.807 48.807 0 0 1 94.435 76.5zM76.5 9.565a2 2 0 0 1-2 3.464C62.824 6.288 49.012 5.198 36.585 9.72a2 2 0 0 1-1.368-3.758C48.744 1.039 63.789 2.226 76.5 9.565z"/><path fill="#EEE" fill-rule="nonzero" d="M62.612 12.397a2 2 0 0 1-1.036 3.864C51.55 13.574 41.08 15.214 32.44 20.593a2 2 0 0 1-2.114-3.396c9.571-5.958 21.18-7.776 32.287-4.8zM12.397 41.388a2 2 0 0 1 3.864 1.036 36.854 36.854 0 0 0 2.986 26.787 2 2 0 1 1-3.54 1.862 40.854 40.854 0 0 1-3.31-29.685zm28.991 50.215a2 2 0 0 1 1.036-3.864c10.098 2.706 20.644 1.022 29.316-4.445a2 2 0 1 1 2.134 3.384c-9.606 6.056-21.299 7.922-32.486 4.925zm50.215-28.991a2 2 0 0 1-3.864-1.036 36.86 36.86 0 0 0-3.208-27.204 2 2 0 1 1 3.517-1.906 40.859 40.859 0 0 1 3.555 30.146z"/><path fill="#EEE" d="M22.717 56.065c2.039 14.585 14.563 25.81 29.71 25.81 16.569 0 30-13.431 30-30v-.077c.191 1.369.29 2.768.29 4.19 0 16.568-13.431 30-30 30-16.543 0-29.958-13.39-30-29.923z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M52.427 83.875c-17.673 0-32-14.327-32-32 0-17.673 14.327-32 32-32 17.673 0 32 14.327 32 32 0 17.673-14.327 32-32 32zm0-4c15.464 0 28-12.536 28-28s-12.536-28-28-28-28 12.536-28 28 12.536 28 28 28zm6.877-16.24a2 2 0 1 1-2.882 2.773 4.979 4.979 0 0 0-3.603-1.533 4.977 4.977 0 0 0-3.539 1.468 2 2 0 1 1-2.83-2.826 8.976 8.976 0 0 1 6.369-2.642 8.98 8.98 0 0 1 6.485 2.76z"/><path fill="#6B4FBB" d="M41.755 49.774l2.122 2.122a2 2 0 1 1-2.829 2.828l-2.121-2.121-2.121 2.121a2 2 0 0 1-2.829-2.828l2.122-2.122-2.122-2.12a2 2 0 1 1 2.829-2.83l2.121 2.122 2.121-2.121a2 2 0 0 1 2.829 2.828l-2.122 2.121zm27 0l2.122 2.122a2 2 0 1 1-2.829 2.828l-2.121-2.121-2.121 2.121a2 2 0 0 1-2.829-2.828l2.122-2.122-2.122-2.12a2 2 0 1 1 2.829-2.83l2.121 2.122 2.121-2.121a2 2 0 0 1 2.829 2.828l-2.122 2.121z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/lock_promotion.svg b/app/assets/images/illustrations/lock_promotion.svg
new file mode 100644
index 00000000000..6f1f9b2b030
--- /dev/null
+++ b/app/assets/images/illustrations/lock_promotion.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><circle cx="39" cy="45" r="37" fill="#F9F9F9"/><circle cx="39" cy="39" r="37" fill="#FFF"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M30 35a4 4 0 0 0-4 4v10a4 4 0 0 0 4 4h18a4 4 0 0 0 4-4V39a4 4 0 0 0-4-4H30zm0-4h18a8 8 0 0 1 8 8v10a8 8 0 0 1-8 8H30a8 8 0 0 1-8-8V39a8 8 0 0 1 8-8z"/><path fill="#6B4FBB" d="M33 29v2h-4v-2c0-5.523 4.477-10 10-10a9.996 9.996 0 0 1 10 10v2h-4v-2a5.997 5.997 0 0 0-6-6 6 6 0 0 0-6 6zm5 13.732a2 2 0 1 1 2 0V44a1 1 0 0 1-2 0v-1.268z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/milestone_removing-page.svg b/app/assets/images/illustrations/milestone_removing-page.svg
new file mode 100644
index 00000000000..a8cd54da0d3
--- /dev/null
+++ b/app/assets/images/illustrations/milestone_removing-page.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42C3.647 61.032 19.575 76 39 76c19.425 0 35.353-14.968 36.88-34 .08.99.12 1.99.12 3 0 20.435-16.565 37-37 37S2 65.435 2 45c0-1.01.04-2.01.12-3z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#FDE1D4" fill-rule="nonzero" d="M25.934 25.205a3 3 0 1 1 4.127 4.356A12.952 12.952 0 0 0 26 39c0 7.18 5.82 13 13 13s13-5.82 13-13c0-3.621-1.484-6.999-4.063-9.44a3 3 0 1 1 4.126-4.357A18.951 18.951 0 0 1 58 39c0 10.493-8.507 19-19 19s-19-8.507-19-19a18.951 18.951 0 0 1 5.934-13.795z"/><rect width="6" height="18" x="36" y="17" fill="#FA6D34" rx="3"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/activity.svg b/app/assets/images/illustrations/profile-page/activity.svg
new file mode 100644
index 00000000000..a0304479737
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/activity.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M10 71.092a3 3 0 0 0 3.413-1.047L22.308 58H66a6 6 0 0 0 6-6V19.528A5.985 5.985 0 0 1 74 24v33a6 6 0 0 1-6 6H24.308l-8.895 12.045A3 3 0 0 1 10 73.263v-2.17z"/><path fill="#EEE" fill-rule="nonzero" d="M20.699 56.812A2 2 0 0 1 22.308 56H66a4 4 0 0 0 4-4V19a4 4 0 0 0-4-4H14a4 4 0 0 0-4 4v49.263a1 1 0 0 0 1.804.594L20.7 56.812zM23.317 60l-8.295 11.233A5 5 0 0 1 6 68.263V19a8 8 0 0 1 8-8h52a8 8 0 0 1 8 8v33a8 8 0 0 1-8 8H23.317z"/><rect width="26" height="4" x="27" y="26" fill="#6B4FBB" rx="2"/><rect width="26" height="4" x="27" y="34" fill="#C3B8E3" rx="2"/><rect width="26" height="4" x="27" y="42" fill="#E1DBF1" rx="2"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/contributed-projects.svg b/app/assets/images/illustrations/profile-page/contributed-projects.svg
new file mode 100644
index 00000000000..023a7e3b956
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/contributed-projects.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M31.526 21.774c.152.38.266.78.339 1.198l.005.028h-.13l-.214-1.226zM69 30.682c.632.95 1 2.091 1 3.318v6.08c2.86 5.48 2.867 12.028 0 17.41v3.267l7.255 7.255a3 3 0 0 1 0 4.243l-1.414 1.414a3 3 0 0 1-4.243 0l-4.519-4.518c-.9.539-1.953.849-3.079.849H12a6 6 0 0 1-6-6v-1.682A5.994 5.994 0 0 0 11 65h52a6 6 0 0 0 6-6V30.682z"/><path fill="#EEE" fill-rule="nonzero" d="M31.74 25a2 2 0 0 1-1.971-1.657l-.875-5.028A4 4 0 0 0 24.954 15H11a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4h52a4 4 0 0 0 4-4V29a4 4 0 0 0-4-4H31.74zm1.681-4H63a8 8 0 0 1 8 8v30a8 8 0 0 1-8 8H11a8 8 0 0 1-8-8V19a8 8 0 0 1 8-8h13.953a8 8 0 0 1 7.882 6.63l.586 3.37z"/><path fill="#E1DBF1" d="M60.991 56.82l1.414-1.414a3 3 0 0 1 4.243 0l9.9 9.9a3 3 0 0 1 0 4.242l-1.415 1.414a3 3 0 0 1-4.242 0l-9.9-9.9a3 3 0 0 1 0-4.242z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M66.294 59.295c-7.224 7.225-18.938 7.225-26.163 0-7.224-7.225-7.224-18.938 0-26.163 7.225-7.225 18.939-7.225 26.163 0 7.225 7.225 7.225 18.938 0 26.163zm-4.95-4.95c4.492-4.49 4.492-11.772 0-16.263-4.49-4.491-11.772-4.491-16.263 0-4.49 4.49-4.49 11.772 0 16.263 4.491 4.491 11.773 4.491 16.264 0z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/groups.svg b/app/assets/images/illustrations/profile-page/groups.svg
new file mode 100644
index 00000000000..97aca4d69ee
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/groups.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M5 23v-2 2zm70 40v4a6 6 0 0 1-6 6H11a6 6 0 0 1-6-6v-4a6 6 0 0 0 6 6h58a6 6 0 0 0 6-6z"/><path stroke="#EEE" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M32.087 23H69a6 6 0 0 1 6 6v34a6 6 0 0 1-6 6H11a6 6 0 0 1-6-6V17a6 6 0 0 1 6-6h13.953a6 6 0 0 1 5.912 4.972L32.087 23z"/><path fill="#6B4FBB" d="M38 44v-7a2 2 0 1 1 4 0v7h7a2 2 0 1 1 0 4h-7v7a2 2 0 1 1-4 0v-7h-7a2 2 0 1 1 0-4h7z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/personal-project.svg b/app/assets/images/illustrations/profile-page/personal-project.svg
new file mode 100644
index 00000000000..3e8df10ed38
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/personal-project.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M67 66v5a6 6 0 0 1-6 6H19a6 6 0 0 1-6-6v-5a6 6 0 0 0 6 6h42a6 6 0 0 0 6-6z"/><path fill="#EEE" fill-rule="nonzero" d="M44 6v4H19a4 4 0 0 0-4 4v52a4 4 0 0 0 4 4h42a4 4 0 0 0 4-4V14a4.002 4.002 0 0 0-3-3.874V6.062c3.946.492 7 3.858 7 7.938v52a8 8 0 0 1-8 8H19a8 8 0 0 1-8-8V14a8 8 0 0 1 8-8h25z"/><path fill="#E1DBF1" d="M55.142 41.9l-5.657-5.657a2 2 0 1 1 2.829-2.829l7.07 7.071a2 2 0 0 1 0 2.829l-7.07 7.07a2 2 0 1 1-2.829-2.828l5.657-5.657zm-29.485 0l5.657 5.656a2 2 0 1 1-2.829 2.829l-7.07-7.071a2 2 0 0 1 0-2.829l7.07-7.07a2 2 0 1 1 2.829 2.828l-5.657 5.656z"/><path fill="#6B4FBB" d="M35 44a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm6 0a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm6 0a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/><path fill="#EFEDF8" d="M47 2h12a3 3 0 0 1 3 3v19.91a1.5 1.5 0 0 1-2.308 1.265l-5.81-3.714a1.5 1.5 0 0 0-1.605-.006l-5.98 3.753A1.5 1.5 0 0 1 44 24.937V5a3 3 0 0 1 3-3z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M48 20.416l2.15-1.35a5.5 5.5 0 0 1 5.886.025L58 20.346V6H48v14.416zM47 2h12a3 3 0 0 1 3 3v19.91a1.5 1.5 0 0 1-2.308 1.265l-5.81-3.714a1.5 1.5 0 0 0-1.605-.006l-5.98 3.753A1.5 1.5 0 0 1 44 24.937V5a3 3 0 0 1 3-3z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/personal-projects.svg b/app/assets/images/illustrations/profile-page/personal-projects.svg
new file mode 100644
index 00000000000..023a7e3b956
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/personal-projects.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M31.526 21.774c.152.38.266.78.339 1.198l.005.028h-.13l-.214-1.226zM69 30.682c.632.95 1 2.091 1 3.318v6.08c2.86 5.48 2.867 12.028 0 17.41v3.267l7.255 7.255a3 3 0 0 1 0 4.243l-1.414 1.414a3 3 0 0 1-4.243 0l-4.519-4.518c-.9.539-1.953.849-3.079.849H12a6 6 0 0 1-6-6v-1.682A5.994 5.994 0 0 0 11 65h52a6 6 0 0 0 6-6V30.682z"/><path fill="#EEE" fill-rule="nonzero" d="M31.74 25a2 2 0 0 1-1.971-1.657l-.875-5.028A4 4 0 0 0 24.954 15H11a4 4 0 0 0-4 4v40a4 4 0 0 0 4 4h52a4 4 0 0 0 4-4V29a4 4 0 0 0-4-4H31.74zm1.681-4H63a8 8 0 0 1 8 8v30a8 8 0 0 1-8 8H11a8 8 0 0 1-8-8V19a8 8 0 0 1 8-8h13.953a8 8 0 0 1 7.882 6.63l.586 3.37z"/><path fill="#E1DBF1" d="M60.991 56.82l1.414-1.414a3 3 0 0 1 4.243 0l9.9 9.9a3 3 0 0 1 0 4.242l-1.415 1.414a3 3 0 0 1-4.242 0l-9.9-9.9a3 3 0 0 1 0-4.242z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M66.294 59.295c-7.224 7.225-18.938 7.225-26.163 0-7.224-7.225-7.224-18.938 0-26.163 7.225-7.225 18.939-7.225 26.163 0 7.225 7.225 7.225 18.938 0 26.163zm-4.95-4.95c4.492-4.49 4.492-11.772 0-16.263-4.49-4.491-11.772-4.491-16.263 0-4.49 4.49-4.49 11.772 0 16.263 4.491 4.491 11.773 4.491 16.264 0z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/profile-page/snippets.svg b/app/assets/images/illustrations/profile-page/snippets.svg
new file mode 100644
index 00000000000..ef0275cede3
--- /dev/null
+++ b/app/assets/images/illustrations/profile-page/snippets.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none" fill-rule="evenodd"><path fill="#EEE" fill-rule="nonzero" d="M23 12a2 2 0 1 1 0-4h3a2 2 0 1 1 0 4h-3zm11 0a2 2 0 1 1 0-4h3a2 2 0 1 1 0 4h-3zm11 0a2 2 0 1 1 0-4h3a2 2 0 1 1 0 4h-3zm11 0a2 2 0 1 1 0-4h3a2 2 0 1 1 0 4h-3zm11 0a2 2 0 1 1 0-4c1.576 0 3.061.613 4.172 1.688a2 2 0 1 1-2.782 2.874A1.986 1.986 0 0 0 67 12zm2 6.877a2 2 0 1 1 4 0v3a2 2 0 1 1-4 0v-3zm0 11a2 2 0 1 1 4 0v3a2 2 0 1 1-4 0v-3zm0 11a2 2 0 1 1 4 0v3a2 2 0 1 1-4 0v-3zm0 11a2 2 0 1 1 4 0v3a2 2 0 1 1-4 0v-3zm-1.348 8.015a2 2 0 0 1 1.303 3.782 6.042 6.042 0 0 1-1.877.325L65.247 64a2 2 0 1 1-.002-4h1.794a1.99 1.99 0 0 0 .613-.108zM57.246 60a2 2 0 1 1 0 4h-3a2 2 0 1 1 0-4h3zm-11 0a2 2 0 1 1 0 4h-3a2 2 0 1 1 0-4h3zM21 32.369a2 2 0 1 1-4 0v-3a2 2 0 1 1 4 0v3zm0-11a2 2 0 1 1-4 0v-3a2 2 0 1 1 4 0v3z"/><g transform="rotate(30 -8.776 48.352)"><path fill="#E1DBF1" fill-rule="nonzero" d="M31.021 27.176l-1.732-3 4.365-7.561c2.01-3.48 2.455-6.572 1.81-9.285a9.09 9.09 0 0 0-.962-2.446c-.231-.4-.419-.655-.508-.756L25.85 18.222l-1.735-3.006 7.38-12.782c1.164-2.016 3.6-2.128 4.842-.18.205.25.472.628.761 1.129.542.937.99 2.024 1.283 3.252.823 3.457.264 7.335-2.13 11.48l-5.231 9.06zm-6.905 11.96L20.55 45.31l-10.357-5.98 7.018-12.155 1.733 3.002-4.653 8.055 5.161 2.98 2.932-5.077 1.732 3z"/><path fill="#6B4FBB" d="M8.282 54.601a8.96 8.96 0 1 1 8.96-15.519 8.96 8.96 0 0 1-8.96 15.52zm2.24-3.88a4.48 4.48 0 1 0 4.48-7.759 4.48 4.48 0 0 0-4.48 7.76z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M33.94 38.233L14.239 4.128c-.09.1-.277.357-.508.756a9.09 9.09 0 0 0-.962 2.446c-.646 2.713-.2 5.805 1.81 9.285l14.201 24.598 5.162-2.98zM11.134 3.383c.289-.501.555-.879.761-1.13 1.241-1.947 3.678-1.835 4.843.181l21.302 36.897-10.358 5.98L11.98 18.115c-2.393-4.145-2.952-8.023-2.13-11.48a12.075 12.075 0 0 1 1.284-3.252z"/><circle cx="24.39" cy="27.383" r="2.24" fill="#6B4FBB" transform="scale(-1 1) rotate(30 0 -63.642)"/><path fill="#6B4FBB" d="M39.95 54.602a8.96 8.96 0 1 1-8.96-15.52 8.96 8.96 0 0 1 8.96 15.52zm-2.24-3.88a4.48 4.48 0 1 0-4.48-7.76 4.48 4.48 0 0 0 4.48 7.76z"/></g></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/prometheus-graphs_empty.svg b/app/assets/images/illustrations/prometheus-graphs_empty.svg
new file mode 100644
index 00000000000..0ef198f59cd
--- /dev/null
+++ b/app/assets/images/illustrations/prometheus-graphs_empty.svg
@@ -0,0 +1 @@
+<svg width="430" height="267" viewBox="0 0 430 267" xmlns="http://www.w3.org/2000/svg"><title>prometheus-graphs_empty</title><g fill="none" fill-rule="evenodd"><path d="M187 43a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm18 0a2 2 0 0 1 0-4h8a2 2 0 0 1 0 4h-8zm15.769 2.457a2 2 0 0 1 2.883-2.772A11.964 11.964 0 0 1 335 51v.39a2 2 0 0 1-4 0V51a7.965 7.965 0 0 0-2.231-5.543zm2.225 159.857a2 2 0 0 1 3.997.154 11.973 11.973 0 0 1-4.02 8.503 2 2 0 0 1-2.658-2.99 7.974 7.974 0 0 0 2.681-5.667zM320.218 213a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zm-18 0a2 2 0 1 1 0 4h-8a2 2 0 0 1 0-4h8zM89 155.827a2 2 0 1 1-4 0v-8a2 2 0 0 1 4 0v8zm0-18a2 2 0 1 1-4 0v-8a2 2 0 0 1 4 0v8z" fill="#EEE" fill-rule="nonzero"/><path d="M175.116 125.116A10.002 10.002 0 0 1 166 131H54c-5.523 0-10-4.477-10-10V31a10 10 0 0 1 5.884-9.116A9.964 9.964 0 0 0 49 26v90c0 5.523 4.477 10 10 10h112c1.467 0 2.86-.316 4.116-.884z" fill="#F9F9F9"/><path d="M59 20a6 6 0 0 0-6 6v90a6 6 0 0 0 6 6h112a6 6 0 0 0 6-6V26a6 6 0 0 0-6-6H59zm0-4h112c5.523 0 10 4.477 10 10v90c0 5.523-4.477 10-10 10H59c-5.523 0-10-4.477-10-10V26c0-5.523 4.477-10 10-10z" fill="#EEE" fill-rule="nonzero"/><path d="M73 58h4a3 3 0 0 1 3 3v45H70V61a3 3 0 0 1 3-3z" fill="#EFEDF8"/><path d="M93 70h4a3 3 0 0 1 3 3v33H90V73a3 3 0 0 1 3-3z" fill="#E1DBF1"/><path d="M153 70h4a3 3 0 0 1 3 3v33h-10V73a3 3 0 0 1 3-3z" fill="#C3B8E3"/><path d="M133 89h4a3 3 0 0 1 3 3v14h-10V92a3 3 0 0 1 3-3z" fill="#EFEDF8"/><path d="M113 46h4a3 3 0 0 1 3 3v57h-10V49a3 3 0 0 1 3-3z" fill="#6B4FBB"/><path d="M385.4 191.418A10.004 10.004 0 0 1 376 198H221c-5.523 0-10-4.477-10-10V74a9.992 9.992 0 0 1 4.6-8.418A9.981 9.981 0 0 0 215 69v114c0 5.523 4.477 10 10 10h155c1.99 0 3.843-.58 5.4-1.582z" fill="#F9F9F9" opacity=".99"/><path d="M225 63a6 6 0 0 0-6 6v114a6 6 0 0 0 6 6h155a6 6 0 0 0 6-6V69a6 6 0 0 0-6-6H225zm0-4h155c5.523 0 10 4.477 10 10v114c0 5.523-4.477 10-10 10H225c-5.523 0-10-4.477-10-10V69c0-5.523 4.477-10 10-10z" fill="#EEE" fill-rule="nonzero"/><g transform="translate(238 92)"><path d="M44.584 31.917L28.808 49.434a2 2 0 0 1-2.695.255L3.791 32.749a2 2 0 0 1 2.418-3.186l20.858 15.828 15.966-17.73a2 2 0 0 1 2.912-.064l16.09 16.344L77.35.058c.641-1.838 3.263-1.77 3.808.098l19.827 67.92 22.3-37.106a2 2 0 0 1 3.43 2.06l-24.656 41.024c-.898 1.494-3.145 1.204-3.634-.47L79.07 7.273l-14.315 41.02a2 2 0 0 1-3.314.745L44.584 31.917z" fill="#FEF0E8" fill-rule="nonzero"/><circle fill="#FEE1D3" cx="100" cy="71" r="4"/><circle fill="#FDC4A8" cx="44" cy="30" r="4"/><circle stroke="#FC6D26" stroke-width="4" fill="#FFF" cx="5" cy="32" r="5"/><circle stroke="#FC6D26" stroke-width="4" fill="#FFF" cx="125" cy="32" r="5"/></g><path d="M80.41 166.41C72.69 175.07 68 186.486 68 199c0 27.062 21.938 49 49 49 12.513 0 23.93-4.69 32.59-12.41C140.618 245.66 127.55 252 113 252c-27.062 0-49-21.938-49-49 0-14.549 6.34-27.617 16.41-36.59z" fill="#F9F9F9"/><path d="M117 244c24.853 0 45-20.147 45-45s-20.147-45-45-45-45 20.147-45 45 20.147 45 45 45zm0 4c-27.062 0-49-21.938-49-49s21.938-49 49-49 49 21.938 49 49-21.938 49-49 49z" fill="#EEE" fill-rule="nonzero"/><path d="M117 223c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zm0-12c6.627 0 12-5.373 12-12s-5.373-12-12-12-12 5.373-12 12 5.373 12 12 12z" fill="#FEF0E8"/><path d="M117 175c13.255 0 24 10.745 24 24 0 .674-.028 1.34-.082 2h-12.084c.11-.65.166-1.319.166-2 0-6.627-5.373-12-12-12v-12z" fill="#FDC4A8"/></g></svg> \ No newline at end of file
diff --git a/app/assets/images/illustrations/web-ide_promotion.svg b/app/assets/images/illustrations/web-ide_promotion.svg
new file mode 100644
index 00000000000..ef61348057d
--- /dev/null
+++ b/app/assets/images/illustrations/web-ide_promotion.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="114" height="88" viewBox="0 0 114 88"><g fill="none" fill-rule="evenodd"><rect width="110" height="80" x="2" y="8" fill="#F9F9F9" rx="10"/><path fill="#FFF" d="M12 2h90c5.523 0 10 4.477 10 10v60c0 5.523-4.477 10-10 10H12C6.477 82 2 77.523 2 72V12C2 6.477 6.477 2 12 2z"/><path fill="#EEE" fill-rule="nonzero" d="M33 4v4.255A6.968 6.968 0 0 1 37 7h19a6.98 6.98 0 0 1 4.899 2H75a7 7 0 0 1 7 7v2h28v-6a8 8 0 0 0-8-8H33zm-3 0H12a8 8 0 0 0-8 8v60a8 8 0 0 0 8 8h18V4zm48 14v-2a3 3 0 0 0-3-3H62.93c.046.327.07.66.07 1v4h15zM12 0h90c6.627 0 12 5.373 12 12v60c0 6.627-5.373 12-12 12H12C5.373 84 0 78.627 0 72V12C0 5.373 5.373 0 12 0zm98 22H61a2 2 0 0 1-2-2v-6a3 3 0 0 0-3-3H37a3 3 0 0 0-3 3v66h68a8 8 0 0 0 8-8V22z"/><path fill="#EFEDF8" d="M52 36h40a2 2 0 1 1 0 4H52a2 2 0 1 1 0-4z"/><path fill="#E1DBF2" d="M52 46h30a2 2 0 1 1 0 4H52a2 2 0 1 1 0-4z"/><path fill="#EFEDF8" d="M52 56h40a2 2 0 1 1 0 4H52a2 2 0 1 1 0-4z"/><path fill="#E1DBF2" d="M52 66h30a2 2 0 1 1 0 4H52a2 2 0 1 1 0-4zM10 16h14a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4zm0 10h10a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/><path fill="#EFEDF8" d="M10 36h14a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/><path fill="#6B4FBB" d="M10 46h10a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/><path fill="#E1DBF2" d="M10 56h14a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/><path fill="#EFEDF8" d="M10 66h10a2 2 0 1 1 0 4H10a2 2 0 1 1 0-4z"/></g></svg> \ No newline at end of file
diff --git a/app/assets/javascripts/behaviors/quick_submit.js b/app/assets/javascripts/behaviors/quick_submit.js
index 312edc0cd69..51bd5b8ebe5 100644
--- a/app/assets/javascripts/behaviors/quick_submit.js
+++ b/app/assets/javascripts/behaviors/quick_submit.js
@@ -72,5 +72,5 @@ $(document).on('keyup.quick_submit', '.js-quick-submit input[type=submit], .js-q
title,
trigger: 'manual',
});
- $this.tooltip('show').one('blur', () => $this.tooltip('hide'));
+ $this.tooltip('show').one('blur click', () => $this.tooltip('hide'));
});
diff --git a/app/assets/javascripts/behaviors/toggler_behavior.js b/app/assets/javascripts/behaviors/toggler_behavior.js
index 417ac31fc86..81c89441424 100644
--- a/app/assets/javascripts/behaviors/toggler_behavior.js
+++ b/app/assets/javascripts/behaviors/toggler_behavior.js
@@ -12,7 +12,7 @@ $(() => {
const $container = $(container);
$container
- .find('.js-toggle-button .fa')
+ .find('.js-toggle-button .fa-chevron-up, .js-toggle-button .fa-chevron-down')
.toggleClass('fa-chevron-up', toggleState)
.toggleClass('fa-chevron-down', toggleState !== undefined ? !toggleState : undefined);
@@ -22,7 +22,7 @@ $(() => {
}
$('body').on('click', '.js-toggle-button', function toggleButton(e) {
- e.target.classList.toggle('open');
+ e.currentTarget.classList.toggle(e.currentTarget.dataset.toggleOpenClass || 'open');
toggleContainer($(this).closest('.js-toggle-container'));
const targetTag = e.currentTarget.tagName.toLowerCase();
diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue
index 23fec503586..84885ca9306 100644
--- a/app/assets/javascripts/boards/components/board_card.vue
+++ b/app/assets/javascripts/boards/components/board_card.vue
@@ -1,4 +1,5 @@
<script>
+/* eslint-disable vue/require-default-prop */
import './issue_card_inner';
import eventHub from '../eventhub';
@@ -34,6 +35,9 @@ export default {
type: String,
default: '',
},
+ groupId: {
+ type: Number,
+ },
},
data() {
return {
@@ -88,6 +92,7 @@ export default {
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
+ :group-id="groupId"
:root-path="rootPath"
:update-filters="true"
/>
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index 6637904d87d..0d03c1c419c 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -15,6 +15,11 @@ export default {
loadingIcon,
},
props: {
+ groupId: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
disabled: {
type: Boolean,
required: true,
@@ -170,6 +175,7 @@ export default {
<loading-icon />
</div>
<board-new-issue
+ :group-id="groupId"
:list="list"
v-if="list.type !== 'closed' && showIssueForm"/>
<ul
@@ -185,6 +191,7 @@ export default {
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
+ :group-id="groupId"
:root-path="rootPath"
:disabled="disabled"
:key="issue.id" />
diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue
index efface7143d..870d242e774 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue.vue
@@ -1,12 +1,21 @@
<script>
import eventHub from '../eventhub';
+import ProjectSelect from './project_select.vue';
import ListIssue from '../models/issue';
const Store = gl.issueBoards.BoardsStore;
export default {
name: 'BoardNewIssue',
+ components: {
+ ProjectSelect,
+ },
props: {
+ groupId: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
list: {
type: Object,
required: true,
@@ -16,10 +25,20 @@ export default {
return {
title: '',
error: false,
+ selectedProject: {},
};
},
+ computed: {
+ disabled() {
+ if (this.groupId) {
+ return this.title === '' || !this.selectedProject.name;
+ }
+ return this.title === '';
+ },
+ },
mounted() {
this.$refs.input.focus();
+ eventHub.$on('setSelectedProject', this.setSelectedProject);
},
methods: {
submit(e) {
@@ -34,6 +53,7 @@ export default {
labels,
subscribed: true,
assignees: [],
+ project_id: this.selectedProject.id,
});
eventHub.$emit(`scroll-board-list-${this.list.id}`);
@@ -62,52 +82,62 @@ export default {
this.title = '';
eventHub.$emit(`hide-issue-form-${this.list.id}`);
},
+ setSelectedProject(selectedProject) {
+ this.selectedProject = selectedProject;
+ },
},
};
</script>
<template>
- <div class="card board-new-issue-form">
- <form @submit="submit($event)">
- <div
- class="flash-container"
- v-if="error"
- >
- <div class="flash-alert">
- An error occurred. Please try again.
- </div>
- </div>
- <label
- class="label-light"
- :for="list.id + '-title'"
- >
- Title
- </label>
- <input
- class="form-control"
- type="text"
- v-model="title"
- ref="input"
- autocomplete="off"
- :id="list.id + '-title'"
- />
- <div class="clearfix prepend-top-10">
- <button
- class="btn btn-success pull-left"
- type="submit"
- :disabled="title === ''"
- ref="submit-button"
+ <div class="board-new-issue-form">
+ <div class="card">
+ <form @submit="submit($event)">
+ <div
+ class="flash-container"
+ v-if="error"
>
- Submit issue
- </button>
- <button
- class="btn btn-default pull-right"
- type="button"
- @click="cancel"
+ <div class="flash-alert">
+ An error occurred. Please try again.
+ </div>
+ </div>
+ <label
+ class="label-light"
+ :for="list.id + '-title'"
>
- Cancel
- </button>
- </div>
- </form>
+ Title
+ </label>
+ <input
+ class="form-control"
+ type="text"
+ v-model="title"
+ ref="input"
+ autocomplete="off"
+ :id="list.id + '-title'"
+ />
+ <project-select
+ v-if="groupId"
+ :group-id="groupId"
+ />
+ <div class="clearfix prepend-top-10">
+ <button
+ class="btn btn-success pull-left"
+ type="submit"
+ :disabled="disabled"
+ ref="submit-button"
+ >
+ Submit issue
+ </button>
+ <button
+ class="btn btn-default pull-right"
+ type="button"
+ @click="cancel"
+ >
+ Cancel
+ </button>
+ </div>
+ </form>
+ </div>
</div>
</template>
+
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js
index bf474879024..fc2bad2415f 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner.js
+++ b/app/assets/javascripts/boards/components/issue_card_inner.js
@@ -31,6 +31,10 @@ gl.issueBoards.IssueCardInner = Vue.extend({
required: false,
default: false,
},
+ groupId: {
+ type: Number,
+ required: false,
+ },
},
data() {
return {
@@ -64,7 +68,13 @@ gl.issueBoards.IssueCardInner = Vue.extend({
return this.issue.assignees.length > this.numberOverLimit;
},
cardUrl() {
- return `${this.issueLinkBase}/${this.issue.iid}`;
+ let baseUrl = this.issueLinkBase;
+
+ if (this.groupId && this.issue.project) {
+ baseUrl = this.issueLinkBase.replace(':project_path', this.issue.project.path);
+ }
+
+ return `${baseUrl}/${this.issue.iid}`;
},
issueId() {
if (this.issue.iid) {
@@ -148,7 +158,7 @@ gl.issueBoards.IssueCardInner = Vue.extend({
class="card-number"
v-if="issueId"
>
- {{ issueId }}
+ <template v-if="groupId && issue.project">{{issue.project.path}}</template>{{ issueId }}
</span>
</h4>
<div class="card-assignee">
diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue
new file mode 100644
index 00000000000..d99b222c305
--- /dev/null
+++ b/app/assets/javascripts/boards/components/project_select.vue
@@ -0,0 +1,127 @@
+<script>
+ /* global ListIssue */
+ import _ from 'underscore';
+ import eventHub from '../eventhub';
+ import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+ import Api from '../../api';
+
+ export default {
+ name: 'BoardProjectSelect',
+ components: {
+ loadingIcon,
+ },
+ props: {
+ groupId: {
+ type: Number,
+ required: true,
+ default: 0,
+ },
+ },
+ data() {
+ return {
+ loading: true,
+ selectedProject: {},
+ };
+ },
+ computed: {
+ selectedProjectName() {
+ return this.selectedProject.name || 'Select a project';
+ },
+ },
+ mounted() {
+ $(this.$refs.projectsDropdown).glDropdown({
+ filterable: true,
+ filterRemote: true,
+ search: {
+ fields: ['name_with_namespace'],
+ },
+ clicked: ({ $el, e }) => {
+ e.preventDefault();
+ this.selectedProject = {
+ id: $el.data('project-id'),
+ name: $el.data('project-name'),
+ };
+ eventHub.$emit('setSelectedProject', this.selectedProject);
+ },
+ selectable: true,
+ data: (term, callback) => {
+ this.loading = true;
+ return Api.groupProjects(this.groupId, term, (projects) => {
+ this.loading = false;
+ callback(projects);
+ });
+ },
+ renderRow(project) {
+ return `
+ <li>
+ <a href='#' class='dropdown-menu-link' data-project-id="${project.id}" data-project-name="${project.name}">
+ ${_.escape(project.name)}
+ </a>
+ </li>
+ `;
+ },
+ text: project => project.name,
+ });
+ },
+ };
+</script>
+
+<template>
+ <div>
+ <label class="label-light prepend-top-10">
+ Project
+ </label>
+ <div
+ ref="projectsDropdown"
+ class="dropdown"
+ >
+ <button
+ class="dropdown-menu-toggle wide"
+ type="button"
+ data-toggle="dropdown"
+ aria-expanded="false"
+ >
+ {{ selectedProjectName }}
+ <i
+ class="fa fa-chevron-down"
+ aria-hidden="true"
+ >
+ </i>
+ </button>
+ <div class="dropdown-menu dropdown-menu-selectable dropdown-menu-full-width">
+ <div class="dropdown-title">
+ <span>Projects</span>
+ <button
+ aria-label="Close"
+ type="button"
+ class="dropdown-title-button dropdown-menu-close"
+ >
+ <i
+ aria-hidden="true"
+ data-hidden="true"
+ class="fa fa-times dropdown-menu-close-icon"
+ >
+ </i>
+ </button>
+ </div>
+ <div class="dropdown-input">
+ <input
+ class="dropdown-input-field"
+ type="search"
+ placeholder="Search projects"
+ />
+ <i
+ aria-hidden="true"
+ data-hidden="true"
+ class="fa fa-search dropdown-input-search"
+ >
+ </i>
+ </div>
+ <div class="dropdown-content"></div>
+ <div class="dropdown-loading">
+ <loading-icon />
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/boards/components/sidebar/remove_issue.js b/app/assets/javascripts/boards/components/sidebar/remove_issue.js
index 0ae32bb4d0a..09c683ff621 100644
--- a/app/assets/javascripts/boards/components/sidebar/remove_issue.js
+++ b/app/assets/javascripts/boards/components/sidebar/remove_issue.js
@@ -24,7 +24,7 @@ gl.issueBoards.RemoveIssueBtn = Vue.extend({
},
computed: {
updateUrl() {
- return this.issueUpdate;
+ return this.issueUpdate.replace(':project_path', this.issue.project.path);
},
},
methods: {
@@ -32,17 +32,21 @@ gl.issueBoards.RemoveIssueBtn = Vue.extend({
const issue = this.issue;
const lists = issue.getLists();
const listLabelIds = lists.map(list => list.label.id);
- let labelIds = this.issue.labels
+
+ let labelIds = issue.labels
.map(label => label.id)
.filter(id => !listLabelIds.includes(id));
if (labelIds.length === 0) {
labelIds = [''];
}
+
const data = {
issue: {
label_ids: labelIds,
},
};
+
+ // Post the remove data
Vue.http.patch(this.updateUrl, data).catch(() => {
Flash(__('Failed to remove issue from board, please try again.'));
diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js
index 57a7cc4ca30..fb40b9f5565 100644
--- a/app/assets/javascripts/boards/filtered_search_boards.js
+++ b/app/assets/javascripts/boards/filtered_search_boards.js
@@ -6,6 +6,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
constructor(store, updateUrl = false, cantEdit = []) {
super({
page: 'boards',
+ stateFiltersSelector: '.issues-state-filters',
});
this.store = store;
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index 8e31f1865f0..efc0da2e7a2 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -5,14 +5,15 @@ import Vue from 'vue';
import Flash from '~/flash';
import { __ } from '~/locale';
+import '~/vue_shared/models/label';
import FilteredSearchBoards from './filtered_search_boards';
import eventHub from './eventhub';
import sidebarEventHub from '~/sidebar/event_hub'; // eslint-disable-line import/first
import './models/issue';
-import './models/label';
import './models/list';
import './models/milestone';
+import './models/project';
import './models/assignee';
import './stores/boards_store';
import './stores/modal_store';
@@ -89,7 +90,7 @@ export default () => {
sidebarEventHub.$off('toggleSubscription', this.toggleSubscription);
},
mounted () {
- this.filterManager = new FilteredSearchBoards(Store.filter, true);
+ this.filterManager = new FilteredSearchBoards(Store.filter, true, Store.cantEdit);
this.filterManager.setup();
Store.disabled = this.disabled;
@@ -179,6 +180,7 @@ export default () => {
return {
modal: ModalStore.store,
store: Store.state,
+ canAdminList: this.$options.el.hasAttribute('data-can-admin-list'),
};
},
computed: {
@@ -232,6 +234,7 @@ export default () => {
:class="{ 'disabled': disabled }"
:title="tooltipTitle"
:aria-disabled="disabled"
+ v-if="canAdminList"
@click="openModal">
Add issues
</button>
diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js b/app/assets/javascripts/boards/mixins/sortable_default_options.js
index 38a0eb12f92..5e31c6314b2 100644
--- a/app/assets/javascripts/boards/mixins/sortable_default_options.js
+++ b/app/assets/javascripts/boards/mixins/sortable_default_options.js
@@ -1,6 +1,8 @@
/* eslint-disable no-unused-vars, no-mixed-operators, comma-dangle */
/* global DocumentTouch */
+import sortableConfig from '../../sortable/sortable_config';
+
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
@@ -18,19 +20,14 @@ gl.issueBoards.onEnd = () => {
gl.issueBoards.touchEnabled = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
gl.issueBoards.getBoardSortableDefaultOptions = (obj) => {
- const defaultSortOptions = {
- animation: 200,
- forceFallback: true,
- fallbackClass: 'is-dragging',
- fallbackOnBody: true,
- ghostClass: 'is-ghost',
+ const defaultSortOptions = Object.assign({}, sortableConfig, {
filter: '.board-delete, .btn',
delay: gl.issueBoards.touchEnabled ? 100 : 0,
scrollSensitivity: gl.issueBoards.touchEnabled ? 60 : 100,
scrollSpeed: 20,
onStart: gl.issueBoards.onStart,
- onEnd: gl.issueBoards.onEnd
- };
+ onEnd: gl.issueBoards.onEnd,
+ });
Object.keys(obj).forEach((key) => { defaultSortOptions[key] = obj[key]; });
return defaultSortOptions;
diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js
index 3bfb6d39ad5..4c5079efc8b 100644
--- a/app/assets/javascripts/boards/models/issue.js
+++ b/app/assets/javascripts/boards/models/issue.js
@@ -4,6 +4,7 @@
/* global ListAssignee */
import Vue from 'vue';
+import IssueProject from './project';
class ListIssue {
constructor (obj, defaultAvatar) {
@@ -23,6 +24,12 @@ class ListIssue {
this.isLoading = {};
this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
+ this.milestone_id = obj.milestone_id;
+ this.project_id = obj.project_id;
+
+ if (obj.project) {
+ this.project = new IssueProject(obj.project);
+ }
if (obj.milestone) {
this.milestone = new ListMilestone(obj.milestone);
@@ -105,7 +112,8 @@ class ListIssue {
data.issue.label_ids = [''];
}
- return Vue.http.patch(url, data);
+ const projectPath = this.project ? this.project.path : '';
+ return Vue.http.patch(url.replace(':project_path', projectPath), data);
}
}
diff --git a/app/assets/javascripts/boards/models/project.js b/app/assets/javascripts/boards/models/project.js
new file mode 100644
index 00000000000..a3d5c7af7ac
--- /dev/null
+++ b/app/assets/javascripts/boards/models/project.js
@@ -0,0 +1,6 @@
+export default class IssueProject {
+ constructor(obj) {
+ this.id = obj.id;
+ this.path = obj.path;
+ }
+}
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index 1325a268214..f8dcdf3f60a 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -117,7 +117,10 @@
</script>
<template>
- <section class="settings no-animate expanded">
+ <section
+ id="cluster-applications"
+ class="settings no-animate expanded"
+ >
<div class="settings-header">
<h4>
{{ s__('ClusterIntegration|Applications') }}
@@ -183,7 +186,7 @@
<clipboard-button
:text="ingressExternalIp"
:title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')"
- css-class="btn btn-default js-clipboard-btn"
+ class="js-clipboard-btn"
/>
</span>
</div>
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
index ce19069f103..466a5b5d635 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue
+++ b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
@@ -20,10 +20,6 @@
type: String,
required: true,
},
- emptyStateSvgPath: {
- type: String,
- required: true,
- },
errorStateSvgPath: {
type: String,
required: true,
@@ -45,23 +41,14 @@
},
computed: {
- /**
- * Empty state is only rendered if after the first request we receive no pipelines.
- *
- * @return {Boolean}
- */
- shouldRenderEmptyState() {
- return !this.state.pipelines.length &&
- !this.isLoading &&
- this.hasMadeRequest &&
- !this.hasError;
- },
-
shouldRenderTable() {
return !this.isLoading &&
this.state.pipelines.length > 0 &&
!this.hasError;
},
+ shouldRenderErrorState() {
+ return this.hasError && !this.isLoading;
+ },
},
created() {
this.service = new PipelinesService(this.endpoint);
@@ -92,25 +79,22 @@
<div class="content-list pipelines">
<loading-icon
- label="Loading pipelines"
+ :label="s__('Pipelines|Loading Pipelines')"
size="3"
v-if="isLoading"
+ class="prepend-top-20"
/>
- <empty-state
- v-if="shouldRenderEmptyState"
- :help-page-path="helpPagePath"
- :empty-state-svg-path="emptyStateSvgPath"
- />
-
- <error-state
- v-if="shouldRenderErrorState"
- :error-state-svg-path="errorStateSvgPath"
+ <svg-blank-state
+ v-else-if="shouldRenderErrorState"
+ :svg-path="errorStateSvgPath"
+ :message="s__(`Pipelines|There was an error fetching the pipelines.
+ Try again in a few moments or contact your support team.`)"
/>
<div
class="table-holder"
- v-if="shouldRenderTable"
+ v-else-if="shouldRenderTable"
>
<pipelines-table-component
:pipelines="state.pipelines"
diff --git a/app/assets/javascripts/commons/vue.js b/app/assets/javascripts/commons/vue.js
index 8b62d78c043..798623b94fb 100644
--- a/app/assets/javascripts/commons/vue.js
+++ b/app/assets/javascripts/commons/vue.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import '../vue_shared/vue_resource_interceptor';
if (process.env.NODE_ENV !== 'production') {
Vue.config.productionTip = false;
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue
index b8f0566f48c..0578f43d5af 100644
--- a/app/assets/javascripts/groups/components/app.vue
+++ b/app/assets/javascripts/groups/components/app.vue
@@ -152,14 +152,14 @@ export default {
showLeaveGroupModal(group, parentGroup) {
this.targetGroup = group;
this.targetParentGroup = parentGroup;
- this.updateModal = true;
+ this.showModal = true;
this.groupLeaveConfirmationMessage = s__(`GroupsTree|Are you sure you want to leave the "${group.fullName}" group?`);
},
hideLeaveGroupModal() {
- this.updateModal = false;
+ this.showModal = false;
},
leaveGroup() {
- this.updateModal = false;
+ this.showModal = false;
this.targetGroup.isBeingRemoved = true;
this.service.leaveGroup(this.targetGroup.leavePath)
.then(res => res.json())
@@ -208,9 +208,9 @@ export default {
:page-info="pageInfo"
/>
<modal
- v-show="showModal"
- :primary-button-label="__('Leave')"
+ v-if="showModal"
kind="warning"
+ :primary-button-label="__('Leave')"
:title="__('Are you sure?')"
:text="groupLeaveConfirmationMessage"
@cancel="hideLeaveGroupModal"
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index 35094f8e73b..523bd2adb93 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -1,11 +1,14 @@
-import { __ } from './locale';
+import _ from 'underscore';
+import { __, sprintf } from './locale';
import axios from './lib/utils/axios_utils';
import flash from './flash';
+import { convertPermissionToBoolean } from './lib/utils/common_utils';
class ImporterStatus {
- constructor(jobsUrl, importUrl) {
+ constructor({ jobsUrl, importUrl, ciCdOnly }) {
this.jobsUrl = jobsUrl;
this.importUrl = importUrl;
+ this.ciCdOnly = ciCdOnly;
this.initStatusPage();
this.setAutoUpdate();
}
@@ -45,6 +48,7 @@ class ImporterStatus {
repo_id: id,
target_namespace: targetNamespace,
new_name: newName,
+ ci_cd_only: this.ciCdOnly,
})
.then(({ data }) => {
const job = $(`tr#repo_${id}`);
@@ -54,7 +58,13 @@ class ImporterStatus {
$('table.import-jobs tbody').prepend(job);
job.addClass('active');
- job.find('.import-actions').html('<i class="fa fa-spinner fa-spin" aria-label="importing"></i> started');
+ const connectingVerb = this.ciCdOnly ? __('connecting') : __('importing');
+ job.find('.import-actions').html(sprintf(
+ _.escape(__('%{loadingIcon} Started')), {
+ loadingIcon: `<i class="fa fa-spinner fa-spin" aria-label="${_.escape(connectingVerb)}"></i>`,
+ },
+ false,
+ ));
})
.catch(() => flash(__('An error occurred while importing project')));
}
@@ -71,13 +81,16 @@ class ImporterStatus {
switch (job.import_status) {
case 'finished':
jobItem.removeClass('active').addClass('success');
- statusField.html('<span><i class="fa fa-check"></i> done</span>');
+ statusField.html(`<span><i class="fa fa-check"></i> ${__('Done')}</span>`);
break;
case 'scheduled':
- statusField.html(`${spinner} scheduled`);
+ statusField.html(`${spinner} ${__('Scheduled')}`);
break;
case 'started':
- statusField.html(`${spinner} started`);
+ statusField.html(`${spinner} ${__('Started')}`);
+ break;
+ case 'failed':
+ statusField.html(__('Failed'));
break;
default:
statusField.html(job.import_status);
@@ -98,7 +111,11 @@ function initImporterStatus() {
if (importerStatus) {
const data = importerStatus.dataset;
- return new ImporterStatus(data.jobsImportPath, data.importPath);
+ return new ImporterStatus({
+ jobsUrl: data.jobsImportPath,
+ importUrl: data.importPath,
+ ciCdOnly: convertPermissionToBoolean(data.ciCdOnly),
+ });
}
}
diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js
index 2841ecb558b..c259d5405bd 100644
--- a/app/assets/javascripts/milestone_select.js
+++ b/app/assets/javascripts/milestone_select.js
@@ -216,6 +216,9 @@ export default class MilestoneSelect {
$value.html(milestoneLinkNoneTemplate);
return $sidebarCollapsedValue.find('span').text('No');
}
+ })
+ .catch(() => {
+ $loading.fadeOut();
});
}
}
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 031badc7026..8ca94ef3e2a 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -7,34 +7,82 @@
import EmptyState from './empty_state.vue';
import MonitoringStore from '../stores/monitoring_store';
import eventHub from '../event_hub';
- import { convertPermissionToBoolean } from '../../lib/utils/common_utils';
export default {
-
components: {
Graph,
GraphGroup,
EmptyState,
},
- data() {
- const metricsData = document.querySelector('#prometheus-graphs').dataset;
- const store = new MonitoringStore();
+ props: {
+ hasMetrics: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ showLegend: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ showPanels: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ forceSmallGraph: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ documentationPath: {
+ type: String,
+ required: true,
+ },
+ settingsPath: {
+ type: String,
+ required: true,
+ },
+ clustersPath: {
+ type: String,
+ required: true,
+ },
+ tagsPath: {
+ type: String,
+ required: true,
+ },
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ metricsEndpoint: {
+ type: String,
+ required: true,
+ },
+ deploymentEndpoint: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ emptyGettingStartedSvgPath: {
+ type: String,
+ required: true,
+ },
+ emptyLoadingSvgPath: {
+ type: String,
+ required: true,
+ },
+ emptyUnableToConnectSvgPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
return {
- store,
+ store: new MonitoringStore(),
state: 'gettingStarted',
- hasMetrics: convertPermissionToBoolean(metricsData.hasMetrics),
- documentationPath: metricsData.documentationPath,
- settingsPath: metricsData.settingsPath,
- clustersPath: metricsData.clustersPath,
- tagsPath: metricsData.tagsPath,
- projectPath: metricsData.projectPath,
- metricsEndpoint: metricsData.additionalMetrics,
- deploymentEndpoint: metricsData.deploymentEndpoint,
- emptyGettingStartedSvgPath: metricsData.emptyGettingStartedSvgPath,
- emptyLoadingSvgPath: metricsData.emptyLoadingSvgPath,
- emptyUnableToConnectSvgPath: metricsData.emptyUnableToConnectSvgPath,
showEmptyState: true,
updateAspectRatio: false,
updatedAspectRatios: 0,
@@ -67,6 +115,7 @@
window.addEventListener('resize', this.resizeThrottled, false);
}
},
+
methods: {
getGraphsData() {
this.state = 'loading';
@@ -115,6 +164,7 @@
v-for="(groupData, index) in store.groups"
:key="index"
:name="groupData.group"
+ :show-panels="showPanels"
>
<graph
v-for="(graphData, index) in groupData.metrics"
@@ -125,6 +175,8 @@
:deployment-data="store.deploymentData"
:project-path="projectPath"
:tags-path="tagsPath"
+ :show-legend="showLegend"
+ :small-graph="forceSmallGraph"
/>
</graph-group>
</div>
diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue
index ea5c24efaf9..9e67a6f2146 100644
--- a/app/assets/javascripts/monitoring/components/graph.vue
+++ b/app/assets/javascripts/monitoring/components/graph.vue
@@ -52,6 +52,16 @@
type: String,
required: true,
},
+ showLegend: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ smallGraph: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
@@ -130,7 +140,7 @@
const breakpointSize = bp.getBreakpointSize();
const query = this.graphData.queries[0];
this.margin = measurements.large.margin;
- if (breakpointSize === 'xs' || breakpointSize === 'sm') {
+ if (this.smallGraph || breakpointSize === 'xs' || breakpointSize === 'sm') {
this.graphHeight = 300;
this.margin = measurements.small.margin;
this.measurements = measurements.small;
@@ -182,7 +192,9 @@
this.graphHeightOffset,
);
- if (this.timeSeries.length > 3) {
+ if (!this.showLegend) {
+ this.baseGraphHeight -= 50;
+ } else if (this.timeSeries.length > 3) {
this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20;
}
@@ -255,6 +267,7 @@
:time-series="timeSeries"
:unit-of-display="unitOfDisplay"
:current-data-index="currentDataIndex"
+ :show-legend-group="showLegend"
/>
<svg
class="graph-data"
diff --git a/app/assets/javascripts/monitoring/components/graph/legend.vue b/app/assets/javascripts/monitoring/components/graph/legend.vue
index c6e8d726ffc..3149397b61f 100644
--- a/app/assets/javascripts/monitoring/components/graph/legend.vue
+++ b/app/assets/javascripts/monitoring/components/graph/legend.vue
@@ -39,6 +39,11 @@
type: Number,
required: true,
},
+ showLegendGroup: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
@@ -57,8 +62,9 @@
},
rectTransform() {
- const yCoordinate = ((this.graphHeight - this.margin.top) / 2)
- + (this.yLabelWidth / 2) + 10 || 0;
+ const yCoordinate = (((this.graphHeight - this.margin.top)
+ + this.measurements.axisLabelLineOffset) / 2)
+ + (this.yLabelWidth / 2) || 0;
return `translate(0, ${yCoordinate}) rotate(-90)`;
},
@@ -166,39 +172,41 @@
>
Time
</text>
- <g
- class="legend-group"
- v-for="(series, index) in timeSeries"
- :key="index"
- :transform="translateLegendGroup(index)"
- >
- <line
- :stroke="series.lineColor"
- :stroke-width="measurements.legends.height"
- :stroke-dasharray="strokeDashArray(series.lineStyle)"
- :x1="measurements.legends.offsetX"
- :x2="measurements.legends.offsetX + measurements.legends.width"
- :y1="graphHeight - measurements.legends.offsetY"
- :y2="graphHeight - measurements.legends.offsetY"
- />
- <text
- v-if="timeSeries.length > 1"
- class="legend-metric-title"
- ref="legendTitleSvg"
- x="38"
- :y="graphHeight - 30"
- >
- {{ createSeriesString(index, series) }}
- </text>
- <text
- v-else
- class="legend-metric-title"
- ref="legendTitleSvg"
- x="38"
- :y="graphHeight - 30"
+ <template v-if="showLegendGroup">
+ <g
+ class="legend-group"
+ v-for="(series, index) in timeSeries"
+ :key="index"
+ :transform="translateLegendGroup(index)"
>
- {{ legendTitle }} {{ formatMetricUsage(series) }}
- </text>
- </g>
+ <line
+ :stroke="series.lineColor"
+ :stroke-width="measurements.legends.height"
+ :stroke-dasharray="strokeDashArray(series.lineStyle)"
+ :x1="measurements.legends.offsetX"
+ :x2="measurements.legends.offsetX + measurements.legends.width"
+ :y1="graphHeight - measurements.legends.offsetY"
+ :y2="graphHeight - measurements.legends.offsetY"
+ />
+ <text
+ v-if="timeSeries.length > 1"
+ class="legend-metric-title"
+ ref="legendTitleSvg"
+ x="38"
+ :y="graphHeight - 30"
+ >
+ {{ createSeriesString(index, series) }}
+ </text>
+ <text
+ v-else
+ class="legend-metric-title"
+ ref="legendTitleSvg"
+ x="38"
+ :y="graphHeight - 30"
+ >
+ {{ legendTitle }} {{ formatMetricUsage(series) }}
+ </text>
+ </g>
+ </template>
</g>
</template>
diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue
index 079351a69af..f71cf614552 100644
--- a/app/assets/javascripts/monitoring/components/graph_group.vue
+++ b/app/assets/javascripts/monitoring/components/graph_group.vue
@@ -5,12 +5,20 @@
type: String,
required: true,
},
+ showPanels: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
};
</script>
<template>
- <div class="panel panel-default prometheus-panel">
+ <div
+ v-if="showPanels"
+ class="panel panel-default prometheus-panel"
+ >
<div class="panel-heading">
<h4>{{ name }}</h4>
</div>
@@ -18,4 +26,10 @@
<slot></slot>
</div>
</div>
+ <div
+ v-else
+ class="prometheus-graph-group"
+ >
+ <slot></slot>
+ </div>
</template>
diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js
index c3b0ef7e9ca..41270e015d4 100644
--- a/app/assets/javascripts/monitoring/monitoring_bundle.js
+++ b/app/assets/javascripts/monitoring/monitoring_bundle.js
@@ -1,7 +1,22 @@
import Vue from 'vue';
+import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
import Dashboard from './components/dashboard.vue';
-export default () => new Vue({
- el: '#prometheus-graphs',
- render: createElement => createElement(Dashboard),
-});
+export default () => {
+ const el = document.getElementById('prometheus-graphs');
+
+ if (el && el.dataset) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ render(createElement) {
+ return createElement(Dashboard, {
+ props: {
+ ...el.dataset,
+ hasMetrics: convertPermissionToBoolean(el.dataset.hasMetrics),
+ },
+ });
+ },
+ });
+ }
+};
diff --git a/app/assets/javascripts/monitoring/services/monitoring_service.js b/app/assets/javascripts/monitoring/services/monitoring_service.js
index e230a06cd8c..6fcca36d2fa 100644
--- a/app/assets/javascripts/monitoring/services/monitoring_service.js
+++ b/app/assets/javascripts/monitoring/services/monitoring_service.js
@@ -40,6 +40,9 @@ export default class MonitoringService {
}
getDeploymentData() {
+ if (!this.deploymentEndpoint) {
+ return Promise.resolve([]);
+ }
return backOffRequest(() => axios.get(this.deploymentEndpoint))
.then(resp => resp.data)
.then((response) => {
diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js
index 4ce3dad440c..b5b8e3c255d 100644
--- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js
+++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js
@@ -76,7 +76,7 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom
metricTag = seriesCustomizationData.value || timeSeriesMetricLabel;
[lineColor, areaColor] = pickColor(seriesCustomizationData.color);
} else {
- metricTag = timeSeriesMetricLabel || `series ${timeSeriesNumber + 1}`;
+ metricTag = timeSeriesMetricLabel || query.label || `series ${timeSeriesNumber + 1}`;
[lineColor, areaColor] = pickColor();
}
diff --git a/app/assets/javascripts/notes/components/diff_file_header.vue b/app/assets/javascripts/notes/components/diff_file_header.vue
index fe5baa3537f..3bcde17f07c 100644
--- a/app/assets/javascripts/notes/components/diff_file_header.vue
+++ b/app/assets/javascripts/notes/components/diff_file_header.vue
@@ -35,6 +35,7 @@
<clipboard-button
title="Copy file path to clipboard"
:text="diffFile.submoduleLink"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
</span>
</div>
@@ -79,6 +80,7 @@
<clipboard-button
title="Copy file path to clipboard"
:text="diffFile.filePath"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
<small
diff --git a/app/assets/javascripts/pages/groups/boards/index.js b/app/assets/javascripts/pages/groups/boards/index.js
new file mode 100644
index 00000000000..5cfe8723204
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/boards/index.js
@@ -0,0 +1,9 @@
+import UsersSelect from '~/users_select';
+import ShortcutsNavigation from '~/shortcuts_navigation';
+import initBoards from '~/boards';
+
+document.addEventListener('DOMContentLoaded', () => {
+ new UsersSelect(); // eslint-disable-line no-new
+ new ShortcutsNavigation(); // eslint-disable-line no-new
+ initBoards();
+});
diff --git a/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue b/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
new file mode 100644
index 00000000000..22248418c41
--- /dev/null
+++ b/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
@@ -0,0 +1,64 @@
+<script>
+ import axios from '~/lib/utils/axios_utils';
+ import createFlash from '~/flash';
+ import GlModal from '~/vue_shared/components/gl_modal.vue';
+ import { s__, sprintf } from '~/locale';
+ import { visitUrl } from '~/lib/utils/url_utility';
+ import eventHub from '../event_hub';
+
+ export default {
+ components: {
+ GlModal,
+ },
+ props: {
+ milestoneTitle: {
+ type: String,
+ required: true,
+ },
+ url: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ title() {
+ return sprintf(s__('Milestones|Promote %{milestoneTitle} to group milestone?'), { milestoneTitle: this.milestoneTitle });
+ },
+ text() {
+ return s__(`Milestones|Promoting this milestone will make it available for all projects inside the group.
+ Existing project milestones with the same title will be merged.
+ This action cannot be reversed.`);
+ },
+ },
+ methods: {
+ onSubmit() {
+ eventHub.$emit('promoteMilestoneModal.requestStarted', this.url);
+ return axios.post(this.url, { params: { format: 'json' } })
+ .then((response) => {
+ eventHub.$emit('promoteMilestoneModal.requestFinished', { milestoneUrl: this.url, successful: true });
+ visitUrl(response.data.url);
+ })
+ .catch((error) => {
+ eventHub.$emit('promoteMilestoneModal.requestFinished', { milestoneUrl: this.url, successful: false });
+ createFlash(error);
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <gl-modal
+ id="promote-milestone-modal"
+ footer-primary-button-variant="warning"
+ :footer-primary-button-text="s__('Milestones|Promote Milestone')"
+ @submit="onSubmit"
+ >
+ <template
+ slot="title"
+ >
+ {{ title }}
+ </template>
+ {{ text }}
+ </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
new file mode 100644
index 00000000000..d51b5c221e3
--- /dev/null
+++ b/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js
@@ -0,0 +1,84 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import deleteMilestoneModal from './components/delete_milestone_modal.vue';
+import eventHub from './event_hub';
+
+export default () => {
+ Vue.use(Translate);
+
+ const onRequestFinished = ({ milestoneUrl, successful }) => {
+ const button = document.querySelector(`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`);
+
+ if (!successful) {
+ button.removeAttribute('disabled');
+ }
+
+ button.querySelector('.js-loading-icon').classList.add('hidden');
+ };
+
+ const onRequestStarted = (milestoneUrl) => {
+ const button = document.querySelector(`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`);
+ button.setAttribute('disabled', '');
+ button.querySelector('.js-loading-icon').classList.remove('hidden');
+ 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,
+ },
+ data() {
+ return {
+ modalProps: {
+ milestoneId: -1,
+ milestoneTitle: '',
+ milestoneUrl: '',
+ issueCount: -1,
+ mergeRequestCount: -1,
+ },
+ };
+ },
+ mounted() {
+ eventHub.$on('deleteMilestoneModal.props', this.setModalProps);
+ eventHub.$emit('deleteMilestoneModal.mounted');
+ },
+ beforeDestroy() {
+ eventHub.$off('deleteMilestoneModal.props', this.setModalProps);
+ },
+ methods: {
+ setModalProps(modalProps) {
+ this.modalProps = modalProps;
+ },
+ },
+ render(createElement) {
+ return createElement(deleteMilestoneModal, {
+ props: this.modalProps,
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/pages/milestones/shared/index.js b/app/assets/javascripts/pages/milestones/shared/index.js
index 327e2cf569c..dabfe32848b 100644
--- a/app/assets/javascripts/pages/milestones/shared/index.js
+++ b/app/assets/javascripts/pages/milestones/shared/index.js
@@ -1,88 +1,7 @@
-import Vue from 'vue';
-
-import Translate from '~/vue_shared/translate';
-
-import deleteMilestoneModal from './components/delete_milestone_modal.vue';
-import eventHub from './event_hub';
+import initDeleteMilestoneModal from './delete_milestone_modal_init';
+import initPromoteMilestoneModal from './promote_milestone_modal_init';
export default () => {
- Vue.use(Translate);
-
- const onRequestFinished = ({ milestoneUrl, successful }) => {
- const button = document.querySelector(`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`);
-
- if (!successful) {
- button.removeAttribute('disabled');
- }
-
- button.querySelector('.js-loading-icon').classList.add('hidden');
- };
-
- const onRequestStarted = (milestoneUrl) => {
- const button = document.querySelector(`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`);
- button.setAttribute('disabled', '');
- button.querySelector('.js-loading-icon').classList.remove('hidden');
- 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');
- for (let i = 0; i < deleteMilestoneButtons.length; i += 1) {
- const button = deleteMilestoneButtons[i];
- button.addEventListener('click', onDeleteButtonClick);
- }
-
- eventHub.$once('deleteMilestoneModal.mounted', () => {
- for (let i = 0; i < deleteMilestoneButtons.length; i += 1) {
- const button = deleteMilestoneButtons[i];
- button.removeAttribute('disabled');
- }
- });
-
- return new Vue({
- el: '#delete-milestone-modal',
- components: {
- deleteMilestoneModal,
- },
- data() {
- return {
- modalProps: {
- milestoneId: -1,
- milestoneTitle: '',
- milestoneUrl: '',
- issueCount: -1,
- mergeRequestCount: -1,
- },
- };
- },
- mounted() {
- eventHub.$on('deleteMilestoneModal.props', this.setModalProps);
- eventHub.$emit('deleteMilestoneModal.mounted');
- },
- beforeDestroy() {
- eventHub.$off('deleteMilestoneModal.props', this.setModalProps);
- },
- methods: {
- setModalProps(modalProps) {
- this.modalProps = modalProps;
- },
- },
- render(createElement) {
- return createElement(deleteMilestoneModal, {
- props: this.modalProps,
- });
- },
- });
+ initDeleteMilestoneModal();
+ initPromoteMilestoneModal();
};
diff --git a/app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js b/app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js
new file mode 100644
index 00000000000..d00f81c9094
--- /dev/null
+++ b/app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js
@@ -0,0 +1,82 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import PromoteMilestoneModal from './components/promote_milestone_modal.vue';
+import eventHub from './event_hub';
+
+Vue.use(Translate);
+
+export default () => {
+ const onRequestFinished = ({ milestoneUrl, successful }) => {
+ const button = document.querySelector(`.js-promote-project-milestone-button[data-url="${milestoneUrl}"]`);
+
+ if (!successful) {
+ button.removeAttribute('disabled');
+ }
+ };
+
+ const onRequestStarted = (milestoneUrl) => {
+ const button = document.querySelector(`.js-promote-project-milestone-button[data-url="${milestoneUrl}"]`);
+ button.setAttribute('disabled', '');
+ eventHub.$once('promoteMilestoneModal.requestFinished', onRequestFinished);
+ };
+
+ const onDeleteButtonClick = (event) => {
+ const button = event.currentTarget;
+ const modalProps = {
+ milestoneTitle: button.dataset.milestoneTitle,
+ url: button.dataset.url,
+ };
+ eventHub.$once('promoteMilestoneModal.requestStarted', onRequestStarted);
+ eventHub.$emit('promoteMilestoneModal.props', modalProps);
+ };
+
+ const promoteMilestoneButtons = document.querySelectorAll('.js-promote-project-milestone-button');
+ promoteMilestoneButtons.forEach((button) => {
+ button.addEventListener('click', onDeleteButtonClick);
+ });
+
+ eventHub.$once('promoteMilestoneModal.mounted', () => {
+ promoteMilestoneButtons.forEach((button) => {
+ button.removeAttribute('disabled');
+ });
+ });
+
+ const promoteMilestoneModal = document.getElementById('promote-milestone-modal');
+ let promoteMilestoneComponent;
+
+ if (promoteMilestoneModal) {
+ promoteMilestoneComponent = new Vue({
+ el: promoteMilestoneModal,
+ components: {
+ PromoteMilestoneModal,
+ },
+ data() {
+ return {
+ modalProps: {
+ milestoneTitle: '',
+ url: '',
+ },
+ };
+ },
+ mounted() {
+ eventHub.$on('promoteMilestoneModal.props', this.setModalProps);
+ eventHub.$emit('promoteMilestoneModal.mounted');
+ },
+ beforeDestroy() {
+ eventHub.$off('promoteMilestoneModal.props', this.setModalProps);
+ },
+ methods: {
+ setModalProps(modalProps) {
+ this.modalProps = modalProps;
+ },
+ },
+ render(createElement) {
+ return createElement('promote-milestone-modal', {
+ props: this.modalProps,
+ });
+ },
+ });
+ }
+
+ return promoteMilestoneComponent;
+};
diff --git a/app/assets/javascripts/pages/projects/environments/index.js b/app/assets/javascripts/pages/projects/environments/index/index.js
index ace8af00ece..ace8af00ece 100644
--- a/app/assets/javascripts/pages/projects/environments/index.js
+++ b/app/assets/javascripts/pages/projects/environments/index/index.js
diff --git a/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue b/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
new file mode 100644
index 00000000000..54695dfeb99
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
@@ -0,0 +1,79 @@
+<script>
+ import axios from '~/lib/utils/axios_utils';
+ import createFlash from '~/flash';
+ import GlModal from '~/vue_shared/components/gl_modal.vue';
+ import { s__, sprintf } from '~/locale';
+ import { visitUrl } from '~/lib/utils/url_utility';
+ import eventHub from '../event_hub';
+
+ export default {
+ components: {
+ GlModal,
+ },
+ props: {
+ url: {
+ type: String,
+ required: true,
+ },
+ labelTitle: {
+ type: String,
+ required: true,
+ },
+ labelColor: {
+ type: String,
+ required: true,
+ },
+ labelTextColor: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ text() {
+ return s__(`Milestones|Promoting this label will make it available for all projects inside the group.
+ Existing project labels with the same title will be merged. This action cannot be reversed.`);
+ },
+ title() {
+ const label = `<span
+ class="label color-label"
+ style="background-color: ${this.labelColor}; color: ${this.labelTextColor};"
+ >${this.labelTitle}</span>`;
+
+ return sprintf(s__('Labels|Promote label %{labelTitle} to Group Label?'), {
+ labelTitle: label,
+ }, false);
+ },
+ },
+ methods: {
+ onSubmit() {
+ eventHub.$emit('promoteLabelModal.requestStarted', this.url);
+ return axios.post(this.url, { params: { format: 'json' } })
+ .then((response) => {
+ eventHub.$emit('promoteLabelModal.requestFinished', { labelUrl: this.url, successful: true });
+ visitUrl(response.data.url);
+ })
+ .catch((error) => {
+ eventHub.$emit('promoteLabelModal.requestFinished', { labelUrl: this.url, successful: false });
+ createFlash(error);
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <gl-modal
+ id="promote-label-modal"
+ footer-primary-button-variant="warning"
+ :footer-primary-button-text="s__('Labels|Promote Label')"
+ @submit="onSubmit"
+ >
+ <div
+ slot="title"
+ v-html="title"
+ >
+ {{ title }}
+ </div>
+
+ {{ text }}
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/pages/projects/labels/event_hub.js b/app/assets/javascripts/pages/projects/labels/event_hub.js
new file mode 100644
index 00000000000..0948c2e5352
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/labels/event_hub.js
@@ -0,0 +1,3 @@
+import Vue from 'vue';
+
+export default new Vue();
diff --git a/app/assets/javascripts/pages/projects/labels/index/index.js b/app/assets/javascripts/pages/projects/labels/index/index.js
index 6e45de2a724..2abcbfab1ed 100644
--- a/app/assets/javascripts/pages/projects/labels/index/index.js
+++ b/app/assets/javascripts/pages/projects/labels/index/index.js
@@ -1,3 +1,91 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
import initLabels from '~/init_labels';
+import eventHub from '../event_hub';
+import PromoteLabelModal from '../components/promote_label_modal.vue';
-document.addEventListener('DOMContentLoaded', initLabels);
+Vue.use(Translate);
+
+const initLabelIndex = () => {
+ initLabels();
+
+ const onRequestFinished = ({ labelUrl, successful }) => {
+ const button = document.querySelector(`.js-promote-project-label-button[data-url="${labelUrl}"]`);
+
+ if (!successful) {
+ button.removeAttribute('disabled');
+ }
+ };
+
+ const onRequestStarted = (labelUrl) => {
+ const button = document.querySelector(`.js-promote-project-label-button[data-url="${labelUrl}"]`);
+ button.setAttribute('disabled', '');
+ eventHub.$once('promoteLabelModal.requestFinished', onRequestFinished);
+ };
+
+ const onDeleteButtonClick = (event) => {
+ const button = event.currentTarget;
+ const modalProps = {
+ labelTitle: button.dataset.labelTitle,
+ labelColor: button.dataset.labelColor,
+ labelTextColor: button.dataset.labelTextColor,
+ url: button.dataset.url,
+ };
+ eventHub.$once('promoteLabelModal.requestStarted', onRequestStarted);
+ eventHub.$emit('promoteLabelModal.props', modalProps);
+ };
+
+ const promoteLabelButtons = document.querySelectorAll('.js-promote-project-label-button');
+ promoteLabelButtons.forEach((button) => {
+ button.addEventListener('click', onDeleteButtonClick);
+ });
+
+ eventHub.$once('promoteLabelModal.mounted', () => {
+ promoteLabelButtons.forEach((button) => {
+ button.removeAttribute('disabled');
+ });
+ });
+
+ const promoteLabelModal = document.getElementById('promote-label-modal');
+ let promoteLabelModalComponent;
+
+ if (promoteLabelModal) {
+ promoteLabelModalComponent = new Vue({
+ el: promoteLabelModal,
+ components: {
+ PromoteLabelModal,
+ },
+ data() {
+ return {
+ modalProps: {
+ labelTitle: '',
+ labelColor: '',
+ labelTextColor: '',
+ url: '',
+ },
+ };
+ },
+ mounted() {
+ eventHub.$on('promoteLabelModal.props', this.setModalProps);
+ eventHub.$emit('promoteLabelModal.mounted');
+ },
+ beforeDestroy() {
+ eventHub.$off('promoteLabelModal.props', this.setModalProps);
+ },
+ methods: {
+ setModalProps(modalProps) {
+ this.modalProps = modalProps;
+ },
+ },
+ render(createElement) {
+ return createElement('promote-label-modal', {
+ props: this.modalProps,
+ });
+ },
+ });
+ }
+
+ return promoteLabelModalComponent;
+};
+
+document.addEventListener('DOMContentLoaded', initLabelIndex);
diff --git a/app/assets/javascripts/pages/projects/pipelines/index/index.js b/app/assets/javascripts/pages/projects/pipelines/index/index.js
index 25dfa99ad9c..a84e2790680 100644
--- a/app/assets/javascripts/pages/projects/pipelines/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/index/index.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import PipelinesStore from '../../../../pipelines/stores/pipelines_store';
import pipelinesComponent from '../../../../pipelines/components/pipelines.vue';
import Translate from '../../../../vue_shared/translate';
+import { convertPermissionToBoolean } from '../../../../lib/utils/common_utils';
Vue.use(Translate);
@@ -11,16 +12,28 @@ document.addEventListener('DOMContentLoaded', () => new Vue({
pipelinesComponent,
},
data() {
- const store = new PipelinesStore();
-
return {
- store,
+ store: new PipelinesStore(),
};
},
+ created() {
+ this.dataset = document.querySelector(this.$options.el).dataset;
+ },
render(createElement) {
return createElement('pipelines-component', {
props: {
store: this.store,
+ endpoint: this.dataset.endpoint,
+ helpPagePath: this.dataset.helpPagePath,
+ emptyStateSvgPath: this.dataset.emptyStateSvgPath,
+ errorStateSvgPath: this.dataset.errorStateSvgPath,
+ noPipelinesSvgPath: this.dataset.noPipelinesSvgPath,
+ autoDevopsPath: this.dataset.helpAutoDevopsPath,
+ newPipelinePath: this.dataset.newPipelinePath,
+ canCreatePipeline: convertPermissionToBoolean(this.dataset.canCreatePipeline),
+ hasGitlabCi: convertPermissionToBoolean(this.dataset.hasGitlabCi),
+ ciLintPath: this.dataset.ciLintPath,
+ resetCachePath: this.dataset.resetCachePath,
},
});
},
diff --git a/app/assets/javascripts/pipelines/components/blank_state.vue b/app/assets/javascripts/pipelines/components/blank_state.vue
new file mode 100644
index 00000000000..8d3d6223d7b
--- /dev/null
+++ b/app/assets/javascripts/pipelines/components/blank_state.vue
@@ -0,0 +1,32 @@
+<script>
+ export default {
+ name: 'PipelinesSvgState',
+ props: {
+ svgPath: {
+ type: String,
+ required: true,
+ },
+
+ message: {
+ type: String,
+ required: true,
+ },
+ },
+ };
+</script>
+
+<template>
+ <div class="row empty-state">
+ <div class="col-xs-12">
+ <div class="svg-content">
+ <img :src="svgPath" />
+ </div>
+ </div>
+
+ <div class="col-xs-12 text-center">
+ <div class="text-content">
+ <h4>{{ message }}</h4>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/empty_state.vue b/app/assets/javascripts/pipelines/components/empty_state.vue
index dfaa2574091..10ac8c08bed 100644
--- a/app/assets/javascripts/pipelines/components/empty_state.vue
+++ b/app/assets/javascripts/pipelines/components/empty_state.vue
@@ -1,5 +1,6 @@
<script>
export default {
+ name: 'PipelinesEmptyState',
props: {
helpPagePath: {
type: String,
@@ -9,6 +10,10 @@
type: String,
required: true,
},
+ canSetCi: {
+ type: Boolean,
+ required: true,
+ },
},
};
</script>
@@ -22,22 +27,36 @@
<div class="col-xs-12">
<div class="text-content">
- <h4 class="text-center">
- {{ s__("Pipelines|Build with confidence") }}
- </h4>
- <p>
- {{ s__(`Pipelines|Continous Integration can help
-catch bugs by running your tests automatically,
-while Continuous Deployment can help you deliver code to your product environment.`) }}
+
+ <template v-if="canSetCi">
+ <h4 class="text-center">
+ {{ s__('Pipelines|Build with confidence') }}
+ </h4>
+
+ <p>
+ {{ s__(`Pipelines|Continous Integration can help
+ catch bugs by running your tests automatically,
+ while Continuous Deployment can help you deliver
+ code to your product environment.`) }}
+ </p>
+
+ <div class="text-center">
+ <a
+ :href="helpPagePath"
+ class="btn btn-primary js-get-started-pipelines"
+ >
+ {{ s__('Pipelines|Get started with Pipelines') }}
+ </a>
+ </div>
+ </template>
+
+ <p
+ v-else
+ class="text-center"
+ >
+ {{ s__('Pipelines|This project is not currently set up to run pipelines.') }}
</p>
- <div class="text-center">
- <a
- :href="helpPagePath"
- class="btn btn-info"
- >
- {{ s__("Pipelines|Get started with Pipelines") }}
- </a>
- </div>
+
</div>
</div>
</div>
diff --git a/app/assets/javascripts/pipelines/components/error_state.vue b/app/assets/javascripts/pipelines/components/error_state.vue
deleted file mode 100644
index 012853b201d..00000000000
--- a/app/assets/javascripts/pipelines/components/error_state.vue
+++ /dev/null
@@ -1,26 +0,0 @@
-<script>
-export default {
- props: {
- errorStateSvgPath: {
- type: String,
- required: true,
- },
- },
-};
-</script>
-
-<template>
- <div class="row empty-state js-pipelines-error-state">
- <div class="col-xs-12">
- <div class="svg-content">
- <img :src="errorStateSvgPath"/>
- </div>
- </div>
-
- <div class="col-xs-12 text-center">
- <div class="text-content">
- <h4>The API failed to fetch the pipelines.</h4>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/nav_controls.vue b/app/assets/javascripts/pipelines/components/nav_controls.vue
index f31a91c3403..eba5678e3e5 100644
--- a/app/assets/javascripts/pipelines/components/nav_controls.vue
+++ b/app/assets/javascripts/pipelines/components/nav_controls.vue
@@ -1,67 +1,67 @@
<script>
-export default {
- name: 'PipelineNavControls',
- props: {
- newPipelinePath: {
- type: String,
- required: true,
- },
+ import LoadingButton from '../../vue_shared/components/loading_button.vue';
- hasCiEnabled: {
- type: Boolean,
- required: true,
+ export default {
+ name: 'PipelineNavControls',
+ components: {
+ LoadingButton,
},
+ props: {
+ newPipelinePath: {
+ type: String,
+ required: false,
+ default: null,
+ },
- helpPagePath: {
- type: String,
- required: true,
- },
+ resetCachePath: {
+ type: String,
+ required: false,
+ default: null,
+ },
- resetCachePath: {
- type: String,
- required: true,
- },
+ ciLintPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
- ciLintPath: {
- type: String,
- required: true,
+ isResetCacheButtonLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
-
- canCreatePipeline: {
- type: Boolean,
- required: true,
+ methods: {
+ onClickResetCache() {
+ this.$emit('resetRunnersCache', this.resetCachePath);
+ },
},
- },
-};
+ };
</script>
<template>
<div class="nav-controls">
<a
- v-if="canCreatePipeline"
+ v-if="newPipelinePath"
:href="newPipelinePath"
- class="btn btn-create">
- Run Pipeline
+ class="btn btn-create js-run-pipeline"
+ >
+ {{ s__('Pipelines|Run Pipeline') }}
</a>
- <a
- v-if="!hasCiEnabled"
- :href="helpPagePath"
- class="btn btn-info">
- Get started with Pipelines
- </a>
-
- <a
- data-method="post"
- rel="nofollow"
- :href="resetCachePath"
- class="btn btn-default">
- Clear runner caches
- </a>
+ <loading-button
+ v-if="resetCachePath"
+ @click="onClickResetCache"
+ :loading="isResetCacheButtonLoading"
+ class="btn btn-default js-clear-cache"
+ :label="s__('Pipelines|Clear Runner Caches')"
+ />
<a
+ v-if="ciLintPath"
:href="ciLintPath"
- class="btn btn-default">
- CI Lint
+ class="btn btn-default js-ci-lint"
+ >
+ {{ s__('Pipelines|CI Lint') }}
</a>
</div>
</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines.vue
index 90930d5ff44..e0a7284124d 100644
--- a/app/assets/javascripts/pipelines/components/pipelines.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines.vue
@@ -1,12 +1,13 @@
<script>
import _ from 'underscore';
+ import { __, sprintf, s__ } from '../../locale';
+ import createFlash from '../../flash';
import PipelinesService from '../services/pipelines_service';
import pipelinesMixin from '../mixins/pipelines';
- import tablePagination from '../../vue_shared/components/table_pagination.vue';
- import navigationTabs from '../../vue_shared/components/navigation_tabs.vue';
- import navigationControls from './nav_controls.vue';
+ import TablePagination from '../../vue_shared/components/table_pagination.vue';
+ import NavigationTabs from '../../vue_shared/components/navigation_tabs.vue';
+ import NavigationControls from './nav_controls.vue';
import {
- convertPermissionToBoolean,
getParameterByName,
parseQueryStringIntoObject,
} from '../../lib/utils/common_utils';
@@ -14,9 +15,9 @@
export default {
components: {
- tablePagination,
- navigationTabs,
- navigationControls,
+ TablePagination,
+ NavigationTabs,
+ NavigationControls,
},
mixins: [
pipelinesMixin,
@@ -36,111 +37,187 @@
required: false,
default: 'root',
},
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ helpPagePath: {
+ type: String,
+ required: true,
+ },
+ emptyStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ errorStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ noPipelinesSvgPath: {
+ type: String,
+ required: true,
+ },
+ autoDevopsPath: {
+ type: String,
+ required: true,
+ },
+ hasGitlabCi: {
+ type: Boolean,
+ required: true,
+ },
+ canCreatePipeline: {
+ type: Boolean,
+ required: true,
+ },
+ ciLintPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ resetCachePath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ newPipelinePath: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
data() {
- const pipelinesData = document.querySelector('#pipelines-list-vue').dataset;
-
return {
- endpoint: pipelinesData.endpoint,
- helpPagePath: pipelinesData.helpPagePath,
- emptyStateSvgPath: pipelinesData.emptyStateSvgPath,
- errorStateSvgPath: pipelinesData.errorStateSvgPath,
- autoDevopsPath: pipelinesData.helpAutoDevopsPath,
- newPipelinePath: pipelinesData.newPipelinePath,
- canCreatePipeline: pipelinesData.canCreatePipeline,
- hasCi: pipelinesData.hasCi,
- ciLintPath: pipelinesData.ciLintPath,
- resetCachePath: pipelinesData.resetCachePath,
+ // Start with loading state to avoid a glitch when the empty state will be rendered
+ isLoading: true,
state: this.store.state,
scope: getParameterByName('scope') || 'all',
page: getParameterByName('page') || '1',
requestData: {},
+ isResetCacheButtonLoading: false,
};
},
- computed: {
- canCreatePipelineParsed() {
- return convertPermissionToBoolean(this.canCreatePipeline);
- },
+ stateMap: {
+ // with tabs
+ loading: 'loading',
+ tableList: 'tableList',
+ error: 'error',
+ emptyTab: 'emptyTab',
+ // without tabs
+ emptyState: 'emptyState',
+ },
+ scopes: {
+ all: 'all',
+ pending: 'pending',
+ running: 'running',
+ finished: 'finished',
+ branches: 'branches',
+ tags: 'tags',
+ },
+ computed: {
/**
- * The empty state should only be rendered when the request is made to fetch all pipelines
- * and none is returned.
- *
- * @return {Boolean}
- */
- shouldRenderEmptyState() {
- return !this.isLoading &&
- !this.hasError &&
- this.hasMadeRequest &&
- !this.state.pipelines.length &&
- (this.scope === 'all' || this.scope === null);
+ * `hasGitlabCi` handles both internal and external CI.
+ * The order on which the checks are made in this method is
+ * important to guarantee we handle all the corner cases.
+ */
+ stateToRender() {
+ const { stateMap } = this.$options;
+
+ if (this.isLoading) {
+ return stateMap.loading;
+ }
+
+ if (this.hasError) {
+ return stateMap.error;
+ }
+
+ if (this.state.pipelines.length) {
+ return stateMap.tableList;
+ }
+
+ if ((this.scope !== 'all' && this.scope !== null) || this.hasGitlabCi) {
+ return stateMap.emptyTab;
+ }
+
+ return stateMap.emptyState;
},
/**
- * When a specific scope does not have pipelines we render a message.
- *
- * @return {Boolean}
+ * Tabs are rendered in all states except empty state.
+ * They are not rendered before the first request to avoid a flicker on first load.
*/
- shouldRenderNoPipelinesMessage() {
- return !this.isLoading &&
- !this.hasError &&
- !this.state.pipelines.length &&
- this.scope !== 'all' &&
- this.scope !== null;
+ shouldRenderTabs() {
+ const { stateMap } = this.$options;
+ return this.hasMadeRequest &&
+ [
+ stateMap.loading,
+ stateMap.tableList,
+ stateMap.error,
+ stateMap.emptyTab,
+ ].includes(this.stateToRender);
},
- shouldRenderTable() {
- return !this.hasError &&
- !this.isLoading && this.state.pipelines.length;
+ shouldRenderButtons() {
+ return (this.newPipelinePath ||
+ this.resetCachePath ||
+ this.ciLintPath) && this.shouldRenderTabs;
},
- /**
- * Pagination should only be rendered when there is more than one page.
- *
- * @return {Boolean}
- */
+
shouldRenderPagination() {
return !this.isLoading &&
this.state.pipelines.length &&
this.state.pageInfo.total > this.state.pageInfo.perPage;
},
- hasCiEnabled() {
- return this.hasCi !== undefined;
+
+ emptyTabMessage() {
+ const { scopes } = this.$options;
+ const possibleScopes = [scopes.pending, scopes.running, scopes.finished];
+
+ if (possibleScopes.includes(this.scope)) {
+ return sprintf(s__('Pipelines|There are currently no %{scope} pipelines.'), {
+ scope: this.scope,
+ });
+ }
+
+ return s__('Pipelines|There are currently no pipelines.');
},
tabs() {
const { count } = this.state;
+ const { scopes } = this.$options;
+
return [
{
- name: 'All',
- scope: 'all',
+ name: __('All'),
+ scope: scopes.all,
count: count.all,
isActive: this.scope === 'all',
},
{
- name: 'Pending',
- scope: 'pending',
+ name: __('Pending'),
+ scope: scopes.pending,
count: count.pending,
isActive: this.scope === 'pending',
},
{
- name: 'Running',
- scope: 'running',
+ name: __('Running'),
+ scope: scopes.running,
count: count.running,
isActive: this.scope === 'running',
},
{
- name: 'Finished',
- scope: 'finished',
+ name: __('Finished'),
+ scope: scopes.finished,
count: count.finished,
isActive: this.scope === 'finished',
},
{
- name: 'Branches',
- scope: 'branches',
+ name: __('Branches'),
+ scope: scopes.branches,
isActive: this.scope === 'branches',
},
{
- name: 'Tags',
- scope: 'tags',
+ name: __('Tags'),
+ scope: scopes.tags,
isActive: this.scope === 'tags',
},
];
@@ -187,7 +264,24 @@
this.errorCallback();
// restart polling
- this.poll.restart();
+ this.poll.restart({ data: this.requestData });
+ });
+ },
+
+ handleResetRunnersCache(endpoint) {
+ this.isResetCacheButtonLoading = true;
+
+ this.service.postAction(endpoint)
+ .then(() => {
+ this.isResetCacheButtonLoading = false;
+ createFlash(
+ s__('Pipelines|Project cache successfully reset.'),
+ 'notice',
+ );
+ })
+ .catch(() => {
+ this.isResetCacheButtonLoading = false;
+ createFlash(s__('Pipelines|Something went wrong while cleaning runners cache.'));
});
},
},
@@ -197,69 +291,72 @@
<div class="pipelines-container">
<div
class="top-area scrolling-tabs-container inner-page-scroll-tabs"
- v-if="!shouldRenderEmptyState"
+ v-if="shouldRenderTabs || shouldRenderButtons"
>
<div class="fade-left">
<i
class="fa fa-angle-left"
- aria-hidden="true">
+ aria-hidden="true"
+ >
</i>
</div>
<div class="fade-right">
<i
class="fa fa-angle-right"
- aria-hidden="true">
+ aria-hidden="true"
+ >
</i>
</div>
<navigation-tabs
+ v-if="shouldRenderTabs"
:tabs="tabs"
@onChangeTab="onChangeTab"
scope="pipelines"
/>
<navigation-controls
+ v-if="shouldRenderButtons"
:new-pipeline-path="newPipelinePath"
- :has-ci-enabled="hasCiEnabled"
- :help-page-path="helpPagePath"
:reset-cache-path="resetCachePath"
:ci-lint-path="ciLintPath"
- :can-create-pipeline="canCreatePipelineParsed "
+ @resetRunnersCache="handleResetRunnersCache"
+ :is-reset-cache-button-loading="isResetCacheButtonLoading"
/>
</div>
<div class="content-list pipelines">
<loading-icon
- label="Loading Pipelines"
+ v-if="stateToRender === $options.stateMap.loading"
+ :label="s__('Pipelines|Loading Pipelines')"
size="3"
- v-if="isLoading"
class="prepend-top-20"
/>
<empty-state
- v-if="shouldRenderEmptyState"
+ v-else-if="stateToRender === $options.stateMap.emptyState"
:help-page-path="helpPagePath"
:empty-state-svg-path="emptyStateSvgPath"
+ :can-set-ci="canCreatePipeline"
/>
- <error-state
- v-if="shouldRenderErrorState"
- :error-state-svg-path="errorStateSvgPath"
+ <svg-blank-state
+ v-else-if="stateToRender === $options.stateMap.error"
+ :svg-path="errorStateSvgPath"
+ :message="s__(`Pipelines|There was an error fetching the pipelines.
+ Try again in a few moments or contact your support team.`)"
/>
- <div
- class="blank-state-row"
- v-if="shouldRenderNoPipelinesMessage"
- >
- <div class="blank-state-center">
- <h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2>
- </div>
- </div>
+ <svg-blank-state
+ v-else-if="stateToRender === $options.stateMap.emptyTab"
+ :svg-path="noPipelinesSvgPath"
+ :message="emptyTabMessage"
+ />
<div
class="table-holder"
- v-if="shouldRenderTable"
+ v-else-if="stateToRender === $options.stateMap.tableList"
>
<pipelines-table-component
diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js
index 50bdf80c3e3..522a4277bd7 100644
--- a/app/assets/javascripts/pipelines/mixins/pipelines.js
+++ b/app/assets/javascripts/pipelines/mixins/pipelines.js
@@ -1,23 +1,19 @@
import Visibility from 'visibilityjs';
+import { __ } from '../../locale';
import Flash from '../../flash';
import Poll from '../../lib/utils/poll';
-import emptyState from '../components/empty_state.vue';
-import errorState from '../components/error_state.vue';
-import loadingIcon from '../../vue_shared/components/loading_icon.vue';
-import pipelinesTableComponent from '../components/pipelines_table.vue';
+import EmptyState from '../components/empty_state.vue';
+import SvgBlankState from '../components/blank_state.vue';
+import LoadingIcon from '../../vue_shared/components/loading_icon.vue';
+import PipelinesTableComponent from '../components/pipelines_table.vue';
import eventHub from '../event_hub';
export default {
components: {
- pipelinesTableComponent,
- errorState,
- emptyState,
- loadingIcon,
- },
- computed: {
- shouldRenderErrorState() {
- return this.hasError && !this.isLoading;
- },
+ PipelinesTableComponent,
+ SvgBlankState,
+ EmptyState,
+ LoadingIcon,
},
data() {
return {
@@ -55,12 +51,10 @@ export default {
}
});
- eventHub.$on('refreshPipelines', this.fetchPipelines);
eventHub.$on('postAction', this.postAction);
},
beforeDestroy() {
- eventHub.$off('refreshPipelines');
- eventHub.$on('postAction', this.postAction);
+ eventHub.$off('postAction', this.postAction);
},
destroyed() {
this.poll.stop();
@@ -85,6 +79,7 @@ export default {
this.hasError = true;
this.isLoading = false;
this.updateGraphDropdown = false;
+ this.hasMadeRequest = true;
},
setIsMakingRequest(isMakingRequest) {
this.isMakingRequest = isMakingRequest;
@@ -95,8 +90,8 @@ export default {
},
postAction(endpoint) {
this.service.postAction(endpoint)
- .then(() => eventHub.$emit('refreshPipelines'))
- .catch(() => new Flash('An error occurred while making the request.'));
+ .then(() => this.fetchPipelines())
+ .catch(() => Flash(__('An error occurred while making the request.')));
},
},
};
diff --git a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
index e8126ac573d..03bb281395a 100644
--- a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
+++ b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
@@ -1,3 +1,5 @@
+import _ from 'underscore';
+import { s__, n__, sprintf } from '~/locale';
import axios from '../lib/utils/axios_utils';
import PANEL_STATE from './constants';
import { backOff } from '../lib/utils/common_utils';
@@ -20,6 +22,7 @@ export default class PrometheusMetrics {
this.$missingEnvVarMetricsList = this.$missingEnvVarPanel.find('.js-missing-var-metrics-list');
this.activeMetricsEndpoint = this.$monitoredMetricsPanel.data('activeMetrics');
+ this.helpMetricsPath = this.$monitoredMetricsPanel.data('metrics-help-path');
this.$panelToggle.on('click', e => this.handlePanelToggle(e));
}
@@ -59,23 +62,39 @@ export default class PrometheusMetrics {
populateActiveMetrics(metrics) {
let totalMonitoredMetrics = 0;
let totalMissingEnvVarMetrics = 0;
+ let totalExporters = 0;
metrics.forEach((metric) => {
- this.$monitoredMetricsList.append(`<li>${metric.group}<span class="badge">${metric.active_metrics}</span></li>`);
- totalMonitoredMetrics += metric.active_metrics;
- if (metric.metrics_missing_requirements > 0) {
- this.$missingEnvVarMetricsList.append(`<li>${metric.group}</li>`);
- totalMissingEnvVarMetrics += 1;
+ if (metric.active_metrics > 0) {
+ totalExporters += 1;
+ this.$monitoredMetricsList.append(`<li>${_.escape(metric.group)}<span class="badge">${_.escape(metric.active_metrics)}</span></li>`);
+ totalMonitoredMetrics += metric.active_metrics;
+ if (metric.metrics_missing_requirements > 0) {
+ this.$missingEnvVarMetricsList.append(`<li>${_.escape(metric.group)}</li>`);
+ totalMissingEnvVarMetrics += 1;
+ }
}
});
- this.$monitoredMetricsCount.text(totalMonitoredMetrics);
- this.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
+ if (totalMonitoredMetrics === 0) {
+ const emptyCommonMetricsText = sprintf(s__('PrometheusService|<p class="text-tertiary">No <a href="%{docsUrl}">common metrics</a> were found</p>'), {
+ docsUrl: this.helpMetricsPath,
+ }, false);
+ this.$monitoredMetricsEmpty.empty();
+ this.$monitoredMetricsEmpty.append(emptyCommonMetricsText);
+ this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
+ } else {
+ const metricsCountText = sprintf(s__('PrometheusService|%{exporters} with %{metrics} were found'), {
+ exporters: n__('%d exporter', '%d exporters', totalExporters),
+ metrics: n__('%d metric', '%d metrics', totalMonitoredMetrics),
+ });
+ this.$monitoredMetricsCount.text(metricsCountText);
+ this.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
- if (totalMissingEnvVarMetrics > 0) {
- this.$missingEnvVarPanel.removeClass('hidden');
- this.$missingEnvVarPanel.find('.flash-container').off('click');
- this.$missingEnvVarMetricCount.text(totalMissingEnvVarMetrics);
+ if (totalMissingEnvVarMetrics > 0) {
+ this.$missingEnvVarPanel.removeClass('hidden');
+ this.$missingEnvVarMetricCount.text(totalMissingEnvVarMetrics);
+ }
}
}
@@ -97,15 +116,15 @@ export default class PrometheusMetrics {
})
.catch(stop);
})
- .then((res) => {
- if (res && res.data && res.data.length) {
- this.populateActiveMetrics(res.data);
- } else {
+ .then((res) => {
+ if (res && res.data && res.data.length) {
+ this.populateActiveMetrics(res.data);
+ } else {
+ this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
+ }
+ })
+ .catch(() => {
this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
- }
- })
- .catch(() => {
- this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
- });
+ });
}
}
diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue
index b4906ba4ee5..a03180e80e6 100644
--- a/app/assets/javascripts/registry/components/collapsible_container.vue
+++ b/app/assets/javascripts/registry/components/collapsible_container.vue
@@ -86,6 +86,7 @@
v-if="repo.location"
:text="clipboardText"
:title="repo.location"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
<div class="controls hidden-xs pull-right">
diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue
index bef850eddc0..ee4eb3581f3 100644
--- a/app/assets/javascripts/registry/components/table_registry.vue
+++ b/app/assets/javascripts/registry/components/table_registry.vue
@@ -90,6 +90,7 @@
v-if="item.location"
:title="item.location"
:text="clipboardText(item.location)"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
</td>
<td>
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
index 8269fe1281d..b58e04b5e60 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.js
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
@@ -1,3 +1,4 @@
+<script>
import Flash from '../../../flash';
import AssigneeTitle from './assignee_title';
import Assignees from './assignees.vue';
@@ -6,11 +7,9 @@ import eventHub from '../../event_hub';
export default {
name: 'SidebarAssignees',
- data() {
- return {
- store: new Store(),
- loading: false,
- };
+ components: {
+ AssigneeTitle,
+ Assignees,
},
props: {
mediator: {
@@ -27,9 +26,28 @@ export default {
default: false,
},
},
- components: {
- AssigneeTitle,
- Assignees,
+ data() {
+ return {
+ store: new Store(),
+ loading: false,
+ };
+ },
+ created() {
+ this.removeAssignee = this.store.removeAssignee.bind(this.store);
+ this.addAssignee = this.store.addAssignee.bind(this.store);
+ this.removeAllAssignees = this.store.removeAllAssignees.bind(this.store);
+
+ // Get events from glDropdown
+ eventHub.$on('sidebar.removeAssignee', this.removeAssignee);
+ eventHub.$on('sidebar.addAssignee', this.addAssignee);
+ eventHub.$on('sidebar.removeAllAssignees', this.removeAllAssignees);
+ eventHub.$on('sidebar.saveAssignees', this.saveAssignees);
+ },
+ beforeDestroy() {
+ eventHub.$off('sidebar.removeAssignee', this.removeAssignee);
+ eventHub.$off('sidebar.addAssignee', this.addAssignee);
+ eventHub.$off('sidebar.removeAllAssignees', this.removeAllAssignees);
+ eventHub.$off('sidebar.saveAssignees', this.saveAssignees);
},
methods: {
assignSelf() {
@@ -54,39 +72,24 @@ export default {
});
},
},
- created() {
- this.removeAssignee = this.store.removeAssignee.bind(this.store);
- this.addAssignee = this.store.addAssignee.bind(this.store);
- this.removeAllAssignees = this.store.removeAllAssignees.bind(this.store);
-
- // Get events from glDropdown
- eventHub.$on('sidebar.removeAssignee', this.removeAssignee);
- eventHub.$on('sidebar.addAssignee', this.addAssignee);
- eventHub.$on('sidebar.removeAllAssignees', this.removeAllAssignees);
- eventHub.$on('sidebar.saveAssignees', this.saveAssignees);
- },
- beforeDestroy() {
- eventHub.$off('sidebar.removeAssignee', this.removeAssignee);
- eventHub.$off('sidebar.addAssignee', this.addAssignee);
- eventHub.$off('sidebar.removeAllAssignees', this.removeAllAssignees);
- eventHub.$off('sidebar.saveAssignees', this.saveAssignees);
- },
- template: `
- <div>
- <assignee-title
- :number-of-assignees="store.assignees.length"
- :loading="loading || store.isFetching.assignees"
- :editable="store.editable"
- :show-toggle="!signedIn"
- />
- <assignees
- v-if="!store.isFetching.assignees"
- class="value"
- :root-path="store.rootPath"
- :users="store.assignees"
- :editable="store.editable"
- @assign-self="assignSelf"
- />
- </div>
- `,
};
+</script>
+
+<template>
+ <div>
+ <assignee-title
+ :number-of-assignees="store.assignees.length"
+ :loading="loading || store.isFetching.assignees"
+ :editable="store.editable"
+ :show-toggle="!signedIn"
+ />
+ <assignees
+ v-if="!store.isFetching.assignees"
+ class="value"
+ :root-path="store.rootPath"
+ :users="store.assignees"
+ :editable="store.editable"
+ @assign-self="assignSelf"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 56cc78ca0ca..ef748f18301 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking';
-import SidebarAssignees from './components/assignees/sidebar_assignees';
+import SidebarAssignees from './components/assignees/sidebar_assignees.vue';
import ConfidentialIssueSidebar from './components/confidential/confidential_issue_sidebar.vue';
import SidebarMoveIssue from './lib/sidebar_move_issue';
import LockIssueSidebar from './components/lock/lock_issue_sidebar.vue';
diff --git a/app/assets/javascripts/sortable/sortable_config.js b/app/assets/javascripts/sortable/sortable_config.js
new file mode 100644
index 00000000000..43ef5d66422
--- /dev/null
+++ b/app/assets/javascripts/sortable/sortable_config.js
@@ -0,0 +1,7 @@
+export default {
+ animation: 200,
+ forceFallback: true,
+ fallbackClass: 'is-dragging',
+ fallbackOnBody: true,
+ ghostClass: 'is-ghost',
+};
diff --git a/app/assets/javascripts/terminal/terminal.js b/app/assets/javascripts/terminal/terminal.js
index 6b9422b1816..904b0093f7b 100644
--- a/app/assets/javascripts/terminal/terminal.js
+++ b/app/assets/javascripts/terminal/terminal.js
@@ -6,8 +6,14 @@
constructor(options) {
this.options = options || {};
- this.options.cursorBlink = options.cursorBlink || true;
- this.options.screenKeys = options.screenKeys || true;
+ if (!Object.prototype.hasOwnProperty.call(this.options, 'cursorBlink')) {
+ this.options.cursorBlink = true;
+ }
+
+ if (!Object.prototype.hasOwnProperty.call(this.options, 'screenKeys')) {
+ this.options.screenKeys = true;
+ }
+
this.container = document.querySelector(options.selector);
this.setSocketUrl();
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js b/app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue
index 69e70ba1dd6..a16f9055a6d 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue
@@ -1,11 +1,15 @@
+<script>
import statusCodes from '../../lib/utils/http_status';
import { bytesToMiB } from '../../lib/utils/number_utils';
import { backOff } from '../../lib/utils/common_utils';
-import MemoryGraph from '../../vue_shared/components/memory_graph';
+import MemoryGraph from '../../vue_shared/components/memory_graph.vue';
import MRWidgetService from '../services/mr_widget_service';
export default {
name: 'MemoryUsage',
+ components: {
+ MemoryGraph,
+ },
props: {
metricsUrl: {
type: String,
@@ -28,9 +32,6 @@ export default {
backOffRequestCounter: 0,
};
},
- components: {
- 'mr-memory-graph': MemoryGraph,
- },
computed: {
shouldShowLoading() {
return this.loadingMetrics && !this.hasMetrics && !this.loadFailed;
@@ -57,6 +58,10 @@ export default {
return 'unchanged';
},
},
+ mounted() {
+ this.loadingMetrics = true;
+ this.loadMetrics();
+ },
methods: {
getMegabytes(bytesString) {
const valueInBytes = Number(bytesString).toFixed(2);
@@ -114,40 +119,42 @@ export default {
});
},
},
- mounted() {
- this.loadingMetrics = true;
- this.loadMetrics();
- },
- template: `
- <div class="mr-info-list clearfix mr-memory-usage js-mr-memory-usage">
- <p
- v-if="shouldShowLoading"
- class="usage-info js-usage-info usage-info-loading">
- <i
- class="fa fa-spinner fa-spin usage-info-load-spinner"
- aria-hidden="true" />Loading deployment statistics
- </p>
- <p
- v-if="shouldShowMemoryGraph"
- class="usage-info js-usage-info">
- <a :href="metricsMonitoringUrl">Memory</a> usage <b>{{memoryChangeType}}</b> from {{memoryFrom}}MB to {{memoryTo}}MB
- </p>
- <p
- v-if="shouldShowLoadFailure"
- class="usage-info js-usage-info usage-info-failed">
- Failed to load deployment statistics
- </p>
- <p
- v-if="shouldShowMetricsUnavailable"
- class="usage-info js-usage-info usage-info-unavailable">
- Deployment statistics are not available currently
- </p>
- <mr-memory-graph
- v-if="shouldShowMemoryGraph"
- :metrics="memoryMetrics"
- :deploymentTime="deploymentTime"
- height="25"
- width="100" />
- </div>
- `,
};
+</script>
+
+<template>
+ <div class="mr-info-list clearfix mr-memory-usage js-mr-memory-usage">
+ <p
+ v-if="shouldShowLoading"
+ class="usage-info js-usage-info usage-info-loading">
+ <i
+ class="fa fa-spinner fa-spin usage-info-load-spinner"
+ aria-hidden="true">
+ </i>Loading deployment statistics
+ </p>
+ <p
+ v-if="shouldShowMemoryGraph"
+ class="usage-info js-usage-info">
+ <a
+ :href="metricsMonitoringUrl"
+ >Memory</a> usage <b>{{ memoryChangeType }}</b> from {{ memoryFrom }}MB to {{ memoryTo }}MB
+ </p>
+ <p
+ v-if="shouldShowLoadFailure"
+ class="usage-info js-usage-info usage-info-failed">
+ Failed to load deployment statistics
+ </p>
+ <p
+ v-if="shouldShowMetricsUnavailable"
+ class="usage-info js-usage-info usage-info-unavailable">
+ Deployment statistics are not available currently
+ </p>
+ <memory-graph
+ v-if="shouldShowMemoryGraph"
+ :metrics="memoryMetrics"
+ :deployment-time="deploymentTime"
+ height="25"
+ width="100"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
index d174a900f63..c7f992384c8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js
@@ -1,7 +1,7 @@
import { getTimeago } from '~/lib/utils/datetime_utility';
import { visitUrl } from '../../lib/utils/url_utility';
import Flash from '../../flash';
-import MemoryUsage from './mr_widget_memory_usage';
+import MemoryUsage from './memory_usage.vue';
import StatusIcon from './mr_widget_status_icon.vue';
import MRWidgetService from '../services/mr_widget_service';
@@ -12,8 +12,8 @@ export default {
service: { type: Object, required: true },
},
components: {
- 'mr-widget-memory-usage': MemoryUsage,
- 'status-icon': StatusIcon,
+ MemoryUsage,
+ StatusIcon,
},
methods: {
formatDate(date) {
@@ -100,7 +100,7 @@ export default {
class="btn btn-default btn-xs">
Stop environment
</button>
- <mr-widget-memory-usage
+ <memory-usage
v-if="deployment.metrics_url"
:metrics-url="deployment.metrics_url"
:metrics-monitoring-url="deployment.metrics_monitoring_url"
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 18a3787857d..3d886e7d628 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
@@ -67,6 +67,7 @@
<clipboard-button
:text="branchNameClipboardData"
:title="__('Copy branch name to clipboard')"
+ css-class="btn-default btn-transparent btn-clipboard"
/>
{{ s__("mrWidget|into") }}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue
new file mode 100644
index 00000000000..f0298f732ea
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue
@@ -0,0 +1,20 @@
+<script>
+ export default {
+ name: 'MRWidgetMaintainerEdit',
+ props: {
+ maintainerEditAllowed: {
+ type: Boolean,
+ default: false,
+ required: false,
+ },
+ },
+ };
+</script>
+
+<template>
+ <section class="mr-info-list mr-links">
+ <p v-if="maintainerEditAllowed">
+ {{ s__("mrWidget|Allows edits from maintainers") }}
+ </p>
+ </section>
+</template>
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
new file mode 100644
index 00000000000..460437ceeff
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue
@@ -0,0 +1,34 @@
+<script>
+ import tooltip from '../../vue_shared/directives/tooltip';
+ import { __ } from '../../locale';
+
+ export default {
+ directives: {
+ tooltip,
+ },
+ created() {
+ this.removesBranchText = __('<strong>Removes</strong> source branch');
+ this.tooltipTitle = __('A user with write access to the source branch selected this option');
+ },
+ };
+</script>
+
+<template>
+ <p
+ v-once
+ class="mr-info-list mr-links source-branch-removal-status append-bottom-0"
+ >
+ <span
+ class="status-text"
+ v-html="removesBranchText"
+ >
+ </span>
+ <i
+ v-tooltip
+ class="fa fa-question-circle"
+ :title="tooltipTitle"
+ :aria-label="tooltipTitle"
+ >
+ </i>
+ </p>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
index 162f048aac7..3c781ccddc8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
@@ -93,7 +93,7 @@ export default {
|| this.mr.preventMerge);
},
isRemoveSourceBranchButtonDisabled() {
- return this.isMergeButtonDisabled || !this.mr.canRemoveSourceBranch;
+ return this.isMergeButtonDisabled;
},
shouldShowSquashBeforeMerge() {
const { commitsCount, enableSquashBeforeMerge } = this.mr;
@@ -282,7 +282,7 @@ export default {
</span>
<div class="media-body-wrap space-children">
<template v-if="shouldShowMergeControls()">
- <label>
+ <label v-if="mr.canRemoveSourceBranch">
<input
id="remove-source-branch-input"
v-model="removeSourceBranch"
diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
index edb3baa39e4..b867dd90a41 100644
--- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js
+++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
@@ -15,6 +15,7 @@ export { default as WidgetHeader } from './components/mr_widget_header.vue';
export { default as WidgetMergeHelp } from './components/mr_widget_merge_help.vue';
export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue';
export { default as WidgetDeployment } from './components/mr_widget_deployment';
+export { default as WidgetMaintainerEdit } from './components/mr_widget_maintainer_edit.vue';
export { default as WidgetRelatedLinks } from './components/mr_widget_related_links.vue';
export { default as MergedState } from './components/states/mr_widget_merged.vue';
export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue';
@@ -39,7 +40,9 @@ export { default as MRWidgetStore } from './stores/mr_widget_store';
export { default as MRWidgetService } from './services/mr_widget_service';
export { default as eventHub } from './event_hub';
export { default as getStateKey } from './stores/get_state_key';
-export { default as mrWidgetOptions } from './mr_widget_options';
export { default as stateMaps } from './stores/state_maps';
export { default as SquashBeforeMerge } from './components/states/mr_widget_squash_before_merge';
export { default as notify } from '../lib/utils/notify';
+export { default as SourceBranchRemovalStatus } from './components/source_branch_removal_status.vue';
+
+export { default as mrWidgetOptions } from './mr_widget_options';
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
index 797f0f6ec0f..01365b70897 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
@@ -6,6 +6,7 @@ import {
WidgetMergeHelp,
WidgetPipeline,
WidgetDeployment,
+ WidgetMaintainerEdit,
WidgetRelatedLinks,
MergedState,
ClosedState,
@@ -32,6 +33,7 @@ import {
stateMaps,
SquashBeforeMerge,
notify,
+ SourceBranchRemovalStatus,
} from './dependencies';
import { setFavicon } from '../lib/utils/common_utils';
@@ -68,6 +70,9 @@ export default {
shouldRenderDeployments() {
return this.mr.deployments.length;
},
+ shouldRenderSourceBranchRemovalStatus() {
+ return !this.mr.canRemoveSourceBranch && this.mr.shouldRemoveSourceBranch;
+ },
},
methods: {
createService(store) {
@@ -211,6 +216,7 @@ export default {
'mr-widget-merge-help': WidgetMergeHelp,
'mr-widget-pipeline': WidgetPipeline,
'mr-widget-deployment': WidgetDeployment,
+ 'mr-widget-maintainer-edit': WidgetMaintainerEdit,
'mr-widget-related-links': WidgetRelatedLinks,
'mr-widget-merged': MergedState,
'mr-widget-closed': ClosedState,
@@ -232,6 +238,7 @@ export default {
'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState,
'mr-widget-auto-merge-failed': AutoMergeFailed,
'mr-widget-rebase': RebaseState,
+ SourceBranchRemovalStatus,
},
template: `
<div class="mr-state-widget prepend-top-default">
@@ -251,11 +258,15 @@ export default {
:is="componentName"
:mr="mr"
:service="service" />
+ <mr-widget-maintainer-edit
+ :maintainerEditAllowed="mr.maintainerEditAllowed" />
<mr-widget-related-links
v-if="shouldRenderRelatedLinks"
:state="mr.state"
- :related-links="mr.relatedLinks"
- />
+ :related-links="mr.relatedLinks" />
+ <source-branch-removal-status
+ v-if="shouldRenderSourceBranchRemovalStatus"
+ />
</div>
<div
class="mr-widget-footer"
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 9a750ce42bd..5d07bcf1bb9 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
@@ -76,6 +76,7 @@ export default class MergeRequestStore {
this.canBeMerged = data.can_be_merged || false;
this.isMergeAllowed = data.mergeable || false;
this.mergeOngoing = data.merge_ongoing;
+ this.maintainerEditAllowed = data.allow_maintainer_to_push;
// Cherry-pick and Revert actions related
this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
index 3b6c2da1664..cab126a7eca 100644
--- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue
+++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
@@ -31,7 +31,7 @@
cssClass: {
type: String,
required: false,
- default: 'btn btn-default btn-transparent btn-clipboard',
+ default: 'btn-default',
},
},
};
@@ -40,6 +40,7 @@
<template>
<button
type="button"
+ class="btn"
:class="cssClass"
:title="title"
:data-clipboard-text="text"
diff --git a/app/assets/javascripts/vue_shared/components/memory_graph.js b/app/assets/javascripts/vue_shared/components/memory_graph.vue
index f37ef1a5ca3..b07f6b07afe 100644
--- a/app/assets/javascripts/vue_shared/components/memory_graph.js
+++ b/app/assets/javascripts/vue_shared/components/memory_graph.vue
@@ -1,3 +1,4 @@
+<script>
import { getTimeago } from '../../lib/utils/datetime_utility';
export default {
@@ -22,6 +23,9 @@ export default {
return `Deployed ${deployedSince}`;
},
},
+ mounted() {
+ this.renderGraph(this.deploymentTime, this.metrics);
+ },
methods: {
/**
* Returns metric value index in metrics array
@@ -103,15 +107,27 @@ export default {
this.dotY = dotY;
},
},
- mounted() {
- this.renderGraph(this.deploymentTime, this.metrics);
- },
- template: `
- <div class="memory-graph-container">
- <svg class="has-tooltip" :title="getFormattedMedian" :width="width" :height="height" xmlns="http://www.w3.org/2000/svg">
- <path :d="pathD" :viewBox="pathViewBox" />
- <circle r="1.5" :cx="dotX" :cy="dotY" tranform="translate(0 -1)" />
- </svg>
- </div>
- `,
};
+</script>
+
+<template>
+ <div class="memory-graph-container">
+ <svg
+ class="has-tooltip"
+ :title="getFormattedMedian"
+ :width="width"
+ :height="height"
+ xmlns="http://www.w3.org/2000/svg">
+ <path
+ :d="pathD"
+ :viewBox="pathViewBox"
+ />
+ <circle
+ r="1.5"
+ :cx="dotX"
+ :cy="dotY"
+ tranform="translate(0 -1)"
+ />
+ </svg>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue
new file mode 100644
index 00000000000..c1dd4d42d9d
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue
@@ -0,0 +1,149 @@
+<script>
+import LabelsSelect from '~/labels_select';
+import LoadingIcon from '../../loading_icon.vue';
+
+import DropdownTitle from './dropdown_title.vue';
+import DropdownValue from './dropdown_value.vue';
+import DropdownValueCollapsed from './dropdown_value_collapsed.vue';
+import DropdownButton from './dropdown_button.vue';
+import DropdownHiddenInput from './dropdown_hidden_input.vue';
+import DropdownHeader from './dropdown_header.vue';
+import DropdownSearchInput from './dropdown_search_input.vue';
+import DropdownFooter from './dropdown_footer.vue';
+import DropdownCreateLabel from './dropdown_create_label.vue';
+
+export default {
+ components: {
+ LoadingIcon,
+ DropdownTitle,
+ DropdownValue,
+ DropdownValueCollapsed,
+ DropdownButton,
+ DropdownHiddenInput,
+ DropdownHeader,
+ DropdownSearchInput,
+ DropdownFooter,
+ DropdownCreateLabel,
+ },
+ props: {
+ showCreate: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ abilityName: {
+ type: String,
+ required: true,
+ },
+ context: {
+ type: Object,
+ required: true,
+ },
+ namespace: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ updatePath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ labelsPath: {
+ type: String,
+ required: true,
+ },
+ labelsWebUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ labelFilterBasePath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ canEdit: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ hiddenInputName() {
+ return this.showCreate ? `${this.abilityName}[label_names][]` : 'label_id[]';
+ },
+ },
+ mounted() {
+ this.labelsDropdown = new LabelsSelect(this.$refs.dropdownButton, {
+ handleClick: this.handleClick,
+ });
+ },
+ methods: {
+ handleClick(label) {
+ this.$emit('onLabelClick', label);
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="block labels js-labels-block">
+ <dropdown-value-collapsed
+ v-if="showCreate"
+ :labels="context.labels"
+ />
+ <dropdown-title
+ :can-edit="canEdit"
+ />
+ <dropdown-value
+ :labels="context.labels"
+ :label-filter-base-path="labelFilterBasePath"
+ >
+ <slot></slot>
+ </dropdown-value>
+ <div
+ v-if="canEdit"
+ class="selectbox js-selectbox"
+ style="display: none;"
+ >
+ <dropdown-hidden-input
+ v-for="label in context.labels"
+ :key="label.id"
+ :name="hiddenInputName"
+ :label="label"
+ />
+ <div class="dropdown">
+ <dropdown-button
+ :ability-name="abilityName"
+ :field-name="hiddenInputName"
+ :update-path="updatePath"
+ :labels-path="labelsPath"
+ :namespace="namespace"
+ :labels="context.labels"
+ :show-extra-options="!showCreate"
+ />
+ <div
+ class="dropdown-menu dropdown-select dropdown-menu-paging
+dropdown-menu-labels dropdown-menu-selectable"
+ >
+ <div class="dropdown-page-one">
+ <dropdown-header v-if="showCreate" />
+ <dropdown-search-input/>
+ <div class="dropdown-content"></div>
+ <div class="dropdown-loading">
+ <loading-icon />
+ </div>
+ <dropdown-footer
+ v-if="showCreate"
+ :labels-web-url="labelsWebUrl"
+ />
+ </div>
+ <dropdown-create-label
+ v-if="showCreate"
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue
new file mode 100644
index 00000000000..47497c1de98
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue
@@ -0,0 +1,78 @@
+<script>
+import { __, s__, sprintf } from '~/locale';
+
+export default {
+ props: {
+ abilityName: {
+ type: String,
+ required: true,
+ },
+ fieldName: {
+ type: String,
+ required: true,
+ },
+ updatePath: {
+ type: String,
+ required: true,
+ },
+ labelsPath: {
+ type: String,
+ required: true,
+ },
+ namespace: {
+ type: String,
+ required: true,
+ },
+ labels: {
+ type: Array,
+ required: true,
+ },
+ showExtraOptions: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ dropdownToggleText() {
+ if (this.labels.length === 0) {
+ return __('Label');
+ }
+
+ if (this.labels.length > 1) {
+ return sprintf(s__('LabelSelect|%{firstLabelName} +%{remainingLabelCount} more'), {
+ firstLabelName: this.labels[0].title,
+ remainingLabelCount: this.labels.length - 1,
+ });
+ }
+
+ return this.labels[0].title;
+ },
+ },
+};
+</script>
+
+<template>
+ <button
+ type="button"
+ ref="dropdownButton"
+ class="dropdown-menu-toggle wide js-label-select js-multiselect js-context-config-modal"
+ data-toggle="dropdown"
+ :class="{ 'js-extra-options': showExtraOptions }"
+ :data-ability-name="abilityName"
+ :data-field-name="fieldName"
+ :data-issue-update="updatePath"
+ :data-labels="labelsPath"
+ :data-namespace-path="namespace"
+ :data-show-any="showExtraOptions"
+ >
+ <span class="dropdown-toggle-text">
+ {{ dropdownToggleText }}
+ </span>
+ <i
+ aria-hidden="true"
+ class="fa fa-chevron-down"
+ data-hidden="true"
+ >
+ </i>
+ </button>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue
new file mode 100644
index 00000000000..4200d1e8473
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue
@@ -0,0 +1,84 @@
+<script>
+export default {
+ created() {
+ this.suggestedColors = gon.suggested_label_colors;
+ },
+};
+</script>
+
+<template>
+ <div class="dropdown-page-two dropdown-new-label">
+ <div class="dropdown-title">
+ <button
+ type="button"
+ class="dropdown-title-button dropdown-menu-back"
+ :aria-label="__('Go back')"
+ >
+ <i
+ aria-hidden="true"
+ class="fa fa-arrow-left"
+ data-hidden="true"
+ >
+ </i>
+ </button>
+ {{ __('Create new label') }}
+ <button
+ type="button"
+ class="dropdown-title-button dropdown-menu-close"
+ :aria-label="__('Close')"
+ >
+ <i
+ aria-hidden="true"
+ class="fa fa-times dropdown-menu-close-icon"
+ data-hidden="true"
+ >
+ </i>
+ </button>
+ </div>
+ <div class="dropdown-content">
+ <div class="dropdown-labels-error js-label-error"></div>
+ <input
+ id="new_label_name"
+ type="text"
+ class="default-dropdown-input"
+ :placeholder="__('Name new label')"
+ />
+ <div class="suggest-colors suggest-colors-dropdown">
+ <a
+ v-for="(color, index) in suggestedColors"
+ href="#"
+ :key="index"
+ :data-color="color"
+ :style="{
+ backgroundColor: color,
+ }"
+ >
+ &nbsp;
+ </a>
+ </div>
+ <div class="dropdown-label-color-input">
+ <div class="dropdown-label-color-preview js-dropdown-label-color-preview"></div>
+ <input
+ id="new_label_color"
+ type="text"
+ class="default-dropdown-input"
+ :placeholder="__('Assign custom color like #FF0000')"
+ />
+ </div>
+ <div class="clearfix">
+ <button
+ type="button"
+ class="btn btn-primary pull-left js-new-label-btn disabled"
+ >
+ {{ __('Create') }}
+ </button>
+ <button
+ type="button"
+ class="btn btn-default pull-right js-cancel-label-btn"
+ >
+ {{ __('Cancel') }}
+ </button>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue
new file mode 100644
index 00000000000..e951a863811
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue
@@ -0,0 +1,34 @@
+<script>
+export default {
+ props: {
+ labelsWebUrl: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="dropdown-footer">
+ <ul class="dropdown-footer-list">
+ <li>
+ <a
+ href="#"
+ class="dropdown-toggle-page"
+ >
+ {{ __('Create new label') }}
+ </a>
+ </li>
+ <li>
+ <a
+ data-is-link="true"
+ class="dropdown-external-link"
+ :href="labelsWebUrl"
+ >
+ {{ __('Manage labels') }}
+ </a>
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue
new file mode 100644
index 00000000000..7664acdf19c
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue
@@ -0,0 +1,21 @@
+<script>
+export default {};
+</script>
+
+<template>
+ <div class="dropdown-title">
+ <span>{{ __('Assign labels') }}</span>
+ <button
+ type="button"
+ class="dropdown-title-button dropdown-menu-close"
+ :aria-label="__('Close')"
+ >
+ <i
+ aria-hidden="true"
+ class="fa fa-times dropdown-menu-close-icon"
+ data-hidden="true"
+ >
+ </i>
+ </button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_hidden_input.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_hidden_input.vue
new file mode 100644
index 00000000000..1832c3c1757
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_hidden_input.vue
@@ -0,0 +1,22 @@
+<script>
+export default {
+ props: {
+ name: {
+ type: String,
+ required: true,
+ },
+ label: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <input
+ type="hidden"
+ :name="name"
+ :value="label.id"
+ />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue
new file mode 100644
index 00000000000..ae633460c95
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue
@@ -0,0 +1,27 @@
+<script>
+export default {};
+</script>
+
+<template>
+ <div class="dropdown-input">
+ <input
+ autocomplete="off"
+ class="dropdown-input-field"
+ type="search"
+ :placeholder="__('Search')"
+ />
+ <i
+ aria-hidden="true"
+ class="fa fa-search dropdown-input-search"
+ data-hidden="true"
+ >
+ </i>
+ <i
+ aria-hidden="true"
+ class="fa fa-times dropdown-input-clear js-dropdown-input-clear"
+ data-hidden="true"
+ role="button"
+ >
+ </i>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue
new file mode 100644
index 00000000000..7da82e90e29
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue
@@ -0,0 +1,30 @@
+<script>
+export default {
+ props: {
+ canEdit: {
+ type: Boolean,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="title hide-collapsed append-bottom-10">
+ {{ __('Labels') }}
+ <template v-if="canEdit">
+ <i
+ aria-hidden="true"
+ class="fa fa-spinner fa-spin block-loading"
+ data-hidden="true"
+ >
+ </i>
+ <button
+ type="button"
+ class="edit-link btn btn-blank pull-right js-sidebar-dropdown-toggle"
+ >
+ {{ __('Edit') }}
+ </button>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue
new file mode 100644
index 00000000000..69d588eb25d
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue
@@ -0,0 +1,63 @@
+<script>
+import tooltip from '~/vue_shared/directives/tooltip';
+
+export default {
+ directives: {
+ tooltip,
+ },
+ props: {
+ labels: {
+ type: Array,
+ required: true,
+ },
+ labelFilterBasePath: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ isEmpty() {
+ return this.labels.length === 0;
+ },
+ },
+ methods: {
+ labelFilterUrl(label) {
+ return `${this.labelFilterBasePath}?label_name[]=${encodeURIComponent(label.title)}`;
+ },
+ labelStyle(label) {
+ return {
+ color: label.textColor,
+ backgroundColor: label.color,
+ };
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="hide-collapsed value issuable-show-labels js-value">
+ <span
+ v-if="isEmpty"
+ class="text-secondary"
+ >
+ <slot>{{ __('None') }}</slot>
+ </span>
+ <a
+ v-else
+ v-for="label in labels"
+ :key="label.id"
+ :href="labelFilterUrl(label)"
+ >
+ <span
+ v-tooltip
+ class="label color-label"
+ data-placement="bottom"
+ data-container="body"
+ :style="labelStyle(label)"
+ :title="label.description"
+ >
+ {{ label.title }}
+ </span>
+ </a>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue
new file mode 100644
index 00000000000..5cf728fe050
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue
@@ -0,0 +1,48 @@
+<script>
+import { s__, sprintf } from '~/locale';
+import tooltip from '~/vue_shared/directives/tooltip';
+
+export default {
+ directives: {
+ tooltip,
+ },
+ props: {
+ labels: {
+ type: Array,
+ required: true,
+ },
+ },
+ computed: {
+ labelsList() {
+ const labelsString = this.labels.slice(0, 5).map(label => label.title).join(', ');
+
+ if (this.labels.length > 5) {
+ return sprintf(s__('LabelSelect|%{labelsString}, and %{remainingLabelCount} more'), {
+ labelsString,
+ remainingLabelCount: this.labels.length - 5,
+ });
+ }
+
+ return labelsString;
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ v-tooltip
+ class="sidebar-collapsed-icon"
+ data-placement="left"
+ data-container="body"
+ :title="labelsList"
+ >
+ <i
+ aria-hidden="true"
+ data-hidden="true"
+ class="fa fa-tags"
+ >
+ </i>
+ <span>{{ labels.length }}</span>
+ </div>
+</template>
diff --git a/app/assets/javascripts/boards/models/label.js b/app/assets/javascripts/vue_shared/models/label.js
index 98c1ec014c4..70b9efe0c68 100644
--- a/app/assets/javascripts/boards/models/label.js
+++ b/app/assets/javascripts/vue_shared/models/label.js
@@ -1,7 +1,5 @@
-/* eslint-disable no-unused-vars, space-before-function-paren */
-
class ListLabel {
- constructor (obj) {
+ constructor(obj) {
this.id = obj.id;
this.title = obj.title;
this.type = obj.type;
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index ae517c41cb2..37d33320445 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -14,6 +14,10 @@
color: $gl-text-color-secondary;
}
+.text-tertiary {
+ color: $gl-text-color-tertiary;
+}
+
.text-primary,
.text-primary:hover {
color: $brand-primary;
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 1d7b0b602cc..127583626cf 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -272,7 +272,7 @@
.divider {
height: 1px;
- margin: 6px 0;
+ margin: #{$grid-size / 2} 0;
padding: 0;
background-color: $dropdown-divider-color;
diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss
index 88ce119ee3a..cb2f71b0033 100644
--- a/app/assets/stylesheets/framework/flash.scss
+++ b/app/assets/stylesheets/framework/flash.scss
@@ -12,6 +12,12 @@
margin: 0;
}
+ .flash-warning {
+ @extend .alert;
+ @extend .alert-warning;
+ margin: 0;
+ }
+
.flash-alert {
@extend .alert;
@extend .alert-danger;
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
index a6b1bf9b099..48b981dd31f 100644
--- a/app/assets/stylesheets/framework/modal.scss
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -2,14 +2,17 @@
background-color: $modal-body-bg;
padding: #{3 * $grid-size} #{2 * $grid-size};
- .page-title {
- margin-top: 0;
-
+ .page-title,
+ .modal-title {
.color-label {
font-size: $gl-font-size;
padding: $gl-vert-padding $label-padding-modal;
}
}
+
+ .page-title {
+ margin-top: 0;
+ }
}
.modal-body {
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 884665d35c7..58700661142 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -369,7 +369,8 @@
}
> text {
- font-size: 12px;
+ fill: $theme-gray-600;
+ font-size: 10px;
}
}
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 47672783d5a..a6ca8ed5016 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -205,7 +205,8 @@
}
.badge {
- font-size: inherit;
+ font-size: 12px;
+ line-height: 12px;
}
.panel-heading .badge-count {
diff --git a/app/controllers/admin/impersonation_tokens_controller.rb b/app/controllers/admin/impersonation_tokens_controller.rb
index 7a2c7234a1e..a7b562b1d8e 100644
--- a/app/controllers/admin/impersonation_tokens_controller.rb
+++ b/app/controllers/admin/impersonation_tokens_controller.rb
@@ -9,7 +9,6 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController
@impersonation_token = finder.build(impersonation_token_params)
if @impersonation_token.save
- flash[:impersonation_token] = @impersonation_token.token
redirect_to admin_user_impersonation_tokens_path, notice: "A new impersonation token has been created."
else
set_index_vars
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb
index 352f12a89fd..19dbee84c11 100644
--- a/app/controllers/boards/issues_controller.rb
+++ b/app/controllers/boards/issues_controller.rb
@@ -1,6 +1,9 @@
module Boards
class IssuesController < Boards::ApplicationController
include BoardsResponses
+ include ControllerWithCrossProjectAccessCheck
+
+ requires_cross_project_access if: -> { board&.group_board? }
before_action :whitelist_query_limiting, only: [:index, :update]
before_action :authorize_read_issue, only: [:index]
@@ -64,11 +67,19 @@ module Boards
end
def issues_finder
- IssuesFinder.new(current_user, project_id: board_parent.id)
+ if board.group_board?
+ IssuesFinder.new(current_user, group_id: board_parent.id)
+ else
+ IssuesFinder.new(current_user, project_id: board_parent.id)
+ end
end
def project
- board_parent
+ @project ||= if board.group_board?
+ Project.find(issue_params[:project_id])
+ else
+ board_parent
+ end
end
def move_params
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index db8c362f125..2753f83c3cf 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -56,6 +56,7 @@ module AuthenticatesWithTwoFactor
session.delete(:otp_user_id)
remember_me(user) if user_params[:remember_me] == '1'
+ user.save!
sign_in(user)
else
user.increment_failed_attempts!
diff --git a/app/controllers/concerns/boards_responses.rb b/app/controllers/concerns/boards_responses.rb
index a145049dc7d..da830ec2cb1 100644
--- a/app/controllers/concerns/boards_responses.rb
+++ b/app/controllers/concerns/boards_responses.rb
@@ -1,10 +1,46 @@
module BoardsResponses
+ include Gitlab::Utils::StrongMemoize
+
+ def board_params
+ params.require(:board).permit(:name, :weight, :milestone_id, :assignee_id, label_ids: [])
+ end
+
+ def parent
+ strong_memoize(:parent) do
+ group? ? group : project
+ end
+ end
+
+ def boards_path
+ if group?
+ group_boards_path(parent)
+ else
+ project_boards_path(parent)
+ end
+ end
+
+ def board_path(board)
+ if group?
+ group_board_path(parent, board)
+ else
+ project_board_path(parent, board)
+ end
+ end
+
+ def group?
+ instance_variable_defined?(:@group)
+ end
+
def authorize_read_list
- authorize_action_for!(board.parent, :read_list)
+ ability = board.group_board? ? :read_group : :read_list
+
+ authorize_action_for!(board.parent, ability)
end
def authorize_read_issue
- authorize_action_for!(board.parent, :read_issue)
+ ability = board.group_board? ? :read_group : :read_issue
+
+ authorize_action_for!(board.parent, ability)
end
def authorize_update_issue
@@ -31,6 +67,10 @@ module BoardsResponses
respond_with(@board) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
+ def serialize_as_json(resource)
+ resource.as_json(only: [:id])
+ end
+
def respond_with(resource)
respond_to do |format|
format.html
diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb
index 6f4fdcdaa4f..b26a76d2b62 100644
--- a/app/controllers/concerns/creates_commit.rb
+++ b/app/controllers/concerns/creates_commit.rb
@@ -4,7 +4,7 @@ module CreatesCommit
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil)
- if can?(current_user, :push_code, @project)
+ if user_access(@project).can_push_to_branch?(branch_name_or_ref)
@project_to_commit_into = @project
@branch_name ||= @ref
else
@@ -50,7 +50,7 @@ module CreatesCommit
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def authorize_edit_tree!
- return if can_collaborate_with_project?
+ return if can_collaborate_with_project?(project, ref: branch_name_or_ref)
access_denied!
end
@@ -123,4 +123,8 @@ module CreatesCommit
params[:create_merge_request].present? &&
(different_project? || @start_branch != @branch_name) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
+
+ def branch_name_or_ref
+ @branch_name || @ref # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
end
diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb
new file mode 100644
index 00000000000..7c2016f0326
--- /dev/null
+++ b/app/controllers/groups/boards_controller.rb
@@ -0,0 +1,27 @@
+class Groups::BoardsController < Groups::ApplicationController
+ include BoardsResponses
+
+ before_action :assign_endpoint_vars
+
+ def index
+ @boards = Boards::ListService.new(group, current_user).execute
+
+ respond_with_boards
+ end
+
+ def show
+ @board = group.boards.find(params[:id])
+
+ respond_with_board
+ end
+
+ def assign_endpoint_vars
+ @boards_endpoint = group_boards_url(group)
+ @namespace_path = group.to_param
+ @labels_endpoint = group_labels_url(group)
+ end
+
+ def serialize_as_json(resource)
+ resource.as_json(only: [:id])
+ end
+end
diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb
index ac1d97dc54a..58be330f466 100644
--- a/app/controllers/groups/labels_controller.rb
+++ b/app/controllers/groups/labels_controller.rb
@@ -35,10 +35,18 @@ class Groups::LabelsController < Groups::ApplicationController
def create
@label = Labels::CreateService.new(label_params).execute(group: group)
- if @label.valid?
- redirect_to group_labels_path(@group)
- else
- render :new
+ respond_to do |format|
+ format.html do
+ if @label.valid?
+ redirect_to group_labels_path(@group)
+ else
+ render :new
+ end
+ end
+
+ format.json do
+ render json: LabelSerializer.new.represent_appearance(@label)
+ end
end
end
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index 69fb8121ded..eb7d5fca367 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -42,7 +42,9 @@ class Import::GithubController < Import::BaseController
target_namespace = find_or_create_namespace(namespace_path, current_user.namespace_path)
if can?(current_user, :create_projects, target_namespace)
- project = Gitlab::LegacyGithubImport::ProjectCreator.new(repo, project_name, target_namespace, current_user, access_params, type: provider).execute
+ project = Gitlab::LegacyGithubImport::ProjectCreator
+ .new(repo, project_name, target_namespace, current_user, access_params, type: provider)
+ .execute(extra_project_attrs)
if project.persisted?
render json: ProjectSerializer.new.represent(project)
@@ -73,15 +75,15 @@ class Import::GithubController < Import::BaseController
end
def new_import_url
- public_send("new_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
+ public_send("new_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def status_import_url
- public_send("status_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
+ public_send("status_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def callback_import_url
- public_send("callback_import_#{provider}_url") # rubocop:disable GitlabSecurity/PublicSend
+ public_send("callback_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def provider_unauthorized
@@ -116,4 +118,12 @@ class Import::GithubController < Import::BaseController
def client_options
{}
end
+
+ def extra_project_attrs
+ {}
+ end
+
+ def extra_import_params
+ {}
+ end
end
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index 52430ea771f..025d8270b7c 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -62,7 +62,7 @@ class InvitesController < ApplicationController
case source
when Project
project = member.source
- label = "project #{project.name_with_namespace}"
+ label = "project #{project.full_name}"
path = project_path(project)
when Group
group = member.source
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 6025a40348b..6d9b42a2c04 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -6,7 +6,7 @@ class Projects::ApplicationController < ApplicationController
before_action :repository
layout 'project'
- helper_method :repository, :can_collaborate_with_project?
+ helper_method :repository, :can_collaborate_with_project?, :user_access
private
@@ -31,11 +31,12 @@ class Projects::ApplicationController < ApplicationController
@repository ||= project.repository
end
- def can_collaborate_with_project?(project = nil)
+ def can_collaborate_with_project?(project = nil, ref: nil)
project ||= @project
can?(current_user, :push_code, project) ||
- (current_user && current_user.already_forked?(project))
+ (current_user && current_user.already_forked?(project)) ||
+ user_access(project).can_push_to_branch?(ref)
end
def authorize_action!(action)
@@ -90,4 +91,9 @@ class Projects::ApplicationController < ApplicationController
def check_issues_available!
return render_404 unless @project.feature_available?(:issues, current_user)
end
+
+ def user_access(project)
+ @user_access ||= {}
+ @user_access[project] ||= Gitlab::UserAccess.new(current_user, project: project)
+ end
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 74c25505e36..0c1c286a0a4 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -9,8 +9,12 @@ class Projects::BlobController < Projects::ApplicationController
before_action :require_non_empty_project, except: [:new, :create]
before_action :authorize_download_code!
- before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy]
+
+ # We need to assign the blob vars before `authorize_edit_tree!` so we can
+ # validate access to a specific ref.
before_action :assign_blob_vars
+ before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy]
+
before_action :commit, except: [:new, :create]
before_action :blob, except: [:new, :create]
before_action :require_branch_head, only: [:edit, :update]
@@ -38,7 +42,7 @@ class Projects::BlobController < Projects::ApplicationController
end
format.json do
- page_title @blob.path, @ref, @project.name_with_namespace
+ page_title @blob.path, @ref, @project.full_name
show_json
end
@@ -46,7 +50,7 @@ class Projects::BlobController < Projects::ApplicationController
end
def edit
- if can_collaborate_with_project?
+ if can_collaborate_with_project?(project, ref: @ref)
blob.load_all_data!
else
redirect_to action: 'show'
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index cabafe26357..965cece600e 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -7,13 +7,19 @@ class Projects::BranchesController < Projects::ApplicationController
before_action :authorize_download_code!
before_action :authorize_push_code!, only: [:new, :create, :destroy, :destroy_all_merged]
- def index
- @sort = params[:sort].presence || sort_value_recently_updated
- @branches = BranchesFinder.new(@repository, params.merge(sort: @sort)).execute
- @branches = Kaminari.paginate_array(@branches).page(params[:page])
+ # Support legacy URLs
+ before_action :redirect_for_legacy_index_sort_or_search, only: [:index]
+ def index
respond_to do |format|
format.html do
+ @sort = params[:sort].presence || sort_value_recently_updated
+ @mode = params[:state].presence || 'overview'
+ @overview_max_branches = 5
+
+ # Fetch branches for the specified mode
+ fetch_branches_by_mode
+
@refs_pipelines = @project.pipelines.latest_successful_for_refs(@branches.map(&:name))
@merged_branch_names =
repository.merged_branch_names(@branches.map(&:name))
@@ -28,7 +34,9 @@ class Projects::BranchesController < Projects::ApplicationController
end
end
format.json do
- render json: @branches.map(&:name)
+ branches = BranchesFinder.new(@repository, params).execute
+ branches = Kaminari.paginate_array(branches).page(params[:page])
+ render json: branches.map(&:name)
end
end
end
@@ -123,4 +131,27 @@ class Projects::BranchesController < Projects::ApplicationController
context: 'autodeploy'
)
end
+
+ def redirect_for_legacy_index_sort_or_search
+ # Normalize a legacy URL with redirect
+ if request.format != :json && !params[:state].presence && [:sort, :search, :page].any? { |key| params[key].presence }
+ redirect_to project_branches_filtered_path(@project, state: 'all'), notice: 'Update your bookmarked URLs as filtered/sorted branches URL has been changed.'
+ end
+ end
+
+ def fetch_branches_by_mode
+ if @mode == 'overview'
+ # overview mode
+ @active_branches, @stale_branches = BranchesFinder.new(@repository, sort: sort_value_recently_updated).execute.partition(&:active?)
+ # Here we get one more branch to indicate if there are more data we're not showing
+ @active_branches = @active_branches.first(@overview_max_branches + 1)
+ @stale_branches = @stale_branches.first(@overview_max_branches + 1)
+ @branches = @active_branches + @stale_branches
+ else
+ # active/stale/all view mode
+ @branches = BranchesFinder.new(@repository, params.merge(sort: @sort)).execute
+ @branches = @branches.select { |b| b.state.to_s == @mode } if %w[active stale].include?(@mode)
+ @branches = Kaminari.paginate_array(@branches).page(params[:page])
+ end
+ end
end
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 3cb4eb23981..2b0c2ca97c0 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -17,10 +17,8 @@ class Projects::CompareController < Projects::ApplicationController
def show
apply_diff_view_cookie!
- # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37430
- Gitlab::GitalyClient.allow_n_plus_1_calls do
- render
- end
+
+ render
end
def diff_for_path
diff --git a/app/controllers/projects/deployments_controller.rb b/app/controllers/projects/deployments_controller.rb
index 1a418d0f15a..b68cdc39cb8 100644
--- a/app/controllers/projects/deployments_controller.rb
+++ b/app/controllers/projects/deployments_controller.rb
@@ -24,7 +24,7 @@ class Projects::DeploymentsController < Projects::ApplicationController
end
def additional_metrics
- return render_404 unless deployment.has_additional_metrics?
+ return render_404 unless deployment.has_metrics?
respond_to do |format|
format.json do
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index e0f4710175f..99790b8e7e8 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -112,12 +112,14 @@ class Projects::LabelsController < Projects::ApplicationController
begin
return render_404 unless promote_service.execute(@label)
+ flash[:notice] = "#{@label.title} promoted to group label."
respond_to do |format|
format.html do
- redirect_to(project_labels_path(@project),
- notice: 'Label was promoted to a Group Label')
+ redirect_to(project_labels_path(@project), status: 303)
+ end
+ format.json do
+ render json: { url: project_labels_path(@project) }
end
- format.js
end
rescue ActiveRecord::RecordInvalid => e
Gitlab::AppLogger.error "Failed to promote label \"#{@label.title}\" to group label"
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index 793ae03fb88..67d4ea2ca8f 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -15,6 +15,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
def merge_request_params_attributes
[
+ :allow_maintainer_to_push,
:assignee_id,
:description,
:force_remove_source_branch,
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index a1af125547c..54e7d81de6a 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -187,7 +187,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
begin
@merge_request.environments_for(current_user).map do |environment|
project = environment.project
- deployment = environment.first_deployment_for(@merge_request.diff_head_commit)
+ deployment = environment.first_deployment_for(@merge_request.diff_head_sha)
stop_url =
if environment.stop_action? && can?(current_user, :create_deployment, environment)
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 75b17d05e22..ff93147d00f 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -70,9 +70,17 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def promote
- promoted_milestone = Milestones::PromoteService.new(project, current_user).execute(milestone)
- flash[:notice] = "Milestone has been promoted to group milestone."
- redirect_to group_milestone_path(project.group, promoted_milestone.iid)
+ Milestones::PromoteService.new(project, current_user).execute(milestone)
+
+ flash[:notice] = "#{milestone.title} promoted to group milestone"
+ respond_to do |format|
+ format.html do
+ redirect_to project_milestones_path(project)
+ end
+ format.json do
+ render json: { url: project_milestones_path(project) }
+ end
+ end
rescue Milestones::PromoteService::PromoteMilestoneError => error
redirect_to milestone, alert: error.message
end
diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb
index 3b10a93e97f..35fec229db7 100644
--- a/app/controllers/projects/network_controller.rb
+++ b/app/controllers/projects/network_controller.rb
@@ -9,25 +9,22 @@ class Projects::NetworkController < Projects::ApplicationController
before_action :assign_commit
def show
- # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37602
- Gitlab::GitalyClient.allow_n_plus_1_calls do
- @url = project_network_path(@project, @ref, @options.merge(format: :json))
- @commit_url = project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")
-
- respond_to do |format|
- format.html do
- if @options[:extended_sha1] && !@commit
- flash.now[:alert] = "Git revision '#{@options[:extended_sha1]}' does not exist."
- end
- end
+ @url = project_network_path(@project, @ref, @options.merge(format: :json))
+ @commit_url = project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")
- format.json do
- @graph = Network::Graph.new(project, @ref, @commit, @options[:filter_ref])
+ respond_to do |format|
+ format.html do
+ if @options[:extended_sha1] && !@commit
+ flash.now[:alert] = "Git revision '#{@options[:extended_sha1]}' does not exist."
end
end
- render
+ format.json do
+ @graph = Network::Graph.new(project, @ref, @commit, @options[:filter_ref])
+ end
end
+
+ render
end
def assign_commit
diff --git a/app/controllers/projects/prometheus/metrics_controller.rb b/app/controllers/projects/prometheus/metrics_controller.rb
index b739d0f0f90..1dd886409a5 100644
--- a/app/controllers/projects/prometheus/metrics_controller.rb
+++ b/app/controllers/projects/prometheus/metrics_controller.rb
@@ -2,11 +2,12 @@ module Projects
module Prometheus
class MetricsController < Projects::ApplicationController
before_action :authorize_admin_project!
+ before_action :require_prometheus_metrics!
def active_common
respond_to do |format|
format.json do
- matched_metrics = prometheus_service.matched_metrics || {}
+ matched_metrics = prometheus_adapter.query(:matched_metrics) || {}
if matched_metrics.any?
render json: matched_metrics
@@ -19,8 +20,12 @@ module Projects
private
- def prometheus_service
- @prometheus_service ||= project.find_or_initialize_service('prometheus')
+ def prometheus_adapter
+ @prometheus_adapter ||= ::Prometheus::AdapterService.new(project).prometheus_adapter
+ end
+
+ def require_prometheus_metrics!
+ render_404 unless prometheus_adapter.can_query?
end
end
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index daa5c88aae0..f14cb5f6a9f 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -3,7 +3,8 @@ class Projects::ServicesController < Projects::ApplicationController
# Authorize
before_action :authorize_admin_project!
- before_action :service, only: [:edit, :update, :test]
+ before_action :ensure_service_enabled
+ before_action :service
respond_to :html
@@ -23,26 +24,30 @@ class Projects::ServicesController < Projects::ApplicationController
end
def test
- message = {}
+ if @service.can_test?
+ render json: service_test_response, status: :ok
+ else
+ render json: {}, status: :not_found
+ end
+ end
- if @service.can_test? && @service.update_attributes(service_params[:service])
+ private
+
+ def service_test_response
+ if @service.update_attributes(service_params[:service])
data = @service.test_data(project, current_user)
outcome = @service.test(data)
- unless outcome[:success]
- message = { error: true, message: 'Test failed.', service_response: outcome[:result].to_s }
+ if outcome[:success]
+ {}
+ else
+ { error: true, message: 'Test failed.', service_response: outcome[:result].to_s }
end
-
- status = :ok
else
- status = :not_found
+ { error: true, message: 'Validations failed.', service_response: @service.errors.full_messages.join(',') }
end
-
- render json: message, status: status
end
- private
-
def success_message
if @service.active?
"#{@service.title} activated."
@@ -54,4 +59,8 @@ class Projects::ServicesController < Projects::ApplicationController
def service
@service ||= @project.find_or_initialize_service(params[:id])
end
+
+ def ensure_service_enabled
+ render_404 unless service
+ end
end
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index 86717bb7242..259809f3429 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -13,12 +13,14 @@ module Projects
def reset_cache
if ResetProjectCacheService.new(@project, current_user).execute
- flash[:notice] = _("Project cache successfully reset.")
+ respond_to do |format|
+ format.json { head :ok }
+ end
else
- flash[:error] = _("Unable to reset project cache.")
+ respond_to do |format|
+ format.json { head :bad_request }
+ end
end
-
- redirect_to project_pipelines_path(@project)
end
private
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index f752a46f828..ee9b5458282 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -36,7 +36,7 @@ class Projects::TreeController < Projects::ApplicationController
end
format.json do
- page_title @path.presence || _("Files"), @ref, @project.name_with_namespace
+ page_title @path.presence || _("Files"), @ref, @project.full_name
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/38261
Gitlab::GitalyClient.allow_n_plus_1_calls do
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 913689a1e74..ee197c75764 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -41,11 +41,11 @@ class ProjectsController < Projects::ApplicationController
cookies[:issue_board_welcome_hidden] = { path: project_path(@project), value: nil, expires: Time.at(0) }
redirect_to(
- project_path(@project),
+ project_path(@project, custom_import_params),
notice: _("Project '%{project_name}' was successfully created.") % { project_name: @project.name }
)
else
- render 'new', locals: { active_tab: ('import' if project_params[:import_url].present?) }
+ render 'new', locals: { active_tab: active_new_project_tab }
end
end
@@ -103,7 +103,7 @@ class ProjectsController < Projects::ApplicationController
def show
if @project.import_in_progress?
- redirect_to project_import_path(@project)
+ redirect_to project_import_path(@project, custom_import_params)
return
end
@@ -130,7 +130,7 @@ class ProjectsController < Projects::ApplicationController
return access_denied! unless can?(current_user, :remove_project, @project)
::Projects::DestroyService.new(@project, current_user, {}).async_execute
- flash[:notice] = _("Project '%{project_name}' is in the process of being deleted.") % { project_name: @project.name_with_namespace }
+ flash[:notice] = _("Project '%{project_name}' is in the process of being deleted.") % { project_name: @project.full_name }
redirect_to dashboard_projects_path, status: 302
rescue Projects::DestroyService::DestroyError => ex
@@ -359,6 +359,14 @@ class ProjectsController < Projects::ApplicationController
]
end
+ def custom_import_params
+ {}
+ end
+
+ def active_new_project_tab
+ project_params[:import_url].present? ? 'import' : 'blank'
+ end
+
def repo_exists?
project.repository_exists? && !project.empty_repo?
diff --git a/app/finders/branches_finder.rb b/app/finders/branches_finder.rb
index 852eac3647d..8bb1366867c 100644
--- a/app/finders/branches_finder.rb
+++ b/app/finders/branches_finder.rb
@@ -1,5 +1,5 @@
class BranchesFinder
- def initialize(repository, params)
+ def initialize(repository, params = {})
@repository = repository
@params = params
end
diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb
index 47c8b9b60ed..150f4c7688b 100644
--- a/app/finders/todos_finder.rb
+++ b/app/finders/todos_finder.rb
@@ -150,9 +150,7 @@ class TodosFinder
if project?
items.where(project: project)
else
- projects = Project
- .public_or_visible_to_user(current_user)
- .order_id_desc
+ projects = Project.public_or_visible_to_user(current_user)
items.joins(:project).merge(projects)
end
diff --git a/app/finders/user_recent_events_finder.rb b/app/finders/user_recent_events_finder.rb
index 6f7f7c30d92..65d6e019746 100644
--- a/app/finders/user_recent_events_finder.rb
+++ b/app/finders/user_recent_events_finder.rb
@@ -12,6 +12,8 @@ class UserRecentEventsFinder
attr_reader :current_user, :target_user, :params
+ LIMIT = 20
+
def initialize(current_user, target_user, params = {})
@current_user = current_user
@target_user = target_user
@@ -19,15 +21,44 @@ class UserRecentEventsFinder
end
def execute
- target_user
- .recent_events
- .merge(projects_for_current_user)
- .references(:project)
+ recent_events(params[:offset] || 0)
+ .joins(:project)
.with_associations
- .limit_recent(20, params[:offset])
+ .limit_recent(LIMIT, params[:offset])
+ end
+
+ private
+
+ def recent_events(offset)
+ sql = <<~SQL
+ (#{projects}) AS projects_for_join
+ JOIN (#{target_events.to_sql}) AS #{Event.table_name}
+ ON #{Event.table_name}.project_id = projects_for_join.id
+ SQL
+
+ # Workaround for https://github.com/rails/rails/issues/24193
+ Event.from([Arel.sql(sql)])
end
- def projects_for_current_user
- ProjectsFinder.new(current_user: current_user).execute
+ def target_events
+ Event.where(author: target_user)
+ end
+
+ def projects
+ # Compile a list of projects `current_user` interacted with
+ # and `target_user` is allowed to see.
+
+ authorized = target_user
+ .project_interactions
+ .joins(:project_authorizations)
+ .where(project_authorizations: { user: current_user })
+ .select(:id)
+
+ visible = target_user
+ .project_interactions
+ .where(visibility_level: [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC])
+ .select(:id)
+
+ Gitlab::SQL::Union.new([authorized, visible]).to_sql
end
end
diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb
index 12b3d9bac1a..275e892b2e6 100644
--- a/app/helpers/boards_helper.rb
+++ b/app/helpers/boards_helper.rb
@@ -17,23 +17,35 @@ module BoardsHelper
end
def build_issue_link_base
- project_issues_path(@project)
+ if board.group_board?
+ "#{group_path(@board.group)}/:project_path/issues"
+ else
+ project_issues_path(@project)
+ end
end
def board_base_url
- project_boards_path(@project)
+ if board.group_board?
+ group_boards_url(@group)
+ else
+ project_boards_path(@project)
+ end
end
def multiple_boards_available?
- current_board_parent.multiple_issue_boards_available?(current_user)
+ current_board_parent.multiple_issue_boards_available?
end
def current_board_path(board)
- @current_board_path ||= project_board_path(current_board_parent, board)
+ @current_board_path ||= if board.group_board?
+ group_board_path(current_board_parent, board)
+ else
+ project_board_path(current_board_parent, board)
+ end
end
def current_board_parent
- @current_board_parent ||= @project
+ @current_board_parent ||= @group || @project
end
def can_admin_issue?
@@ -47,7 +59,8 @@ module BoardsHelper
labels: labels_filter_path(true),
labels_endpoint: @labels_endpoint,
namespace_path: @namespace_path,
- project_path: @project&.try(:path)
+ project_path: @project&.path,
+ group_path: @group&.path
}
end
@@ -59,7 +72,8 @@ module BoardsHelper
field_name: 'issue[assignee_ids][]',
first_user: current_user&.username,
current_user: 'true',
- project_id: @project&.try(:id),
+ project_id: @project&.id,
+ group_id: @group&.id,
null_user: 'true',
multi_select: 'true',
'dropdown-header': dropdown_options[:data][:'dropdown-header'],
diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb
index 00b9a0e00eb..07b1fc3d7cf 100644
--- a/app/helpers/branches_helper.rb
+++ b/app/helpers/branches_helper.rb
@@ -1,15 +1,4 @@
module BranchesHelper
- def filter_branches_path(options = {})
- exist_opts = {
- search: params[:search],
- sort: params[:sort]
- }
-
- options = exist_opts.merge(options)
-
- project_branches_path(@project, @id, options)
- end
-
def project_branches
options_for_select(@project.repository.branch_names, @project.default_branch)
end
diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb
index e26ce6da030..905e2002592 100644
--- a/app/helpers/form_helper.rb
+++ b/app/helpers/form_helper.rb
@@ -27,7 +27,7 @@ module FormHelper
first_user: current_user&.username,
null_user: true,
current_user: true,
- project_id: @project.id,
+ project_id: @project&.id,
field_name: 'issue[assignee_ids][]',
default_label: 'Unassigned',
'max-select': 1,
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 7910de73c52..16eceb3f48f 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -129,7 +129,7 @@ module GroupsHelper
links = [:overview, :group_members]
if can?(current_user, :read_cross_project)
- links += [:activity, :issues, :labels, :milestones, :merge_requests]
+ links += [:activity, :issues, :boards, :labels, :milestones, :merge_requests]
end
if can?(current_user, :admin_group, @group)
diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb
index a18ebfb6030..9149d79ecb8 100644
--- a/app/helpers/import_helper.rb
+++ b/app/helpers/import_helper.rb
@@ -1,19 +1,81 @@
module ImportHelper
+ def has_ci_cd_only_params?
+ false
+ end
+
def import_project_target(owner, name)
namespace = current_user.can_create_group? ? owner : current_user.namespace_path
"#{namespace}/#{name}"
end
- def provider_project_link(provider, path_with_namespace)
- url = __send__("#{provider}_project_url", path_with_namespace) # rubocop:disable GitlabSecurity/PublicSend
+ def provider_project_link(provider, full_path)
+ url = __send__("#{provider}_project_url", full_path) # rubocop:disable GitlabSecurity/PublicSend
+
+ link_to full_path, url, target: '_blank', rel: 'noopener noreferrer'
+ end
+
+ def import_will_timeout_message(_ci_cd_only)
+ timeout = time_interval_in_words(Gitlab.config.gitlab_shell.git_timeout)
+ _('The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination.') % { timeout: timeout }
+ end
+
+ def import_svn_message(_ci_cd_only)
+ svn_link = link_to _('this document'), help_page_path('user/project/import/svn')
+ _('To import an SVN repository, check out %{svn_link}.').html_safe % { svn_link: svn_link }
+ end
+
+ def import_in_progress_title
+ if @project.forked?
+ _('Forking in progress')
+ else
+ _('Import in progress')
+ end
+ end
+
+ def import_wait_and_refresh_message
+ _('Please wait while we import the repository for you. Refresh at will.')
+ end
+
+ def import_github_title
+ _('Import repositories from GitHub')
+ end
+
+ def import_github_authorize_message
+ _('To import GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:')
+ end
+
+ def import_github_personal_access_token_message
+ personal_access_token_link = link_to _('Personal Access Token'), 'https://github.com/settings/tokens'
+
+ if github_import_configured?
+ _('Alternatively, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import.').html_safe % { personal_access_token_link: personal_access_token_link }
+ else
+ _('To import GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import.').html_safe % { personal_access_token_link: personal_access_token_link }
+ end
+ end
+
+ def import_configure_github_admin_message
+ github_integration_link = link_to 'GitHub integration', help_page_path('integration/github')
+
+ if current_user.admin?
+ _('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.').html_safe % { github_integration_link: github_integration_link }
+ else
+ _('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.').html_safe % { github_integration_link: github_integration_link }
+ end
+ end
+
+ def import_githubish_choose_repository_message
+ _('Choose which repositories you want to import.')
+ end
- link_to path_with_namespace, url, target: '_blank', rel: 'noopener noreferrer'
+ def import_all_githubish_repositories_button_label
+ _('Import all repositories')
end
private
- def github_project_url(path_with_namespace)
- "#{github_root_url}/#{path_with_namespace}"
+ def github_project_url(full_path)
+ "#{github_root_url}/#{full_path}"
end
def github_root_url
@@ -23,7 +85,7 @@ module ImportHelper
@github_url = provider.fetch('url', 'https://github.com') if provider
end
- def gitea_project_url(path_with_namespace)
- "#{@gitea_host_url.sub(%r{/+\z}, '')}/#{path_with_namespace}"
+ def gitea_project_url(full_path)
+ "#{@gitea_host_url.sub(%r{/+\z}, '')}/#{full_path}"
end
end
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 44ecc2212f2..f6ddb6d4cfe 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -99,7 +99,7 @@ module IssuablesHelper
project = Project.find_by(id: project_id)
if project
- project.name_with_namespace
+ project.full_name
else
default_label
end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index c1c19062c91..b2c641a5dbd 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -1,4 +1,5 @@
module LabelsHelper
+ extend self
include ActionView::Helpers::TagHelper
def show_label_issuables_link?(label, issuables_type, current_user: nil, project: nil)
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index ce57422f45d..fb4fe1c40b7 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -125,6 +125,19 @@ module MergeRequestsHelper
link_to(url[merge_request.project, merge_request], data: data_attrs, &block)
end
+ def allow_maintainer_push_unavailable_reason(merge_request)
+ return if merge_request.can_allow_maintainer_to_push?(current_user)
+
+ minimum_visibility = [merge_request.target_project.visibility_level,
+ merge_request.source_project.visibility_level].min
+
+ if minimum_visibility < Gitlab::VisibilityLevel::INTERNAL
+ _('Not available for private projects')
+ elsif ProtectedBranch.protected?(merge_request.source_project, merge_request.source_branch)
+ _('Not available for protected branches')
+ end
+ end
+
def merge_params_ee(merge_request)
{}
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index cc1c69a1999..da9fe734f1c 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -97,13 +97,13 @@ module ProjectsHelper
end
def remove_project_message(project)
- _("You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?") %
- { project_name_with_namespace: project.name_with_namespace }
+ _("You are going to remove %{project_full_name}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?") %
+ { project_full_name: project.full_name }
end
def transfer_project_message(project)
- _("You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?") %
- { project_name_with_namespace: project.name_with_namespace }
+ _("You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?") %
+ { project_full_name: project.full_name }
end
def remove_fork_project_message(project)
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index e6a6496871a..761c1252fc8 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -110,7 +110,7 @@ module SearchHelper
category: "Projects",
id: p.id,
value: "#{search_result_sanitize(p.name)}",
- label: "#{search_result_sanitize(p.name_with_namespace)}",
+ label: "#{search_result_sanitize(p.full_name)}",
url: project_path(p)
}
end
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index ddb48371c79..f7620e0b6b8 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -114,7 +114,7 @@ module TodosHelper
projects = current_user.authorized_projects.sorted_by_activity.non_archived.with_route
projects = projects.map do |project|
- { id: project.id, text: project.name_with_namespace }
+ { id: project.id, text: project.full_name }
end
projects.unshift({ id: '', text: 'Any Project' }).to_json
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index f6a6d9bebde..b64be89c181 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -49,15 +49,13 @@ module TreeHelper
return false unless on_top_of_branch?(project, ref)
- can_collaborate_with_project?(project)
+ can_collaborate_with_project?(project, ref: ref)
end
def tree_edit_branch(project = @project, ref = @ref)
return unless can_edit_tree?(project, ref)
- project = project.present(current_user: current_user)
-
- if project.can_current_user_push_to_branch?(ref)
+ if user_access(project).can_push_to_branch?(ref)
ref
else
project = tree_edit_project(project)
@@ -88,7 +86,16 @@ module TreeHelper
end
def commit_in_fork_help
- "A new branch will be created in your fork and a new merge request will be started."
+ _("A new branch will be created in your fork and a new merge request will be started.")
+ end
+
+ def commit_in_single_accessible_branch
+ branch_name = html_escape(selected_branch)
+
+ message = _("Your changes can be committed to %{branch_name} because a merge "\
+ "request is open.") % { branch_name: "<strong>#{branch_name}</strong>" }
+
+ message.html_safe
end
def path_breadcrumbs(max_links = 6)
@@ -125,4 +132,8 @@ module TreeHelper
return tree.name
end
end
+
+ def selected_branch
+ @branch_name || tree_edit_branch
+ end
end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 45d4fb451d8..e4212775956 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -117,7 +117,7 @@ class Notify < BaseMailer
if Gitlab::IncomingEmail.enabled? && @sent_notification
address = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key))
- address.display_name = @project.name_with_namespace
+ address.display_name = @project.full_name
headers['Reply-To'] = address
diff --git a/app/models/badge.rb b/app/models/badge.rb
new file mode 100644
index 00000000000..f7e10c2ebfc
--- /dev/null
+++ b/app/models/badge.rb
@@ -0,0 +1,51 @@
+class Badge < ActiveRecord::Base
+ # This structure sets the placeholders that the urls
+ # can have. This hash also sets which action to ask when
+ # the placeholder is found.
+ PLACEHOLDERS = {
+ 'project_path' => :full_path,
+ 'project_id' => :id,
+ 'default_branch' => :default_branch,
+ 'commit_sha' => ->(project) { project.commit&.sha }
+ }.freeze
+
+ # This regex is built dynamically using the keys from the PLACEHOLDER struct.
+ # So, we can easily add new placeholder just by modifying the PLACEHOLDER hash.
+ # This regex will build the new PLACEHOLDER_REGEX with the new information
+ PLACEHOLDERS_REGEX = /(#{PLACEHOLDERS.keys.join('|')})/.freeze
+
+ default_scope { order_created_at_asc }
+
+ scope :order_created_at_asc, -> { reorder(created_at: :asc) }
+
+ validates :link_url, :image_url, url_placeholder: { protocols: %w(http https), placeholder_regex: PLACEHOLDERS_REGEX }
+ validates :type, presence: true
+
+ def rendered_link_url(project = nil)
+ build_rendered_url(link_url, project)
+ end
+
+ def rendered_image_url(project = nil)
+ build_rendered_url(image_url, project)
+ end
+
+ private
+
+ def build_rendered_url(url, project = nil)
+ return url unless valid? && project
+
+ Gitlab::StringPlaceholderReplacer.replace_string_placeholders(url, PLACEHOLDERS_REGEX) do |arg|
+ replace_placeholder_action(PLACEHOLDERS[arg], project)
+ end
+ end
+
+ # The action param represents the :symbol or Proc to call in order
+ # to retrieve the return value from the project.
+ # This method checks if it is a Proc and use the call method, and if it is
+ # a symbol just send the action
+ def replace_placeholder_action(action, project)
+ return unless project
+
+ action.is_a?(Proc) ? action.call(project) : project.public_send(action) # rubocop:disable GitlabSecurity/PublicSend
+ end
+end
diff --git a/app/models/badges/group_badge.rb b/app/models/badges/group_badge.rb
new file mode 100644
index 00000000000..f4b2bdecdcc
--- /dev/null
+++ b/app/models/badges/group_badge.rb
@@ -0,0 +1,5 @@
+class GroupBadge < Badge
+ belongs_to :group
+
+ validates :group, presence: true
+end
diff --git a/app/models/badges/project_badge.rb b/app/models/badges/project_badge.rb
new file mode 100644
index 00000000000..3945b376052
--- /dev/null
+++ b/app/models/badges/project_badge.rb
@@ -0,0 +1,15 @@
+class ProjectBadge < Badge
+ belongs_to :project
+
+ validates :project, presence: true
+
+ def rendered_link_url(project = nil)
+ project ||= self.project
+ super
+ end
+
+ def rendered_image_url(project = nil)
+ project ||= self.project
+ super
+ end
+end
diff --git a/app/models/board.rb b/app/models/board.rb
index 5bb7d3d3722..3cede6fc99a 100644
--- a/app/models/board.rb
+++ b/app/models/board.rb
@@ -1,20 +1,22 @@
class Board < ActiveRecord::Base
+ belongs_to :group
belongs_to :project
has_many :lists, -> { order(:list_type, :position) }, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
validates :project, presence: true, if: :project_needed?
+ validates :group, presence: true, unless: :project
def project_needed?
- true
+ !group
end
def parent
- project
+ @parent ||= group || project
end
def group_board?
- false
+ group_id.present?
end
def backlog_list
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index 89ebd63e605..7b25d8c4089 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -1,6 +1,8 @@
module Clusters
module Applications
class Prometheus < ActiveRecord::Base
+ include PrometheusAdapter
+
VERSION = "2.0.0".freeze
self.table_name = 'clusters_applications_prometheus'
@@ -39,7 +41,7 @@ module Clusters
)
end
- def proxy_client
+ def prometheus_client
return unless kube_client
proxy_url = kube_client.proxy_url('service', service_name, service_port, Gitlab::Kubernetes::Helm::NAMESPACE)
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index 7adf1663c35..16efe90fa27 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -56,12 +56,13 @@ module Clusters
def specification
{
"gitlabUrl" => gitlab_url,
- "runnerToken" => ensure_runner.token
+ "runnerToken" => ensure_runner.token,
+ "runners" => { "privileged" => privileged }
}
end
def content_values
- specification.merge(YAML.load_file(chart_values_file))
+ YAML.load_file(chart_values_file).deep_merge!(specification)
end
end
end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 1c0046107d7..49eb069016a 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -51,9 +51,6 @@ module Clusters
scope :enabled, -> { where(enabled: true) }
scope :disabled, -> { where(enabled: false) }
- scope :for_environment, -> (env) { where(environment_scope: ['*', '', env.slug]) }
- scope :for_all_environments, -> { where(environment_scope: ['*', '']) }
-
def status_name
if provider
provider.status_name
diff --git a/app/models/commit.rb b/app/models/commit.rb
index b9106309142..cceae5efb72 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -9,6 +9,7 @@ class Commit
include Mentionable
include Referable
include StaticModel
+ include ::Gitlab::Utils::StrongMemoize
attr_mentionable :safe_message, pipeline: :single_line
@@ -225,11 +226,13 @@ class Commit
end
def parents
- @parents ||= parent_ids.map { |id| project.commit(id) }
+ @parents ||= parent_ids.map { |oid| Commit.lazy(project, oid) }
end
def parent
- @parent ||= project.commit(self.parent_id) if self.parent_id
+ strong_memoize(:parent) do
+ project.commit_by(oid: self.parent_id) if self.parent_id
+ end
end
def notes
diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb
index 89d0474a596..faa94204e33 100644
--- a/app/models/concerns/deployment_platform.rb
+++ b/app/models/concerns/deployment_platform.rb
@@ -1,5 +1,6 @@
module DeploymentPlatform
- def deployment_platform
+ # EE would override this and utilize the extra argument
+ def deployment_platform(environment: nil)
@deployment_platform ||=
find_cluster_platform_kubernetes ||
find_kubernetes_service_integration ||
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 4560bc23193..5a566f3ac02 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -223,6 +223,10 @@ module Issuable
def to_ability_name
model_name.singular
end
+
+ def parent_class
+ ::Project
+ end
end
def today?
diff --git a/app/models/concerns/prometheus_adapter.rb b/app/models/concerns/prometheus_adapter.rb
new file mode 100644
index 00000000000..18cbbd871a1
--- /dev/null
+++ b/app/models/concerns/prometheus_adapter.rb
@@ -0,0 +1,48 @@
+module PrometheusAdapter
+ extend ActiveSupport::Concern
+
+ included do
+ include ReactiveCaching
+
+ self.reactive_cache_key = ->(adapter) { [adapter.class.model_name.singular, adapter.id] }
+ self.reactive_cache_lease_timeout = 30.seconds
+ self.reactive_cache_refresh_interval = 30.seconds
+ self.reactive_cache_lifetime = 1.minute
+
+ def prometheus_client
+ raise NotImplementedError
+ end
+
+ def prometheus_client_wrapper
+ Gitlab::PrometheusClient.new(prometheus_client)
+ end
+
+ def can_query?
+ prometheus_client.present?
+ end
+
+ def query(query_name, *args)
+ return unless can_query?
+
+ query_class = Gitlab::Prometheus::Queries.const_get("#{query_name.to_s.classify}Query")
+
+ args.map!(&:id)
+
+ with_reactive_cache(query_class.name, *args, &query_class.method(:transform_reactive_result))
+ end
+
+ # Cache metrics for specific environment
+ def calculate_reactive_cache(query_class_name, *args)
+ return unless prometheus_client
+
+ data = Kernel.const_get(query_class_name).new(prometheus_client_wrapper).query(*args)
+ {
+ success: true,
+ data: data,
+ last_update: Time.now.utc
+ }
+ rescue Gitlab::PrometheusClient::Error => err
+ { success: false, result: err.message }
+ end
+ end
+end
diff --git a/app/models/cycle_analytics/summary.rb b/app/models/cycle_analytics/summary.rb
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/app/models/cycle_analytics/summary.rb
+++ /dev/null
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index b6cf168d60e..66e61c06765 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -98,28 +98,29 @@ class Deployment < ActiveRecord::Base
end
def has_metrics?
- project.monitoring_service.present?
+ prometheus_adapter&.can_query?
end
def metrics
return {} unless has_metrics?
- project.monitoring_service.deployment_metrics(self)
- end
-
- def has_additional_metrics?
- project.prometheus_service.present?
+ metrics = prometheus_adapter.query(:deployment, self)
+ metrics&.merge(deployment_time: created_at.to_i) || {}
end
def additional_metrics
- return {} unless project.prometheus_service.present?
+ return {} unless has_metrics?
- metrics = project.prometheus_service.additional_deployment_metrics(self)
+ metrics = prometheus_adapter.query(:additional_metrics_deployment, self)
metrics&.merge(deployment_time: created_at.to_i) || {}
end
private
+ def prometheus_adapter
+ environment.prometheus_adapter
+ end
+
def ref_path
File.join(environment.ref_path, 'deployments', iid.to_s)
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index f78c21aebe5..2b0a88ac5b4 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -99,8 +99,8 @@ class Environment < ActiveRecord::Base
folder_name == "production"
end
- def first_deployment_for(commit)
- ref = project.repository.ref_name_for_sha(ref_path, commit.sha)
+ def first_deployment_for(commit_sha)
+ ref = project.repository.ref_name_for_sha(ref_path, commit_sha)
return nil unless ref
@@ -146,21 +146,19 @@ class Environment < ActiveRecord::Base
end
def has_metrics?
- project.monitoring_service.present? && available? && last_deployment.present?
+ prometheus_adapter&.can_query? && available? && last_deployment.present?
end
def metrics
- project.monitoring_service.environment_metrics(self) if has_metrics?
+ prometheus_adapter.query(:environment, self) if has_metrics?
end
- def has_additional_metrics?
- project.prometheus_service.present? && available? && last_deployment.present?
+ def additional_metrics
+ prometheus_adapter.query(:additional_metrics_environment, self) if has_metrics?
end
- def additional_metrics
- if has_additional_metrics?
- project.prometheus_service.additional_environment_metrics(self)
- end
+ def prometheus_adapter
+ @prometheus_adapter ||= Prometheus::AdapterService.new(project, deployment_platform).prometheus_adapter
end
def slug
@@ -226,6 +224,10 @@ class Environment < ActiveRecord::Base
self.environment_type || self.name
end
+ def deployment_platform
+ project.deployment_platform(environment: self)
+ end
+
private
# Slugifying a name may remove the uniqueness guarantee afforded by it being
diff --git a/app/models/event.rb b/app/models/event.rb
index 75538ba196c..17a198d52c7 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -65,6 +65,7 @@ class Event < ActiveRecord::Base
# Callbacks
after_create :reset_project_activity
after_create :set_last_repository_updated_at, if: :push?
+ after_create :track_user_interacted_projects
# Scopes
scope :recent, -> { reorder(id: :desc) }
@@ -158,7 +159,7 @@ class Event < ActiveRecord::Base
def project_name
if project
- project.name_with_namespace
+ project.full_name
else
"(deleted project)"
end
@@ -389,4 +390,11 @@ class Event < ActiveRecord::Base
Project.unscoped.where(id: project_id)
.update_all(last_repository_updated_at: created_at)
end
+
+ def track_user_interacted_projects
+ # Note the call to .available? is due to earlier migrations
+ # that would otherwise conflict with the call to .track
+ # (because the table does not exist yet).
+ UserInteractedProject.track(self) if UserInteractedProject.available?
+ end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 75bf013ecd2..8d183006c65 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -31,6 +31,9 @@ class Group < Namespace
has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_many :boards
+ has_many :badges, class_name: 'GroupBadge'
+
accepts_nested_attributes_for :variables, allow_destroy: true
validate :visibility_level_allowed_by_projects
diff --git a/app/models/label.rb b/app/models/label.rb
index 7538f2d8718..de7f1d56c64 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -35,6 +35,7 @@ class Label < ActiveRecord::Base
scope :templates, -> { where(template: true) }
scope :with_title, ->(title) { where(title: title) }
scope :with_lists_and_board, -> { joins(lists: :board).merge(List.movable) }
+ scope :on_group_boards, ->(group_id) { with_lists_and_board.where(boards: { group_id: group_id }) }
scope :on_project_boards, ->(project_id) { with_lists_and_board.where(boards: { project_id: project_id }) }
def self.prioritized(project)
diff --git a/app/models/member.rb b/app/models/member.rb
index 408e8b2d704..36090676051 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -85,6 +85,7 @@ class Member < ActiveRecord::Base
after_create :create_notification_setting, unless: [:pending?, :importing?]
after_create :post_create_hook, unless: [:pending?, :importing?]
after_update :post_update_hook, unless: [:pending?, :importing?]
+ after_destroy :destroy_notification_setting
after_destroy :post_destroy_hook, unless: :pending?
after_commit :refresh_member_authorized_projects
@@ -315,6 +316,10 @@ class Member < ActiveRecord::Base
user.notification_settings.find_or_create_for(source)
end
+ def destroy_notification_setting
+ notification_setting&.destroy
+ end
+
def notification_setting
@notification_setting ||= user&.notification_settings_for(source)
end
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index b6f1dd272cd..1c7ed4a96df 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -13,8 +13,6 @@ class ProjectMember < Member
scope :in_project, ->(project) { where(source_id: project.id) }
- before_destroy :delete_member_todos
-
class << self
# Add users to projects with passed access option
#
@@ -93,10 +91,6 @@ class ProjectMember < Member
private
- def delete_member_todos
- user.todos.where(project_id: source_id).destroy_all if user
- end
-
def send_invite
notification_service.invite_project_member(self, @raw_invite_token)
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 5bec68ce4f6..c2bae379a94 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -375,15 +375,27 @@ class MergeRequest < ActiveRecord::Base
end
def diff_start_sha
- diff_start_commit.try(:sha)
+ if persisted?
+ merge_request_diff.start_commit_sha
+ else
+ target_branch_head.try(:sha)
+ end
end
def diff_base_sha
- diff_base_commit.try(:sha)
+ if persisted?
+ merge_request_diff.base_commit_sha
+ else
+ branch_merge_base_commit.try(:sha)
+ end
end
def diff_head_sha
- diff_head_commit.try(:sha)
+ if persisted?
+ merge_request_diff.head_commit_sha
+ else
+ source_branch_head.try(:sha)
+ end
end
# When importing a pull request from GitHub, the old and new branches may no
@@ -646,7 +658,7 @@ class MergeRequest < ActiveRecord::Base
!ProtectedBranch.protected?(source_project, source_branch) &&
!source_project.root_ref?(source_branch) &&
Ability.allowed?(current_user, :push_code, source_project) &&
- diff_head_commit == source_branch_head
+ diff_head_sha == source_branch_head.try(:sha)
end
def should_remove_source_branch?
@@ -853,7 +865,7 @@ class MergeRequest < ActiveRecord::Base
def can_be_merged_by?(user)
access = ::Gitlab::UserAccess.new(user, project: project)
- access.can_push_to_branch?(target_branch) || access.can_merge_to_branch?(target_branch)
+ access.can_update_branch?(target_branch)
end
def can_be_merged_via_command_line_by?(user)
@@ -1075,4 +1087,22 @@ class MergeRequest < ActiveRecord::Base
project.merge_requests.merged.where(author_id: author_id).empty?
end
+
+ def allow_maintainer_to_push
+ maintainer_push_possible? && super
+ end
+
+ alias_method :allow_maintainer_to_push?, :allow_maintainer_to_push
+
+ def maintainer_push_possible?
+ source_project.present? && for_fork? &&
+ target_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
+ source_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
+ !ProtectedBranch.protected?(source_project, source_branch)
+ end
+
+ def can_allow_maintainer_to_push?(user)
+ maintainer_push_possible? &&
+ Ability.allowed?(user, :push_code, source_project)
+ end
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index db274ea8172..e350b675639 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -222,6 +222,11 @@ class Namespace < ActiveRecord::Base
has_parent?
end
+ # Overridden on EE module
+ def multiple_issue_boards_available?
+ false
+ end
+
def full_path_was
if parent_id_was.nil?
path_was
diff --git a/app/models/network/commit.rb b/app/models/network/commit.rb
index 9357e55b419..22d48c9e661 100644
--- a/app/models/network/commit.rb
+++ b/app/models/network/commit.rb
@@ -24,12 +24,7 @@ module Network
end
def parents(map)
- @commit.parents.map do |p|
- if map.include?(p.id)
- map[p.id]
- end
- end
- .compact
+ map.values_at(*@commit.parent_ids).compact
end
end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index d7a67ec277c..787a80f0196 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -81,7 +81,7 @@ class Note < ActiveRecord::Base
validates :author, presence: true
validates :discussion_id, presence: true, format: { with: /\A\h{40}\z/ }
- validate unless: [:for_commit?, :importing?, :for_personal_snippet?] do |note|
+ validate unless: [:for_commit?, :importing?, :skip_project_check?] do |note|
unless note.noteable.try(:project) == note.project
errors.add(:project, 'does not match noteable project')
end
@@ -228,7 +228,7 @@ class Note < ActiveRecord::Base
end
def skip_project_check?
- for_personal_snippet?
+ !for_project_noteable?
end
def commit
@@ -308,6 +308,11 @@ class Note < ActiveRecord::Base
self.noteable.supports_discussions? && !part_of_discussion?
end
+ def can_create_todo?
+ # Skip system notes, and notes on project snippet
+ !system? && !for_snippet?
+ end
+
def discussion_class(noteable = nil)
# When commit notes are rendered on an MR's Discussion page, they are
# displayed in one discussion instead of individually.
diff --git a/app/models/project.rb b/app/models/project.rb
index 5b1f8b2658b..5f9d9785d64 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -150,6 +150,7 @@ class Project < ActiveRecord::Base
# Merge Requests for target project should be removed with it
has_many :merge_requests, foreign_key: 'target_project_id'
+ has_many :source_of_merge_requests, foreign_key: 'source_project_id', class_name: 'MergeRequest'
has_many :issues
has_many :labels, class_name: 'ProjectLabel'
has_many :services
@@ -221,6 +222,8 @@ class Project < ActiveRecord::Base
has_one :auto_devops, class_name: 'ProjectAutoDevops'
has_many :custom_attributes, class_name: 'ProjectCustomAttribute'
+ has_many :project_badges, class_name: 'ProjectBadge'
+
accepts_nested_attributes_for :variables, allow_destroy: true
accepts_nested_attributes_for :project_feature, update_only: true
accepts_nested_attributes_for :import_data
@@ -274,7 +277,8 @@ class Project < ActiveRecord::Base
scope :without_storage_feature, ->(feature) { where('storage_version < :version OR storage_version IS NULL', version: HASHED_STORAGE_FEATURES[feature]) }
scope :with_unmigrated_storage, -> { where('storage_version < :version OR storage_version IS NULL', version: LATEST_STORAGE_VERSION) }
- scope :sorted_by_activity, -> { reorder(last_activity_at: :desc) }
+ # last_activity_at is throttled every minute, but last_repository_updated_at is updated with every push
+ scope :sorted_by_activity, -> { reorder("GREATEST(COALESCE(last_activity_at, '1970-01-01'), COALESCE(last_repository_updated_at, '1970-01-01')) DESC") }
scope :sorted_by_stars, -> { reorder('projects.star_count DESC') }
scope :in_namespace, ->(namespace_ids) { where(namespace_id: namespace_ids) }
@@ -776,7 +780,7 @@ class Project < ActiveRecord::Base
end
def last_activity_date
- last_repository_updated_at || last_activity_at || updated_at
+ [last_activity_at, last_repository_updated_at, updated_at].compact.max
end
def project_id
@@ -1525,16 +1529,34 @@ class Project < ActiveRecord::Base
end
end
+ def import_export_shared
+ @import_export_shared ||= Gitlab::ImportExport::Shared.new(self)
+ end
+
def export_path
return nil unless namespace.present? || hashed_storage?(:repository)
- File.join(Gitlab::ImportExport.storage_path, disk_path)
+ import_export_shared.archive_path
end
def export_project_path
Dir.glob("#{export_path}/*export.tar.gz").max_by { |f| File.ctime(f) }
end
+ def export_status
+ if export_in_progress?
+ :started
+ elsif export_project_path
+ :finished
+ else
+ :none
+ end
+ end
+
+ def export_in_progress?
+ import_export_shared.active_export_count > 0
+ end
+
def remove_exports
return nil unless export_path.present?
@@ -1663,8 +1685,9 @@ class Project < ActiveRecord::Base
end
end
- def multiple_issue_boards_available?(user)
- feature_available?(:multiple_issue_boards, user)
+ # Overridden on EE module
+ def multiple_issue_boards_available?
+ false
end
def issue_board_milestone_available?(user = nil)
@@ -1766,6 +1789,44 @@ class Project < ActiveRecord::Base
.set(import_jid, StuckImportJobsWorker::IMPORT_JOBS_EXPIRATION)
end
+ def badges
+ return project_badges unless group
+
+ group_badges_rel = GroupBadge.where(group: group.self_and_ancestors)
+
+ union = Gitlab::SQL::Union.new([project_badges.select(:id),
+ group_badges_rel.select(:id)])
+
+ Badge.where("id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
+ end
+
+ def merge_requests_allowing_push_to_user(user)
+ return MergeRequest.none unless user
+
+ developer_access_exists = user.project_authorizations
+ .where('access_level >= ? ', Gitlab::Access::DEVELOPER)
+ .where('project_authorizations.project_id = merge_requests.target_project_id')
+ .limit(1)
+ .select(1)
+ source_of_merge_requests.opened
+ .where(allow_maintainer_to_push: true)
+ .where('EXISTS (?)', developer_access_exists)
+ end
+
+ def branch_allows_maintainer_push?(user, branch_name)
+ return false unless user
+
+ cache_key = "user:#{user.id}:#{branch_name}:branch_allows_push"
+
+ memoized_results = strong_memoize(:branch_allows_maintainer_push) do
+ Hash.new do |result, cache_key|
+ result[cache_key] = fetch_branch_allows_maintainer_push?(user, branch_name)
+ end
+ end
+
+ memoized_results[cache_key]
+ end
+
private
def storage
@@ -1888,4 +1949,22 @@ class Project < ActiveRecord::Base
raise ex
end
+
+ def fetch_branch_allows_maintainer_push?(user, branch_name)
+ check_access = -> do
+ merge_request = source_of_merge_requests.opened
+ .where(allow_maintainer_to_push: true)
+ .find_by(source_branch: branch_name)
+
+ merge_request&.can_be_merged_by?(user)
+ end
+
+ if RequestStore.active?
+ RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_maintainer_push") do
+ check_access.call
+ end
+ else
+ check_access.call
+ end
+ end
end
diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb
index 109258d1eb7..4f289e6e215 100644
--- a/app/models/project_services/asana_service.rb
+++ b/app/models/project_services/asana_service.rb
@@ -68,7 +68,7 @@ http://app.asana.com/-/account_api'
end
user = data[:user_name]
- project_name = project.name_with_namespace
+ project_name = project.full_name
data[:commits].each do |commit|
push_msg = "#{user} pushed to branch #{branch} of #{project_name} ( #{commit[:url]} ):"
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
index c3f5b310619..8d7a4fceb08 100644
--- a/app/models/project_services/campfire_service.rb
+++ b/app/models/project_services/campfire_service.rb
@@ -86,7 +86,7 @@ class CampfireService < Service
after = push[:after]
message = ""
- message << "[#{project.name_with_namespace}] "
+ message << "[#{project.full_name}] "
message << "#{push[:user_name]} "
if Gitlab::Git.blank_ref?(before)
diff --git a/app/models/project_services/chat_notification_service.rb b/app/models/project_services/chat_notification_service.rb
index e2ffdf72201..dab0ea1a681 100644
--- a/app/models/project_services/chat_notification_service.rb
+++ b/app/models/project_services/chat_notification_service.rb
@@ -129,7 +129,7 @@ class ChatNotificationService < Service
end
def project_name
- project.name_with_namespace.gsub(/\s/, '')
+ project.full_name.gsub(/\s/, '')
end
def project_url
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index bfe7ac29c18..f31c3f02af2 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -120,7 +120,7 @@ class HipchatService < Service
else
message << "pushed to #{ref_type} <a href=\""\
"#{project.web_url}/commits/#{CGI.escape(ref)}\">#{ref}</a> "
- message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/, '')}</a> "
+ message << "of <a href=\"#{project.web_url}\">#{project.full_name.gsub!(/\s/, '')}</a> "
message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)"
push[:commits].take(MAX_COMMITS).each do |commit|
@@ -274,7 +274,7 @@ class HipchatService < Service
end
def project_name
- project.name_with_namespace.gsub(/\s/, '')
+ project.full_name.gsub(/\s/, '')
end
def project_url
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 436a870b0c4..e5035c81df0 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -1,5 +1,7 @@
class JiraService < IssueTrackerService
include Gitlab::Routing
+ include ApplicationHelper
+ include ActionView::Helpers::AssetUrlHelper
validates :url, url: true, presence: true, if: :activated?
validates :api_url, url: true, allow_blank: true
@@ -268,7 +270,9 @@ class JiraService < IssueTrackerService
url: url,
title: title,
status: status,
- icon: { title: 'GitLab', url16x16: 'https://gitlab.com/favicon.ico' }
+ icon: {
+ title: 'GitLab', url16x16: asset_url('favicon.ico', host: gitlab_config.url)
+ }
}
}
end
diff --git a/app/models/project_services/mattermost_slash_commands_service.rb b/app/models/project_services/mattermost_slash_commands_service.rb
index 4d2037286a2..227d430083d 100644
--- a/app/models/project_services/mattermost_slash_commands_service.rb
+++ b/app/models/project_services/mattermost_slash_commands_service.rb
@@ -37,7 +37,7 @@ class MattermostSlashCommandsService < SlashCommandsService
private
def command(params)
- pretty_project_name = project.name_with_namespace
+ pretty_project_name = project.full_name
params.merge(
auto_complete: true,
diff --git a/app/models/project_services/monitoring_service.rb b/app/models/project_services/monitoring_service.rb
index ee9cd78327a..9af68b4e821 100644
--- a/app/models/project_services/monitoring_service.rb
+++ b/app/models/project_services/monitoring_service.rb
@@ -9,11 +9,11 @@ class MonitoringService < Service
%w()
end
- def environment_metrics(environment)
+ def can_query?
raise NotImplementedError
end
- def deployment_metrics(deployment)
+ def query(_, *_)
raise NotImplementedError
end
end
diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb
index 58731451429..dcaeb65dc32 100644
--- a/app/models/project_services/prometheus_service.rb
+++ b/app/models/project_services/prometheus_service.rb
@@ -1,9 +1,5 @@
class PrometheusService < MonitoringService
- include ReactiveService
-
- self.reactive_cache_lease_timeout = 30.seconds
- self.reactive_cache_refresh_interval = 30.seconds
- self.reactive_cache_lifetime = 1.minute
+ include PrometheusAdapter
# Access to prometheus is directly through the API
prop_accessor :api_url
@@ -13,7 +9,7 @@ class PrometheusService < MonitoringService
validates :api_url, url: true
end
- before_save :synchronize_service_state!
+ before_save :synchronize_service_state
after_save :clear_reactive_cache!
@@ -66,63 +62,15 @@ class PrometheusService < MonitoringService
# Check we can connect to the Prometheus API
def test(*args)
- client.ping
+ Gitlab::PrometheusClient.new(prometheus_client).ping
{ success: true, result: 'Checked API endpoint' }
rescue Gitlab::PrometheusClient::Error => err
{ success: false, result: err }
end
- def environment_metrics(environment)
- with_reactive_cache(Gitlab::Prometheus::Queries::EnvironmentQuery.name, environment.id, &rename_field(:data, :metrics))
- end
-
- def deployment_metrics(deployment)
- metrics = with_reactive_cache(Gitlab::Prometheus::Queries::DeploymentQuery.name, deployment.environment.id, deployment.id, &rename_field(:data, :metrics))
- metrics&.merge(deployment_time: deployment.created_at.to_i) || {}
- end
-
- def additional_environment_metrics(environment)
- with_reactive_cache(Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery.name, environment.id, &:itself)
- end
-
- def additional_deployment_metrics(deployment)
- with_reactive_cache(Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery.name, deployment.environment.id, deployment.id, &:itself)
- end
-
- def matched_metrics
- with_reactive_cache(Gitlab::Prometheus::Queries::MatchedMetricsQuery.name, &:itself)
- end
-
- # Cache metrics for specific environment
- def calculate_reactive_cache(query_class_name, *args)
- return unless active? && project && !project.pending_delete?
-
- environment_id = args.first
- client = client(environment_id)
-
- data = Kernel.const_get(query_class_name).new(client).query(*args)
- {
- success: true,
- data: data,
- last_update: Time.now.utc
- }
- rescue Gitlab::PrometheusClient::Error => err
- { success: false, result: err.message }
- end
-
- def client(environment_id = nil)
- if manual_configuration?
- Gitlab::PrometheusClient.new(RestClient::Resource.new(api_url))
- else
- cluster = cluster_with_prometheus(environment_id)
- raise Gitlab::PrometheusClient::Error, "couldn't find cluster with Prometheus installed" unless cluster
-
- rest_client = client_from_cluster(cluster)
- raise Gitlab::PrometheusClient::Error, "couldn't create proxy Prometheus client" unless rest_client
-
- Gitlab::PrometheusClient.new(rest_client)
- end
+ def prometheus_client
+ RestClient::Resource.new(api_url) if api_url && manual_configuration? && active?
end
def prometheus_installed?
@@ -134,32 +82,7 @@ class PrometheusService < MonitoringService
private
- def cluster_with_prometheus(environment_id = nil)
- clusters = if environment_id
- ::Environment.find_by(id: environment_id).try do |env|
- # sort results by descending order based on environment_scope being longer
- # thus more closely matching environment slug
- project.clusters.enabled.for_environment(env).sort_by { |c| c.environment_scope&.length }.reverse!
- end
- else
- project.clusters.enabled.for_all_environments
- end
-
- clusters&.detect { |cluster| cluster.application_prometheus&.installed? }
- end
-
- def client_from_cluster(cluster)
- cluster.application_prometheus.proxy_client
- end
-
- def rename_field(old_field, new_field)
- -> (metrics) do
- metrics[new_field] = metrics.delete(old_field)
- metrics
- end
- end
-
- def synchronize_service_state!
+ def synchronize_service_state
self.active = prometheus_installed? || manual_configuration?
true
diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb
index aa7bd4c3c84..e3a1ca2d45f 100644
--- a/app/models/project_services/pushover_service.rb
+++ b/app/models/project_services/pushover_service.rb
@@ -88,10 +88,10 @@ class PushoverService < Service
user: user_key,
device: device,
priority: priority,
- title: "#{project.name_with_namespace}",
+ title: "#{project.full_name}",
message: message,
url: data[:project][:web_url],
- url_title: "See project #{project.name_with_namespace}"
+ url_title: "See project #{project.full_name}"
}
# Sound parameter MUST NOT be sent to API if not selected
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index a9e5cfb8240..33280eda0b9 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -85,6 +85,15 @@ class ProjectTeam
@masters ||= fetch_members(Gitlab::Access::MASTER)
end
+ def owners
+ @owners ||=
+ if group
+ group.owners
+ else
+ [project.owner]
+ end
+ end
+
def import(source_project, current_user = nil)
target_project = project
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 242d9d5f125..42f1ac43e29 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -16,6 +16,7 @@ class Repository
].freeze
include Gitlab::ShellAdapter
+ include Gitlab::RepositoryCacheAdapter
attr_accessor :full_path, :disk_path, :project, :is_wiki
@@ -35,7 +36,7 @@ class Repository
CACHED_METHODS = %i(size commit_count rendered_readme contribution_guide
changelog license_blob license_key gitignore koding_yml
gitlab_ci_yml branch_names tag_names branch_count
- tag_count avatar exists? empty? root_ref has_visible_content?
+ tag_count avatar exists? root_ref has_visible_content?
issue_template_names merge_request_template_names).freeze
# Methods that use cache_method but only memoize the value
@@ -57,22 +58,6 @@ class Repository
merge_request_template: :merge_request_template_names
}.freeze
- # Wraps around the given method and caches its output in Redis and an instance
- # variable.
- #
- # This only works for methods that do not take any arguments.
- def self.cache_method(name, fallback: nil, memoize_only: false)
- original = :"_uncached_#{name}"
-
- alias_method(original, name)
-
- define_method(name) do
- cache_method_output(name, fallback: fallback, memoize_only: memoize_only) do
- __send__(original) # rubocop:disable GitlabSecurity/PublicSend
- end
- end
- end
-
def initialize(full_path, project, disk_path: nil, is_wiki: false)
@full_path = full_path
@disk_path = disk_path || full_path
@@ -253,7 +238,7 @@ class Repository
# branches or tags, but we want to keep some of these commits around, for
# example if they have comments or CI builds.
def keep_around(sha)
- return unless sha && commit_by(oid: sha)
+ return unless sha.present? && commit_by(oid: sha)
return if kept_around?(sha)
@@ -302,17 +287,6 @@ class Repository
expire_method_caches(CACHED_METHODS)
end
- # Expires the caches of a specific set of methods
- def expire_method_caches(methods)
- methods.each do |key|
- cache.expire(key)
-
- ivar = cache_instance_variable_name(key)
-
- remove_instance_variable(ivar) if instance_variable_defined?(ivar)
- end
- end
-
def expire_avatar_cache
expire_method_caches(%i(avatar))
end
@@ -360,7 +334,7 @@ class Repository
def expire_emptiness_caches
return unless empty?
- expire_method_caches(%i(empty? has_visible_content?))
+ expire_method_caches(%i(has_visible_content?))
end
def lookup_cache
@@ -506,12 +480,14 @@ class Repository
end
cache_method :exists?
+ # We don't need to cache the output of this method because both exists? and
+ # has_visible_content? are already memoized and cached. There's no guarantee
+ # that the values are expired and loaded atomically.
def empty?
return true unless exists?
!has_visible_content?
end
- cache_method :empty?
# The size of this repository in megabytes.
def size
@@ -651,14 +627,15 @@ class Repository
end
def last_commit_for_path(sha, path)
- commit_by(oid: last_commit_id_for_path(sha, path))
+ commit = raw_repository.last_commit_for_path(sha, path)
+ ::Commit.new(commit, @project) if commit
end
def last_commit_id_for_path(sha, path)
key = path.blank? ? "last_commit_id_for_path:#{sha}" : "last_commit_id_for_path:#{sha}:#{Digest::SHA1.hexdigest(path)}"
cache.fetch(key) do
- raw_repository.last_commit_id_for_path(sha, path)
+ last_commit_for_path(sha, path)&.id
end
end
@@ -866,20 +843,20 @@ class Repository
raw_repository.ancestor?(ancestor_id, descendant_id)
end
- def fetch_as_mirror(url, forced: false, refmap: :all_refs, remote_name: nil)
+ def fetch_as_mirror(url, forced: false, refmap: :all_refs, remote_name: nil, prune: true)
unless remote_name
remote_name = "tmp-#{SecureRandom.hex}"
tmp_remote_name = true
end
add_remote(remote_name, url, mirror_refmap: refmap)
- fetch_remote(remote_name, forced: forced)
+ fetch_remote(remote_name, forced: forced, prune: prune)
ensure
remove_remote(remote_name) if tmp_remote_name
end
- def fetch_remote(remote, forced: false, ssh_auth: nil, no_tags: false)
- gitlab_shell.fetch_remote(raw_repository, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags)
+ def fetch_remote(remote, forced: false, ssh_auth: nil, no_tags: false, prune: true)
+ gitlab_shell.fetch_remote(raw_repository, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, prune: prune)
end
def fetch_source_branch!(source_repository, source_branch, local_ref)
@@ -921,49 +898,6 @@ class Repository
end
end
- # Caches the supplied block both in a cache and in an instance variable.
- #
- # The cache key and instance variable are named the same way as the value of
- # the `key` argument.
- #
- # This method will return `nil` if the corresponding instance variable is also
- # set to `nil`. This ensures we don't keep yielding the block when it returns
- # `nil`.
- #
- # key - The name of the key to cache the data in.
- # fallback - A value to fall back to in the event of a Git error.
- def cache_method_output(key, fallback: nil, memoize_only: false, &block)
- ivar = cache_instance_variable_name(key)
-
- if instance_variable_defined?(ivar)
- instance_variable_get(ivar)
- else
- # If the repository doesn't exist and a fallback was specified we return
- # that value inmediately. This saves us Rugged/gRPC invocations.
- return fallback unless fallback.nil? || exists?
-
- begin
- value =
- if memoize_only
- yield
- else
- cache.fetch(key, &block)
- end
-
- instance_variable_set(ivar, value)
- rescue Gitlab::Git::Repository::NoRepository
- # Even if the above `#exists?` check passes these errors might still
- # occur (for example because of a non-existing HEAD). We want to
- # gracefully handle this and not cache anything
- fallback
- end
- end
- end
-
- def cache_instance_variable_name(key)
- :"@#{key.to_s.tr('?!', '')}"
- end
-
def file_on_head(type)
if head = tree(:head)
head.blobs.find do |blob|
@@ -1018,8 +952,7 @@ class Repository
end
def cache
- # TODO: should we use UUIDs here? We could move repositories without clearing this cache
- @cache ||= RepositoryCache.new(full_path, @project.id)
+ @cache ||= Gitlab::RepositoryCache.new(self)
end
def tags_sorted_by_committed_date
diff --git a/app/models/service.rb b/app/models/service.rb
index 369cae2e85f..99bf757ae44 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -129,6 +129,17 @@ class Service < ActiveRecord::Base
fields
end
+ def configurable_events
+ events = self.class.supported_events
+
+ # No need to disable individual triggers when there is only one
+ if events.count == 1
+ []
+ else
+ events
+ end
+ end
+
def supported_events
self.class.supported_events
end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index a58c208279e..644120453cf 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -168,5 +168,9 @@ class Snippet < ActiveRecord::Base
def search_code(query)
fuzzy_search(query, [:content])
end
+
+ def parent_class
+ ::Project
+ end
end
end
diff --git a/app/models/todo.rb b/app/models/todo.rb
index bb5965e20eb..8afacd188e0 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -32,8 +32,6 @@ class Todo < ActiveRecord::Base
validates :target_id, presence: true, unless: :for_commit?
validates :commit_id, presence: true, if: :for_commit?
- default_scope { reorder(id: :desc) }
-
scope :pending, -> { with_state(:pending) }
scope :done, -> { with_state(:done) }
@@ -53,10 +51,14 @@ class Todo < ActiveRecord::Base
# milestones, but still show something if the user has a URL with that
# selected.
def sort(method)
- case method.to_s
- when 'priority', 'label_priority' then order_by_labels_priority
- else order_by(method)
- end
+ sorted =
+ case method.to_s
+ when 'priority', 'label_priority' then order_by_labels_priority
+ else order_by(method)
+ end
+
+ # Break ties with the ID column for pagination
+ sorted.order(id: :desc)
end
# Order by priority depending on which issue/merge request the Todo belongs to
diff --git a/app/models/user.rb b/app/models/user.rb
index 9c60adf0c90..b8c55205ab8 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -114,13 +114,15 @@ class User < ActiveRecord::Base
has_many :project_authorizations
has_many :authorized_projects, through: :project_authorizations, source: :project
+ has_many :user_interacted_projects
+ has_many :project_interactions, through: :user_interacted_projects, source: :project, class_name: 'Project'
+
has_many :snippets, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :notes, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :issues, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :merge_requests, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :events, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :subscriptions, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
- has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event"
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :abuse_report, dependent: :destroy, foreign_key: :user_id # rubocop:disable Cop/ActiveRecordDependent
has_many :reported_abuse_reports, dependent: :destroy, foreign_key: :reporter_id, class_name: "AbuseReport" # rubocop:disable Cop/ActiveRecordDependent
@@ -1035,14 +1037,33 @@ class User < ActiveRecord::Base
end
end
+ def todos_done_count(force: false)
+ Rails.cache.fetch(['users', id, 'todos_done_count'], force: force, expires_in: 20.minutes) do
+ TodosFinder.new(self, state: :done).execute.count
+ end
+ end
+
+ def todos_pending_count(force: false)
+ Rails.cache.fetch(['users', id, 'todos_pending_count'], force: force, expires_in: 20.minutes) do
+ TodosFinder.new(self, state: :pending).execute.count
+ end
+ end
+
def update_cache_counts
assigned_open_merge_requests_count(force: true)
assigned_open_issues_count(force: true)
end
+ def update_todos_count_cache
+ todos_done_count(force: true)
+ todos_pending_count(force: true)
+ end
+
def invalidate_cache_counts
invalidate_issue_cache_counts
invalidate_merge_request_cache_counts
+ invalidate_todos_done_count
+ invalidate_todos_pending_count
end
def invalidate_issue_cache_counts
@@ -1053,21 +1074,12 @@ class User < ActiveRecord::Base
Rails.cache.delete(['users', id, 'assigned_open_merge_requests_count'])
end
- def todos_done_count(force: false)
- Rails.cache.fetch(['users', id, 'todos_done_count'], force: force, expires_in: 20.minutes) do
- TodosFinder.new(self, state: :done).execute.count
- end
+ def invalidate_todos_done_count
+ Rails.cache.delete(['users', id, 'todos_done_count'])
end
- def todos_pending_count(force: false)
- Rails.cache.fetch(['users', id, 'todos_pending_count'], force: force, expires_in: 20.minutes) do
- TodosFinder.new(self, state: :pending).execute.count
- end
- end
-
- def update_todos_count_cache
- todos_done_count(force: true)
- todos_pending_count(force: true)
+ def invalidate_todos_pending_count
+ Rails.cache.delete(['users', id, 'todos_pending_count'])
end
# This is copied from Devise::Models::Lockable#valid_for_authentication?, as our auth
diff --git a/app/models/user_interacted_project.rb b/app/models/user_interacted_project.rb
new file mode 100644
index 00000000000..dd55a6acb79
--- /dev/null
+++ b/app/models/user_interacted_project.rb
@@ -0,0 +1,59 @@
+class UserInteractedProject < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :project
+
+ validates :project_id, presence: true
+ validates :user_id, presence: true
+
+ CACHE_EXPIRY_TIME = 1.day
+
+ # Schema version required for this model
+ REQUIRED_SCHEMA_VERSION = 20180223120443
+
+ class << self
+ def track(event)
+ # For events without a project, we simply don't care.
+ # An example of this is the creation of a snippet (which
+ # is not related to any project).
+ return unless event.project_id
+
+ attributes = {
+ project_id: event.project_id,
+ user_id: event.author_id
+ }
+
+ cached_exists?(attributes) do
+ transaction(requires_new: true) do
+ begin
+ where(attributes).select(1).first || create!(attributes)
+ true # not caching the whole record here for now
+ rescue ActiveRecord::RecordNotUnique
+ # Note, above queries are not atomic and prone
+ # to race conditions (similar like #find_or_create!).
+ # In the case where we hit this, the record we want
+ # already exists - shortcut and return.
+ true
+ end
+ end
+ end
+ end
+
+ # Check if we can safely call .track (table exists)
+ def available?
+ @available_flag ||= ActiveRecord::Migrator.current_version >= REQUIRED_SCHEMA_VERSION # rubocop:disable Gitlab/PredicateMemoization
+ end
+
+ # Flushes cached information about schema
+ def reset_column_information
+ @available_flag = nil
+ super
+ end
+
+ private
+
+ def cached_exists?(project_id:, user_id:, &block)
+ cache_key = "user_interacted_projects:#{project_id}:#{user_id}"
+ Rails.cache.fetch(cache_key, expires_in: CACHE_EXPIRY_TIME, &block)
+ end
+ end
+end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index f0bcba588a2..c9cb730c4e9 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -48,7 +48,12 @@ class GroupPolicy < BasePolicy
rule { has_access }.enable :read_namespace
rule { developer }.enable :admin_milestones
- rule { reporter }.enable :admin_label
+
+ rule { reporter }.policy do
+ enable :admin_label
+ enable :admin_list
+ enable :admin_issue
+ end
rule { master }.policy do
enable :create_projects
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 3b0550b4dd6..57ab0c23dcd 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -61,6 +61,11 @@ class ProjectPolicy < BasePolicy
desc "Project has request access enabled"
condition(:request_access_enabled, scope: :subject) { project.request_access_enabled }
+ desc "Has merge requests allowing pushes to user"
+ condition(:has_merge_requests_allowing_pushes, scope: :subject) do
+ project.merge_requests_allowing_push_to_user(user).any?
+ end
+
features = %w[
merge_requests
issues
@@ -291,6 +296,15 @@ class ProjectPolicy < BasePolicy
prevent :read_issue
end
+ # These rules are included to allow maintainers of projects to push to certain
+ # to run pipelines for the branches they have access to.
+ rule { can?(:public_access) & has_merge_requests_allowing_pushes }.policy do
+ enable :create_build
+ enable :update_build
+ enable :create_pipeline
+ enable :update_pipeline
+ end
+
private
def team_member?
diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb
index 08ae49562c7..9f3f2637183 100644
--- a/app/presenters/merge_request_presenter.rb
+++ b/app/presenters/merge_request_presenter.rb
@@ -78,7 +78,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
def rebase_path
- if !rebase_in_progress? && should_be_rebased? && user_can_push_to_source_branch?
+ if !rebase_in_progress? && should_be_rebased? && can_push_to_source_branch?
rebase_project_merge_request_path(project, merge_request)
end
end
@@ -160,7 +160,11 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
def can_push_to_source_branch?
- source_branch_exists? && user_can_push_to_source_branch?
+ return false unless source_branch_exists?
+
+ !!::Gitlab::UserAccess
+ .new(current_user, project: source_project)
+ .can_push_to_branch?(source_branch)
end
private
@@ -191,17 +195,10 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end.sort.to_sentence
end
- def user_can_push_to_source_branch?
- return false unless source_branch_exists?
-
- ::Gitlab::UserAccess
- .new(current_user, project: source_project)
- .can_push_to_branch?(source_branch)
- end
-
def user_can_collaborate_with_project?
can?(current_user, :push_code, project) ||
- (current_user && current_user.already_forked?(project))
+ (current_user && current_user.already_forked?(project)) ||
+ can_push_to_source_branch?
end
def user_can_fork_project?
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 4e8ef320af2..4a812e39ee1 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -11,6 +11,7 @@ class MergeRequestWidgetEntity < IssuableEntity
expose :source_project_id
expose :target_branch
expose :target_project_id
+ expose :allow_maintainer_to_push
expose :should_be_rebased?, as: :should_be_rebased
expose :ff_only_enabled do |merge_request|
@@ -29,6 +30,7 @@ class MergeRequestWidgetEntity < IssuableEntity
expose :can_push_to_source_branch do |merge_request|
presenter(merge_request).can_push_to_source_branch?
end
+
expose :rebase_path do |merge_request|
presenter(merge_request).rebase_path
end
@@ -38,7 +40,7 @@ class MergeRequestWidgetEntity < IssuableEntity
# Diff sha's
expose :diff_head_sha do |merge_request|
- merge_request.diff_head_sha if merge_request.diff_head_commit
+ merge_request.diff_head_sha.presence
end
expose :merge_commit_message
@@ -136,8 +138,8 @@ class MergeRequestWidgetEntity < IssuableEntity
end
expose :new_blob_path do |merge_request|
- if can?(current_user, :push_code, merge_request.project)
- project_new_blob_path(merge_request.project, merge_request.source_branch)
+ if presenter(merge_request).can_push_to_source_branch?
+ project_new_blob_path(merge_request.source_project, merge_request.source_branch)
end
end
diff --git a/app/services/badges/base_service.rb b/app/services/badges/base_service.rb
new file mode 100644
index 00000000000..4f87426bd38
--- /dev/null
+++ b/app/services/badges/base_service.rb
@@ -0,0 +1,11 @@
+module Badges
+ class BaseService
+ protected
+
+ attr_accessor :params
+
+ def initialize(params = {})
+ @params = params.dup
+ end
+ end
+end
diff --git a/app/services/badges/build_service.rb b/app/services/badges/build_service.rb
new file mode 100644
index 00000000000..6267e571838
--- /dev/null
+++ b/app/services/badges/build_service.rb
@@ -0,0 +1,12 @@
+module Badges
+ class BuildService < Badges::BaseService
+ # returns the created badge
+ def execute(source)
+ if source.is_a?(Group)
+ GroupBadge.new(params.merge(group: source))
+ else
+ ProjectBadge.new(params.merge(project: source))
+ end
+ end
+ end
+end
diff --git a/app/services/badges/create_service.rb b/app/services/badges/create_service.rb
new file mode 100644
index 00000000000..aafb87f7dcd
--- /dev/null
+++ b/app/services/badges/create_service.rb
@@ -0,0 +1,10 @@
+module Badges
+ class CreateService < Badges::BaseService
+ # returns the created badge
+ def execute(source)
+ badge = Badges::BuildService.new(params).execute(source)
+
+ badge.tap { |b| b.save }
+ end
+ end
+end
diff --git a/app/services/badges/update_service.rb b/app/services/badges/update_service.rb
new file mode 100644
index 00000000000..7ca84b5df31
--- /dev/null
+++ b/app/services/badges/update_service.rb
@@ -0,0 +1,12 @@
+module Badges
+ class UpdateService < Badges::BaseService
+ # returns the updated badge
+ def execute(badge)
+ if params.present?
+ badge.update_attributes(params)
+ end
+
+ badge
+ end
+ end
+end
diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb
index 6078fe38064..ecd74b74f8a 100644
--- a/app/services/boards/issues/list_service.rb
+++ b/app/services/boards/issues/list_service.rb
@@ -40,7 +40,11 @@ module Boards
end
def set_parent
- params[:project_id] = parent.id
+ if parent.is_a?(Group)
+ params[:group_id] = parent.id
+ else
+ params[:project_id] = parent.id
+ end
end
def set_state
diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb
index 797d6df7c1a..15fed7d17c1 100644
--- a/app/services/boards/issues/move_service.rb
+++ b/app/services/boards/issues/move_service.rb
@@ -60,8 +60,10 @@ module Boards
label_ids =
if moving_to_list.movable?
moving_from_list.label_id
+ elsif board.group_board?
+ ::Label.on_group_boards(parent.id).pluck(:label_id)
else
- Label.on_project_boards(parent.id).pluck(:label_id)
+ ::Label.on_project_boards(parent.id).pluck(:label_id)
end
Array(label_ids).compact
diff --git a/app/services/boards/lists/create_service.rb b/app/services/boards/lists/create_service.rb
index 183556a1d6b..bebc90c7a8d 100644
--- a/app/services/boards/lists/create_service.rb
+++ b/app/services/boards/lists/create_service.rb
@@ -12,7 +12,11 @@ module Boards
private
def available_labels_for(board)
- LabelsFinder.new(current_user, project_id: parent.id).execute
+ if board.group_board?
+ parent.labels
+ else
+ LabelsFinder.new(current_user, project_id: parent.id).execute
+ end
end
def next_position(board)
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index c8b112132b3..3b3d9239086 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -81,7 +81,7 @@ module Ci
end
def related_merge_requests
- MergeRequest.opened.where(source_project: pipeline.project, source_branch: pipeline.ref)
+ pipeline.project.source_of_merge_requests.opened.where(source_branch: pipeline.ref)
end
end
end
diff --git a/app/services/ci/create_trace_artifact_service.rb b/app/services/ci/create_trace_artifact_service.rb
deleted file mode 100644
index ffde824972c..00000000000
--- a/app/services/ci/create_trace_artifact_service.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-module Ci
- class CreateTraceArtifactService < BaseService
- def execute(job)
- return if job.job_artifacts_trace
-
- job.trace.read do |stream|
- break unless stream.file?
-
- clone_file!(stream.path, JobArtifactUploader.workhorse_upload_path) do |clone_path|
- create_job_trace!(job, clone_path)
- FileUtils.rm(stream.path)
- end
- end
- end
-
- private
-
- def create_job_trace!(job, path)
- File.open(path) do |stream|
- job.create_job_artifacts_trace!(
- project: job.project,
- file_type: :trace,
- file: stream)
- end
- end
-
- def clone_file!(src_path, temp_dir)
- FileUtils.mkdir_p(temp_dir)
- Dir.mktmpdir('tmp-trace', temp_dir) do |dir_path|
- temp_path = File.join(dir_path, "job.log")
- FileUtils.copy(src_path, temp_path)
- yield(temp_path)
- end
- end
- end
-end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index e87fd49d193..02fb48108fb 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -109,6 +109,10 @@ class IssuableBaseService < BaseService
@available_labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute
end
+ def handle_quick_actions_on_create(issuable)
+ merge_quick_actions_into_params!(issuable)
+ end
+
def merge_quick_actions_into_params!(issuable)
original_description = params.fetch(:description, issuable.description)
@@ -131,7 +135,7 @@ class IssuableBaseService < BaseService
end
def create(issuable)
- merge_quick_actions_into_params!(issuable)
+ handle_quick_actions_on_create(issuable)
filter_params(issuable)
params.delete(:state_event)
diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb
index b141bfd5fbc..5b51e1982f1 100644
--- a/app/services/members/destroy_service.rb
+++ b/app/services/members/destroy_service.rb
@@ -5,12 +5,9 @@ module Members
return member if member.is_a?(GroupMember) && member.source.last_owner?(member.user)
- Member.transaction do
- unassign_issues_and_merge_requests(member) unless member.invite?
- member.notification_setting&.destroy
+ member.destroy
- member.destroy
- end
+ member.user&.invalidate_cache_counts
if member.request? && member.user != current_user
notification_service.decline_access_request(member)
@@ -37,38 +34,5 @@ module Members
raise "Unknown member type: #{member}!"
end
end
-
- def unassign_issues_and_merge_requests(member)
- if member.is_a?(GroupMember)
- issues = Issue.unscoped.select(1)
- .joins(:project)
- .where('issues.id = issue_assignees.issue_id AND projects.namespace_id = ?', member.source_id)
-
- # DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
- IssueAssignee.unscoped
- .where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
- .delete_all
-
- MergeRequestsFinder.new(current_user, group_id: member.source_id, assignee_id: member.user_id)
- .execute
- .update_all(assignee_id: nil)
- else
- project = member.source
-
- # SELECT 1 FROM issues WHERE issues.id = issue_assignees.issue_id AND issues.project_id = X
- issues = Issue.unscoped.select(1)
- .where('issues.id = issue_assignees.issue_id')
- .where(project_id: project.id)
-
- # DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
- IssueAssignee.unscoped
- .where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
- .delete_all
-
- project.merge_requests.opened.assigned_to(member.user).update_all(assignee_id: nil)
- end
-
- member.user.invalidate_cache_counts
- end
end
end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 20a2b50d3de..231ab76fde4 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -24,6 +24,25 @@ module MergeRequests
private
+ def handle_wip_event(merge_request)
+ if wip_event = params.delete(:wip_event)
+ # We update the title that is provided in the params or we use the mr title
+ title = params[:title] || merge_request.title
+ params[:title] = case wip_event
+ when 'wip' then MergeRequest.wip_title(title)
+ when 'unwip' then MergeRequest.wipless_title(title)
+ end
+ end
+ end
+
+ def filter_params(merge_request)
+ super
+
+ unless merge_request.can_allow_maintainer_to_push?(current_user)
+ params.delete(:allow_maintainer_to_push)
+ end
+ end
+
def merge_request_metrics_service(merge_request)
MergeRequestMetricsService.new(merge_request.metrics)
end
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index 4b186d93772..a98bbdf74dd 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -6,6 +6,7 @@ module MergeRequests
@params_issue_iid = params.delete(:issue_iid)
self.merge_request = MergeRequest.new(params)
+ merge_request.author = current_user
merge_request.compare_commits = []
merge_request.source_project = find_source_project
merge_request.target_project = find_target_project
diff --git a/app/services/merge_requests/conflicts/list_service.rb b/app/services/merge_requests/conflicts/list_service.rb
index ca9a33678e4..72cbc49adb2 100644
--- a/app/services/merge_requests/conflicts/list_service.rb
+++ b/app/services/merge_requests/conflicts/list_service.rb
@@ -17,15 +17,7 @@ module MergeRequests
return @conflicts_can_be_resolved_in_ui = false unless merge_request.has_complete_diff_refs?
return @conflicts_can_be_resolved_in_ui = false if merge_request.branch_missing?
- begin
- # Try to parse each conflict. If the MR's mergeable status hasn't been
- # updated, ensure that we don't say there are conflicts to resolve
- # when there are no conflict files.
- conflicts.files.each(&:lines)
- @conflicts_can_be_resolved_in_ui = conflicts.files.length > 0
- rescue Gitlab::Git::CommandError, Gitlab::Git::Conflict::Parser::UnresolvableError, Gitlab::Git::Conflict::Resolver::ConflictSideMissing
- @conflicts_can_be_resolved_in_ui = false
- end
+ @conflicts_can_be_resolved_in_ui = conflicts.can_be_resolved_in_ui?
end
def conflicts
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index a18b1c90765..c57a2445341 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -34,6 +34,12 @@ module MergeRequests
super
end
+ # Override from IssuableBaseService
+ def handle_quick_actions_on_create(merge_request)
+ super
+ handle_wip_event(merge_request)
+ end
+
private
def update_merge_requests_head_pipeline(merge_request)
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index c153872c874..8a40ad88182 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -98,17 +98,6 @@ module MergeRequests
private
- def handle_wip_event(merge_request)
- if wip_event = params.delete(:wip_event)
- # We update the title that is provided in the params or we use the mr title
- title = params[:title] || merge_request.title
- params[:title] = case wip_event
- when 'wip' then MergeRequest.wip_title(title)
- when 'unwip' then MergeRequest.wipless_title(title)
- end
- end
- end
-
def create_branch_change_note(issuable, branch_type, old_branch, new_branch)
SystemNoteService.change_branch(
issuable, issuable.project, current_user, branch_type,
diff --git a/app/services/notes/build_service.rb b/app/services/notes/build_service.rb
index abf25bb778b..77e7b8a5ea7 100644
--- a/app/services/notes/build_service.rb
+++ b/app/services/notes/build_service.rb
@@ -26,14 +26,19 @@ module Notes
if project
project.notes.find_discussion(discussion_id)
else
- # only PersonalSnippets can have discussions without project association
discussion = Note.find_discussion(discussion_id)
noteable = discussion.noteable
- return nil unless noteable.is_a?(PersonalSnippet) && can?(current_user, :comment_personal_snippet, noteable)
+ return nil unless noteable_without_project?(noteable)
discussion
end
end
+
+ def noteable_without_project?(noteable)
+ return true if noteable.is_a?(PersonalSnippet) && can?(current_user, :comment_personal_snippet, noteable)
+
+ false
+ end
end
end
diff --git a/app/services/notes/post_process_service.rb b/app/services/notes/post_process_service.rb
index 6a10e172483..ad3dcc5010b 100644
--- a/app/services/notes/post_process_service.rb
+++ b/app/services/notes/post_process_service.rb
@@ -11,7 +11,7 @@ module Notes
unless @note.system?
EventCreateService.new.leave_note(@note, @note.author)
- return if @note.for_personal_snippet?
+ return unless @note.for_project_noteable?
@note.create_cross_references!
execute_note_hooks
diff --git a/app/services/notification_recipient_service.rb b/app/services/notification_recipient_service.rb
index 6835b14648b..e4be953e810 100644
--- a/app/services/notification_recipient_service.rb
+++ b/app/services/notification_recipient_service.rb
@@ -280,7 +280,7 @@ module NotificationRecipientService
add_participants(note.author)
add_mentions(note.author, target: note)
- unless note.for_personal_snippet?
+ if note.for_project_noteable?
# Merge project watchers
add_project_watchers
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 01838ec6b5d..7fa1387084c 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -85,7 +85,7 @@ module Projects
end
def after_create_actions
- log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
+ log_info("#{@project.owner.name} created a new project \"#{@project.full_name}\"")
unless @project.gitlab_project_import?
@project.write_repository_config
diff --git a/app/services/projects/import_export/export_service.rb b/app/services/projects/import_export/export_service.rb
index fe4e8ea10bf..af41ce82f65 100644
--- a/app/services/projects/import_export/export_service.rb
+++ b/app/services/projects/import_export/export_service.rb
@@ -2,7 +2,7 @@ module Projects
module ImportExport
class ExportService < BaseService
def execute(_options = {})
- @shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.disk_path, 'work'))
+ @shared = project.import_export_shared
save_all
end
diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb
index c760bd3b626..00fdd047208 100644
--- a/app/services/projects/update_pages_service.rb
+++ b/app/services/projects/update_pages_service.rb
@@ -1,5 +1,8 @@
module Projects
class UpdatePagesService < BaseService
+ InvaildStateError = Class.new(StandardError)
+ FailedToExtractError = Class.new(StandardError)
+
BLOCK_SIZE = 32.kilobytes
MAX_SIZE = 1.terabyte
SITE_PATH = 'public/'.freeze
@@ -11,13 +14,15 @@ module Projects
end
def execute
+ register_attempt
+
# Create status notifying the deployment of pages
@status = create_status
@status.enqueue!
@status.run!
- raise 'missing pages artifacts' unless build.artifacts?
- raise 'pages are outdated' unless latest?
+ raise InvaildStateError, 'missing pages artifacts' unless build.artifacts?
+ raise InvaildStateError, 'pages are outdated' unless latest?
# Create temporary directory in which we will extract the artifacts
FileUtils.mkdir_p(tmp_path)
@@ -26,24 +31,22 @@ module Projects
# Check if we did extract public directory
archive_public_path = File.join(archive_path, 'public')
- raise 'pages miss the public folder' unless Dir.exist?(archive_public_path)
- raise 'pages are outdated' unless latest?
+ raise FailedToExtractError, 'pages miss the public folder' unless Dir.exist?(archive_public_path)
+ raise InvaildStateError, 'pages are outdated' unless latest?
deploy_page!(archive_public_path)
success
end
- rescue => e
+ rescue InvaildStateError, FailedToExtractError => e
register_failure
error(e.message)
- ensure
- register_attempt
- build.erase_artifacts! unless build.has_expiring_artifacts?
end
private
def success
@status.success
+ delete_artifact!
super
end
@@ -52,6 +55,7 @@ module Projects
@status.allow_failure = !latest?
@status.description = message
@status.drop(:script_failure)
+ delete_artifact!
super
end
@@ -72,7 +76,7 @@ module Projects
elsif artifacts.ends_with?('.zip')
extract_zip_archive!(temp_path)
else
- raise 'unsupported artifacts format'
+ raise FailedToExtractError, 'unsupported artifacts format'
end
end
@@ -81,17 +85,17 @@ module Projects
%W(dd bs=#{BLOCK_SIZE} count=#{blocks}),
%W(tar -x -C #{temp_path} #{SITE_PATH}),
err: '/dev/null')
- raise 'pages failed to extract' unless results.compact.all?(&:success?)
+ raise FailedToExtractError, 'pages failed to extract' unless results.compact.all?(&:success?)
end
def extract_zip_archive!(temp_path)
- raise 'missing artifacts metadata' unless build.artifacts_metadata?
+ raise FailedToExtractError, 'missing artifacts metadata' unless build.artifacts_metadata?
# Calculate page size after extract
public_entry = build.artifacts_metadata_entry(SITE_PATH, recursive: true)
if public_entry.total_size > max_size
- raise "artifacts for pages are too large: #{public_entry.total_size}"
+ raise FailedToExtractError, "artifacts for pages are too large: #{public_entry.total_size}"
end
# Requires UnZip at least 6.00 Info-ZIP.
@@ -100,7 +104,7 @@ module Projects
# We add * to end of SITE_PATH, because we want to extract SITE_PATH and all subdirectories
site_path = File.join(SITE_PATH, '*')
unless system(*%W(unzip -qq -n #{artifacts} #{site_path} -d #{temp_path}))
- raise 'pages failed to extract'
+ raise FailedToExtractError, 'pages failed to extract'
end
end
@@ -163,6 +167,11 @@ module Projects
build.artifacts_file.path
end
+ def delete_artifact!
+ build.reload # Reload stable object to prevent erase artifacts with old state
+ build.erase_artifacts! unless build.has_expiring_artifacts?
+ end
+
def latest_sha
project.commit(build.ref).try(:sha).to_s
end
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 379a8068023..5f2615a2c01 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -58,7 +58,7 @@ module Projects
def enabling_wiki?
return false if @project.wiki_enabled?
- params[:project_feature_attributes][:wiki_access_level].to_i > ProjectFeature::DISABLED
+ params.dig(:project_feature_attributes, :wiki_access_level).to_i > ProjectFeature::DISABLED
end
def ensure_wiki_exists
diff --git a/app/services/prometheus/adapter_service.rb b/app/services/prometheus/adapter_service.rb
new file mode 100644
index 00000000000..4504d2ccfe6
--- /dev/null
+++ b/app/services/prometheus/adapter_service.rb
@@ -0,0 +1,36 @@
+module Prometheus
+ class AdapterService
+ def initialize(project, deployment_platform = nil)
+ @project = project
+
+ @deployment_platform = if deployment_platform
+ deployment_platform
+ else
+ project.deployment_platform
+ end
+ end
+
+ attr_reader :deployment_platform, :project
+
+ def prometheus_adapter
+ @prometheus_adapter ||= if service_prometheus_adapter.can_query?
+ service_prometheus_adapter
+ else
+ cluster_prometheus_adapter
+ end
+ end
+
+ def service_prometheus_adapter
+ project.find_or_initialize_service('prometheus')
+ end
+
+ def cluster_prometheus_adapter
+ return unless deployment_platform.respond_to?(:cluster)
+
+ cluster = deployment_platform.cluster
+ return unless cluster.application_prometheus&.installed?
+
+ cluster.application_prometheus
+ end
+ end
+end
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 1e9bd84e749..cba49faac31 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -347,9 +347,9 @@ module QuickActions
"#{verb} this #{noun} as Work In Progress."
end
condition do
- issuable.persisted? &&
- issuable.respond_to?(:work_in_progress?) &&
- current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
+ issuable.respond_to?(:work_in_progress?) &&
+ # Allow it to mark as WIP on MR creation page _or_ through MR notes.
+ (issuable.new_record? || current_user.can?(:"update_#{issuable.to_ability_name}", issuable))
end
command :wip do
@updates[:wip_event] = issuable.work_in_progress? ? 'unwip' : 'wip'
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index af8c02a10b7..ba7946fd23c 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -20,8 +20,8 @@ class SystemHooksService
def build_event_data(model, event)
data = {
event_name: build_event_name(model, event),
- created_at: model.created_at.xmlschema,
- updated_at: model.updated_at.xmlschema
+ created_at: model.created_at&.xmlschema,
+ updated_at: model.updated_at&.xmlschema
}
case model
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index c2ca404b179..ffd48e842c2 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -241,8 +241,7 @@ class TodoService
end
def handle_note(note, author, skip_users = [])
- # Skip system notes, and notes on project snippet
- return if note.system? || note.for_snippet?
+ return unless note.can_create_todo?
project = note.project
target = note.noteable
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index b71002433d6..06b604dad4d 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -49,6 +49,8 @@ module Users
::Projects::DestroyService.new(project, current_user, skip_repo: project.legacy_storage?).execute
end
+ yield(user) if block_given?
+
MigrateToGhostUserService.new(user).execute unless options[:hard_delete]
# Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
diff --git a/app/validators/url_placeholder_validator.rb b/app/validators/url_placeholder_validator.rb
new file mode 100644
index 00000000000..dd681218b6b
--- /dev/null
+++ b/app/validators/url_placeholder_validator.rb
@@ -0,0 +1,32 @@
+# UrlValidator
+#
+# Custom validator for URLs.
+#
+# By default, only URLs for the HTTP(S) protocols will be considered valid.
+# Provide a `:protocols` option to configure accepted protocols.
+#
+# Also, this validator can help you validate urls with placeholders inside.
+# Usually, if you have a url like 'http://www.example.com/%{project_path}' the
+# URI parser will reject that URL format. Provide a `:placeholder_regex` option
+# to configure accepted placeholders.
+#
+# Example:
+#
+# class User < ActiveRecord::Base
+# validates :personal_url, url: true
+#
+# validates :ftp_url, url: { protocols: %w(ftp) }
+#
+# validates :git_url, url: { protocols: %w(http https ssh git) }
+#
+# validates :placeholder_url, url: { placeholder_regex: /(project_path|project_id|default_branch)/ }
+# end
+#
+class UrlPlaceholderValidator < UrlValidator
+ def validate_each(record, attribute, value)
+ placeholder_regex = self.options[:placeholder_regex]
+ value = value.gsub(/%{#{placeholder_regex}}/, 'foo') if placeholder_regex && value
+
+ super(record, attribute, value)
+ end
+end
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 68788134b8e..81d7db04a3c 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -657,9 +657,11 @@
.checkbox
= f.label :version_check_enabled do
= f.check_box :version_check_enabled
- Version check enabled
+ Enable version check
.help-block
- Let GitLab inform you when an update is available.
+ GitLab will inform you if a new version is available.
+ = link_to 'Learn more', help_page_path("user/admin_area/settings/usage_statistics", anchor: "version-check")
+ about what information is shared with GitLab Inc.
.form-group
.col-sm-offset-2.col-sm-10
- can_be_configured = @application_setting.usage_ping_can_be_configured?
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index e3711421b61..05c41082882 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -164,7 +164,7 @@
%h4 Latest projects
- @projects.each do |project|
%p
- = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated-60'
+ = link_to project.full_name, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated-60'
%span.light.pull-right
#{time_ago_with_tooltip(project.created_at)}
.col-md-4
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 2545cecc721..324f3c0a22f 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -68,7 +68,7 @@
- @projects.each do |project|
%li
%strong
- = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project]
+ = link_to project.full_name, [:admin, project.namespace.becomes(Namespace), project]
%span.badge
= storage_counter(project.statistics.storage_size)
%span.pull-right.light
@@ -86,7 +86,7 @@
- @group.shared_projects.sort_by(&:name).each do |project|
%li
%strong
- = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project]
+ = link_to project.full_name, [:admin, project.namespace.becomes(Namespace), project]
%span.badge
= storage_counter(project.statistics.storage_size)
%span.pull-right.light
diff --git a/app/views/admin/hooks/_form.html.haml b/app/views/admin/hooks/_form.html.haml
index d8f96ed5b0d..a6324a97fd5 100644
--- a/app/views/admin/hooks/_form.html.haml
+++ b/app/views/admin/hooks/_form.html.haml
@@ -1,21 +1,20 @@
= form_errors(hook)
.form-group
- = form.label :url, 'URL', class: 'control-label'
- .col-sm-10
- = form.text_field :url, class: 'form-control'
+ = form.label :url, 'URL', class: 'label-light'
+ = form.text_field :url, class: 'form-control'
.form-group
- = form.label :token, 'Secret Token', class: 'control-label'
- .col-sm-10
- = form.text_field :token, class: 'form-control'
- %p.help-block
- Use this token to validate received payloads
+ = form.label :token, 'Secret Token', class: 'label-light'
+ = form.text_field :token, class: 'form-control'
+ %p.help-block
+ Use this token to validate received payloads
.form-group
- = form.label :url, 'Trigger', class: 'control-label'
- .col-sm-10.prepend-top-10
- %div
- System hook will be triggered on set of events like creating project
- or adding ssh key. But you can also enable extra triggers like Push events.
+ = form.label :url, 'Trigger', class: 'label-light'
+ %ul.list-unstyled
+ %li
+ .help-block
+ System hook will be triggered on set of events like creating project
+ or adding ssh key. But you can also enable extra triggers like Push events.
.prepend-top-default
= form.check_box :repository_update_events, class: 'pull-left'
@@ -24,21 +23,21 @@
%strong Repository update events
%p.light
This URL will be triggered when repository is updated
- %div
+ %li
= form.check_box :push_events, class: 'pull-left'
.prepend-left-20
= form.label :push_events, class: 'list-label' do
%strong Push events
%p.light
This URL will be triggered for each branch updated to the repository
- %div
+ %li
= form.check_box :tag_push_events, class: 'pull-left'
.prepend-left-20
= form.label :tag_push_events, class: 'list-label' do
%strong Tag push events
%p.light
This URL will be triggered when a new tag is pushed to the repository
- %div
+ %li
= form.check_box :merge_requests_events, class: 'pull-left'
.prepend-left-20
= form.label :merge_requests_events, class: 'list-label' do
@@ -46,9 +45,8 @@
%p.light
This URL will be triggered when a merge request is created/updated/merged
.form-group
- = form.label :enable_ssl_verification, 'SSL verification', class: 'control-label checkbox'
- .col-sm-10
- .checkbox
- = form.label :enable_ssl_verification do
- = form.check_box :enable_ssl_verification
- %strong Enable SSL verification
+ = form.label :enable_ssl_verification, 'SSL verification', class: 'label-light checkbox'
+ .checkbox
+ = form.label :enable_ssl_verification do
+ = form.check_box :enable_ssl_verification
+ %strong Enable SSL verification
diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index bc02d9969d6..d9e2ce5e74c 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -1,33 +1,35 @@
- page_title 'System Hooks'
-%h3.page-title
- System hooks
+.row.prepend-top-default
+ .col-lg-4
+ %h4.prepend-top-0
+ = page_title
+ %p
+ #{link_to 'System hooks ', help_page_path('system_hooks/system_hooks'), class: 'vlink'} can be
+ used for binding events when GitLab creates a User or Project.
-%p.light
- #{link_to 'System hooks ', help_page_path('system_hooks/system_hooks'), class: 'vlink'} can be
- used for binding events when GitLab creates a User or Project.
+ .col-lg-8.append-bottom-default
+ = 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-create'
-%hr
+ %hr
-= form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-horizontal' } do |f|
- = render partial: 'form', locals: { form: f, hook: @hook }
- .form-actions
- = f.submit 'Add system hook', class: 'btn btn-create'
-%hr
+ - if @hooks.any?
+ .panel.panel-default
+ .panel-heading
+ System hooks (#{@hooks.count})
+ %ul.content-list
+ - @hooks.each do |hook|
+ %li
+ .controls
+ = render 'shared/web_hooks/test_button', triggers: SystemHook.triggers, hook: hook, button_class: 'btn-sm'
+ = link_to 'Edit', edit_admin_hook_path(hook), class: 'btn btn-sm'
+ = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm'
+ .monospace= hook.url
+ %div
+ - SystemHook.triggers.each_value do |event|
+ - if hook.public_send(event)
+ %span.label.label-gray= event.to_s.titleize
+ %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
-- if @hooks.any?
- .panel.panel-default
- .panel-heading
- System hooks (#{@hooks.count})
- %ul.content-list
- - @hooks.each do |hook|
- %li
- .controls
- = render 'shared/web_hooks/test_button', triggers: SystemHook.triggers, hook: hook, button_class: 'btn-sm'
- = link_to 'Edit', edit_admin_hook_path(hook), class: 'btn btn-sm'
- = link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm'
- .monospace= hook.url
- %div
- - SystemHook.triggers.each_value do |event|
- - if hook.public_send(event)
- %span.label.label-gray= event.to_s.titleize
- %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
+= render 'shared/plugins/index'
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 42f92079d85..c02ddafe108 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -1,8 +1,8 @@
- add_to_breadcrumbs "Projects", admin_projects_path
-- breadcrumb_title @project.name_with_namespace
-- page_title @project.name_with_namespace, "Projects"
+- breadcrumb_title @project.full_name
+- page_title @project.full_name, "Projects"
%h3.page-title
- Project: #{@project.name_with_namespace}
+ Project: #{@project.full_name}
= link_to edit_project_path(@project), class: "btn btn-nr pull-right" do
%i.fa.fa-pencil-square-o
Edit
diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml
index 6d8fad0eb8d..185e9d7b35d 100644
--- a/app/views/admin/runners/show.html.haml
+++ b/app/views/admin/runners/show.html.haml
@@ -39,7 +39,7 @@
%tr.alert-info
%td
%strong
- = project.name_with_namespace
+ = project.full_name
%td
.pull-right
= link_to 'Disable', [:admin, project.namespace.becomes(Namespace), project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
@@ -61,7 +61,7 @@
- @projects.each do |project|
%tr
%td
- = project.name_with_namespace
+ = project.full_name
%td
.pull-right
= form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f|
@@ -95,7 +95,7 @@
%td.status
- if project
- = project.name_with_namespace
+ = project.full_name
%td.build-link
- if project
diff --git a/app/views/admin/users/projects.html.haml b/app/views/admin/users/projects.html.haml
index 4a440f3f6d4..96835ee9af5 100644
--- a/app/views/admin/users/projects.html.haml
+++ b/app/views/admin/users/projects.html.haml
@@ -29,12 +29,12 @@
.panel.panel-default
.panel-heading Joined projects (#{@joined_projects.count})
%ul.well-list
- - @joined_projects.sort_by(&:name_with_namespace).each do |project|
+ - @joined_projects.sort_by(&:full_name).each do |project|
- member = project.team.find_member(@user.id)
%li.project_member
.list-item-name
= link_to admin_project_path(project), class: dom_class(project) do
- = project.name_with_namespace
+ = project.full_name
- if member
.pull-right
diff --git a/app/views/groups/boards/index.html.haml b/app/views/groups/boards/index.html.haml
new file mode 100644
index 00000000000..bb56769bd3f
--- /dev/null
+++ b/app/views/groups/boards/index.html.haml
@@ -0,0 +1 @@
+= render "shared/boards/show", board: @boards.first
diff --git a/app/views/groups/boards/show.html.haml b/app/views/groups/boards/show.html.haml
new file mode 100644
index 00000000000..92838fa4b11
--- /dev/null
+++ b/app/views/groups/boards/show.html.haml
@@ -0,0 +1 @@
+= render "shared/boards/show", board: @board, group: true
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index ca3f018c5e6..36df03302e8 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -2,9 +2,6 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@group.name} issues")
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag 'common_vue'
-
- if group_issues_count(state: 'all').zero?
= render 'shared/empty_states/issues', project_select_button: true
- else
diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml
index d10efdad53b..ac7e12fcd0b 100644
--- a/app/views/groups/labels/index.html.haml
+++ b/app/views/groups/labels/index.html.haml
@@ -1,8 +1,10 @@
- page_title 'Labels'
+- issuables = ['issues', 'merge requests']
+
.top-area.adjust
.nav-text
- Labels can be applied to issues and merge requests. Group labels are available for any project within the group.
+ = _("Labels can be applied to %{features}. Group labels are available for any project within the group.") % { features: issuables.to_sentence }
.nav-controls
- if can?(current_user, :admin_label, @group)
@@ -16,4 +18,4 @@
= paginate @labels, theme: 'gitlab'
- else
.nothing-here-block
- No labels created yet.
+ = _("No labels created yet.")
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 8d2bc810a7d..ef181b425bc 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -14,7 +14,7 @@
.list-item-name
%span{ class: visibility_level_color(project.visibility_level) }
= visibility_level_icon(project.visibility_level)
- %strong= link_to project.name_with_namespace, project
+ %strong= link_to project.full_name, project
.pull-right
- if project.archived
%span.label.label-warning archived
diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml
index e9a04e6c122..638c8b5a672 100644
--- a/app/views/import/_githubish_status.html.haml
+++ b/app/views/import/_githubish_status.html.haml
@@ -2,11 +2,11 @@
- provider_title = Gitlab::ImportSources.title(provider)
%p.light
- Select projects you want to import.
+ = import_githubish_choose_repository_message
%hr
%p
= button_tag class: "btn btn-import btn-success js-import-all" do
- Import all projects
+ = import_all_githubish_repositories_button_label
= icon("spinner spin", class: "loading-icon")
.table-responsive
@@ -16,9 +16,9 @@
%colgroup.import-jobs-status-col
%thead
%tr
- %th From #{provider_title}
- %th To GitLab
- %th Status
+ %th= _('From %{provider_title}') % { provider_title: provider_title }
+ %th= _('To GitLab')
+ %th= _('Status')
%tbody
- @already_added_projects.each do |project|
%tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" }
@@ -30,10 +30,12 @@
- if project.import_status == 'finished'
%span
%i.fa.fa-check
- done
+ = _('Done')
- elsif project.import_status == 'started'
%i.fa.fa-spinner.fa-spin
- started
+ = _('Started')
+ - elsif project.import_status == 'failed'
+ = _('Failed')
- else
= project.human_import_status_name
@@ -55,7 +57,9 @@
= text_field_tag :path, repo.name, class: "input-mini form-control", tabindex: 2, autofocus: true, required: true
%td.import-actions.job-status
= button_tag class: "btn btn-import js-add-to-import" do
- Import
+ = has_ci_cd_only_params? ? _('Connect') : _('Import')
= icon("spinner spin", class: "loading-icon")
-.js-importer-status{ data: { jobs_import_path: "#{url_for([:jobs, :import, provider])}", import_path: "#{url_for([:import, provider])}" } }
+.js-importer-status{ data: { jobs_import_path: "#{url_for([:jobs, :import, provider])}",
+ import_path: "#{url_for([:import, provider])}",
+ ci_cd_only: "#{has_ci_cd_only_params?}" } }
diff --git a/app/views/import/github/new.html.haml b/app/views/import/github/new.html.haml
index 9c2da3a3eec..ca47ab5f274 100644
--- a/app/views/import/github/new.html.haml
+++ b/app/views/import/github/new.html.haml
@@ -1,43 +1,31 @@
-- page_title "GitHub Import"
+- title = has_ci_cd_only_params? ? _('Connect repositories from GitHub') : _('GitHub import')
+- page_title title
+- breadcrumb_title title
- header_title "Projects", root_path
%h3.page-title
- = icon 'github', text: 'Import Projects from GitHub'
+ = icon 'github', text: import_github_title
- if github_import_configured?
%p
- To import a GitHub project, you first need to authorize GitLab to access
- the list of your GitHub repositories:
+ = import_github_authorize_message
- = link_to 'List your GitHub repositories', status_import_github_path, class: 'btn btn-success'
+ = link_to _('List your GitHub repositories'), status_import_github_path, class: 'btn btn-success'
%hr
%p
- - if github_import_configured?
- Alternatively,
- - else
- To import a GitHub project,
- you can use a
- = succeed '.' do
- = link_to 'Personal Access Token', 'https://github.com/settings/tokens'
- When you create your Personal Access Token,
- you will need to select the <code>repo</code> scope, so we can display a
- list of your public and private repositories which are available for import.
+ = import_github_personal_access_token_message
= form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do
.form-group
- = text_field_tag :personal_access_token, '', class: 'form-control', placeholder: "Personal Access Token", size: 40
- = submit_tag 'List your GitHub repositories', class: 'btn btn-success'
+ = text_field_tag :personal_access_token, '', class: 'form-control', placeholder: _('Personal Access Token'), size: 40
+ = submit_tag _('List your GitHub repositories'), class: 'btn btn-success'
+
+ -# EE-specific start
+ -# EE-specific end
- unless github_import_configured?
%hr
%p
- Note:
- - if current_user.admin?
- As an administrator you may like to configure
- - else
- Consider asking your GitLab administrator to configure
- = link_to 'GitHub integration', help_page_path("integration/github")
- which will allow login via GitHub and allow importing projects without
- generating a Personal Access Token.
+ = import_configure_github_admin_message
diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml
index 0fe578a0036..b00b972d9c9 100644
--- a/app/views/import/github/status.html.haml
+++ b/app/views/import/github/status.html.haml
@@ -1,6 +1,8 @@
-- page_title "GitHub Import"
+- title = has_ci_cd_only_params? ? _('Connect repositories from GitHub') : _('GitHub import')
+- page_title title
+- breadcrumb_title title
- header_title "Projects", root_path
%h3.page-title
- = icon 'github', text: 'Import Projects from GitHub'
+ = icon 'github', text: import_github_title
= render 'import/githubish_status', provider: 'github'
diff --git a/app/views/invites/show.html.haml b/app/views/invites/show.html.haml
index ad6213b4efd..c2bb1216c5f 100644
--- a/app/views/invites/show.html.haml
+++ b/app/views/invites/show.html.haml
@@ -12,7 +12,7 @@
- project = @member.source
project
%strong
- = link_to project.name_with_namespace, project_url(project)
+ = link_to project.full_name, project_url(project)
- when Group
- group = @member.source
group
diff --git a/app/views/layouts/nav/projects_dropdown/_show.html.haml b/app/views/layouts/nav/projects_dropdown/_show.html.haml
index 59becb043d3..5809d6f7fea 100644
--- a/app/views/layouts/nav/projects_dropdown/_show.html.haml
+++ b/app/views/layouts/nav/projects_dropdown/_show.html.haml
@@ -1,4 +1,4 @@
-- project_meta = { id: @project.id, name: @project.name, namespace: @project.name_with_namespace, web_url: project_path(@project), avatar_url: @project.avatar_url } if @project&.persisted?
+- project_meta = { id: @project.id, name: @project.name, namespace: @project.full_name, web_url: project_path(@project), avatar_url: @project.avatar_url } if @project&.persisted?
.projects-dropdown-container
.project-dropdown-sidebar.qa-projects-dropdown-sidebar
%ul
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index b520f28123f..5ea19c9882d 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -1,6 +1,6 @@
- issues_count = group_issues_count(state: 'opened')
- merge_requests_count = group_merge_requests_count(state: 'opened')
-- issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index']
+- issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index', 'boards#index', 'boards#show']
.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
.nav-sidebar-inner-scroll
@@ -51,12 +51,19 @@
%strong.fly-out-top-item-name
#{ _('Issues') }
%span.badge.count.issue_counter.fly-out-badge= number_with_delimiter(issues_count)
+
%li.divider.fly-out-top-item
= nav_link(path: 'groups#issues', html_options: { class: 'home' }) do
= link_to issues_group_path(@group), title: 'List' do
%span
List
+ - if group_sidebar_link?(:boards)
+ = nav_link(path: ['boards#index', 'boards#show']) do
+ = link_to group_boards_path(@group), title: boards_link_text do
+ %span
+ = boards_link_text
+
- if group_sidebar_link?(:labels)
= nav_link(path: 'labels#index') do
= link_to group_labels_path(@group), title: 'Labels' do
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 6b847fb4b7c..6b51483810e 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -1,4 +1,4 @@
-- page_title @project.name_with_namespace
+- page_title @project.full_name
- page_description @project.description unless page_description
- header_title project_title(@project) unless header_title
- nav "project"
diff --git a/app/views/notify/project_was_exported_email.html.haml b/app/views/notify/project_was_exported_email.html.haml
index f0ba7827cef..71c62f6be4e 100644
--- a/app/views/notify/project_was_exported_email.html.haml
+++ b/app/views/notify/project_was_exported_email.html.haml
@@ -3,6 +3,6 @@
%p
The project export can be downloaded from:
= link_to download_export_project_url(@project), rel: 'nofollow', download: '' do
- = @project.name_with_namespace + " export"
+ = @project.full_name + " export"
%p
The download link will expire in 24 hours.
diff --git a/app/views/notify/project_was_moved_email.html.haml b/app/views/notify/project_was_moved_email.html.haml
index c476a39b661..1b6b1a81665 100644
--- a/app/views/notify/project_was_moved_email.html.haml
+++ b/app/views/notify/project_was_moved_email.html.haml
@@ -3,7 +3,7 @@
%p
The project is now located under
= link_to project_url(@project) do
- = @project.name_with_namespace
+ = @project.full_name
%p
To update the remote url in your local repository run (for ssh):
%p{ style: "background: #f5f5f5; padding:10px; border:1px solid #ddd" }
diff --git a/app/views/profiles/chat_names/_chat_name.html.haml b/app/views/profiles/chat_names/_chat_name.html.haml
index fe1cf802971..c7094800fb2 100644
--- a/app/views/profiles/chat_names/_chat_name.html.haml
+++ b/app/views/profiles/chat_names/_chat_name.html.haml
@@ -4,7 +4,7 @@
%td
%strong
- if can?(current_user, :read_project, project)
- = link_to project.name_with_namespace, project_path(project)
+ = link_to project.full_name, project_path(project)
- else
.light N/A
%td
diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml
index 457583cfd35..1e206def7ee 100644
--- a/app/views/profiles/keys/index.html.haml
+++ b/app/views/profiles/keys/index.html.haml
@@ -12,7 +12,9 @@
Add an SSH key
%p.profile-settings-content
Before you can add an SSH key you need to
- = link_to "generate it.", help_page_path("ssh/README")
+ = link_to "generate one", help_page_path("ssh/README", anchor: 'generating-a-new-ssh-key-pair')
+ or use an
+ = link_to "existing key.", help_page_path("ssh/README", anchor: 'locating-an-existing-ssh-key-pair')
= render 'form'
%hr
%h5
diff --git a/app/views/projects/_commit_button.html.haml b/app/views/projects/_commit_button.html.haml
index b55dc3dce5c..b387e38c1a6 100644
--- a/app/views/projects/_commit_button.html.haml
+++ b/app/views/projects/_commit_button.html.haml
@@ -3,6 +3,4 @@
= link_to 'Cancel', cancel_path,
class: 'btn btn-cancel', data: {confirm: leave_edit_message}
- - unless can?(current_user, :push_code, @project)
- .inline.prepend-left-10
- = commit_in_fork_help
+ = render 'shared/projects/edit_information'
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index b565f14747a..a2ecfddb163 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -23,6 +23,12 @@
- deleted_message = s_('ForkedFromProjectPath|Forked from %{project_name} (deleted)')
= deleted_message % { project_name: fork_source_name(@project) }
+ .project-badges
+ - @project.badges.each do |badge|
+ - badge_link_url = badge.rendered_link_url(@project)
+ %a{ href: badge_link_url, target: '_blank', rel: 'noopener noreferrer' }
+ %img{ src: badge.rendered_image_url(@project), alt: badge_link_url }
+
.project-repo-buttons
.count-buttons
= render 'projects/buttons/star'
diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml
index d367bd6be7b..f4b5ef1555e 100644
--- a/app/views/projects/_new_project_fields.html.haml
+++ b/app/views/projects/_new_project_fields.html.haml
@@ -1,6 +1,8 @@
- visibility_level = params.dig(:project, :visibility_level) || default_project_visibility
+- ci_cd_only = local_assigns.fetch(:ci_cd_only, false)
.row{ id: project_name_id }
+ = f.hidden_field :ci_cd_only, value: ci_cd_only
.form-group.project-path.col-sm-6
= f.label :namespace_id, class: 'label-light' do
%span
diff --git a/app/views/projects/blob/_new_dir.html.haml b/app/views/projects/blob/_new_dir.html.haml
index 5d48a35dc4c..48ff66900be 100644
--- a/app/views/projects/blob/_new_dir.html.haml
+++ b/app/views/projects/blob/_new_dir.html.haml
@@ -17,6 +17,4 @@
= submit_tag _("Create directory"), class: 'btn btn-create'
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- - unless can?(current_user, :push_code, @project)
- .inline.prepend-left-10
- = commit_in_fork_help
+ = render 'shared/projects/edit_information'
diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml
index f1324c61500..182d02376bf 100644
--- a/app/views/projects/blob/_upload.html.haml
+++ b/app/views/projects/blob/_upload.html.haml
@@ -24,6 +24,4 @@
= button_title
= link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- - unless can?(current_user, :push_code, @project)
- .inline.prepend-left-10
- = commit_in_fork_help
+ = render 'shared/projects/edit_information'
diff --git a/app/views/projects/branches/_panel.html.haml b/app/views/projects/branches/_panel.html.haml
new file mode 100644
index 00000000000..12e5a8e8d69
--- /dev/null
+++ b/app/views/projects/branches/_panel.html.haml
@@ -0,0 +1,19 @@
+- branches = local_assigns.fetch(:branches)
+- state = local_assigns.fetch(:state)
+- panel_title = local_assigns.fetch(:panel_title)
+- show_more_text = local_assigns.fetch(:show_more_text)
+- project = local_assigns.fetch(:project)
+- overview_max_branches = local_assigns.fetch(:overview_max_branches)
+
+- return unless branches.any?
+
+.panel.panel-default.prepend-top-10
+ .panel-heading
+ %h4.panel-title
+ = panel_title
+ %ul.content-list.all-branches
+ - branches.first(overview_max_branches).each do |branch|
+ = render "projects/branches/branch", branch: branch, merged: project.repository.merged_to_root_ref?(branch)
+ - if branches.size > overview_max_branches
+ .panel-footer.text-center
+ = link_to show_more_text, project_branches_filtered_path(project, state: state), id: "state-#{state}", data: { state: state }
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index fb770764364..5dcc72d8263 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -3,26 +3,35 @@
%div{ class: container_class }
.top-area.adjust
- - if can?(current_user, :admin_project, @project)
- .nav-text
- - project_settings_link = link_to s_('Branches|project settings'), project_protected_branches_path(@project)
- = s_('Branches|Protected branches can be managed in %{project_settings_link}').html_safe % { project_settings_link: project_settings_link }
+ %ul.nav-links.issues-state-filters
+ %li{ class: active_when(@mode == 'overview') }>
+ = link_to s_('Branches|Overview'), project_branches_path(@project), title: s_('Branches|Show overview of the branches')
+
+ %li{ class: active_when(@mode == 'active') }>
+ = link_to s_('Branches|Active'), project_branches_filtered_path(@project, state: 'active'), title: s_('Branches|Show active branches')
+
+ %li{ class: active_when(@mode == 'stale') }>
+ = link_to s_('Branches|Stale'), project_branches_filtered_path(@project, state: 'stale'), title: s_('Branches|Show stale branches')
+
+ %li{ class: active_when(!%w[overview active stale].include?(@mode)) }>
+ = link_to s_('Branches|All'), project_branches_filtered_path(@project, state: 'all'), title: s_('Branches|Show all branches')
.nav-controls
- = form_tag(filter_branches_path, method: :get) do
+ = form_tag(project_branches_filtered_path(@project, state: 'all'), method: :get) do
= search_field_tag :search, params[:search], { placeholder: s_('Branches|Filter by branch name'), id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
- .dropdown.inline>
- %button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
- %span.light
- = branches_sort_options_hash[@sort]
- = icon('chevron-down')
- %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable
- %li.dropdown-header
- = s_('Branches|Sort by')
- - branches_sort_options_hash.each do |value, title|
- %li
- = link_to title, filter_branches_path(sort: value), class: ("is-active" if @sort == value)
+ - unless @mode == 'overview'
+ .dropdown.inline>
+ %button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
+ %span.light
+ = branches_sort_options_hash[@sort]
+ = icon('chevron-down')
+ %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable
+ %li.dropdown-header
+ = s_('Branches|Sort by')
+ - branches_sort_options_hash.each do |value, title|
+ %li
+ = link_to title, project_branches_filtered_path(@project, state: 'all', search: params[:search], sort: value), class: ("is-active" if @sort == value)
- if can? current_user, :push_code, @project
= link_to project_merged_branches_path(@project),
@@ -35,7 +44,17 @@
= link_to new_project_branch_path(@project), class: 'btn btn-create' do
= s_('Branches|New branch')
- - if @branches.any?
+ - if can?(current_user, :admin_project, @project)
+ - project_settings_link = link_to s_('Branches|project settings'), project_protected_branches_path(@project)
+ .row-content-block
+ %h5
+ = s_('Branches|Protected branches can be managed in %{project_settings_link}.').html_safe % { project_settings_link: project_settings_link }
+
+ - if @mode == 'overview' && (@active_branches.any? || @stale_branches.any?)
+ = render "projects/branches/panel", branches: @active_branches, state: 'active', panel_title: s_('Branches|Active branches'), show_more_text: s_('Branches|Show more active branches'), project: @project, overview_max_branches: @overview_max_branches
+ = render "projects/branches/panel", branches: @stale_branches, state: 'stale', panel_title: s_('Branches|Stale branches'), show_more_text: s_('Branches|Show more stale branches'), project: @project, overview_max_branches: @overview_max_branches
+
+ - elsif @branches.any?
%ul.content-list.all-branches
- @branches.each do |branch|
= render "projects/branches/branch", branch: branch, merged: @merged_branch_names.include?(branch.name)
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index 0cd2d45c74b..9126476e79e 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -63,7 +63,7 @@
- if admin
%td
- if job.project
- = link_to job.project.name_with_namespace, admin_project_path(job.project)
+ = link_to job.project.full_name, admin_project_path(job.project)
%td
- if job.try(:runner)
= runner_link(job.runner)
diff --git a/app/views/projects/clusters/_integration_form.html.haml b/app/views/projects/clusters/_integration_form.html.haml
index d4c0cd82ce3..db97203a2aa 100644
--- a/app/views/projects/clusters/_integration_form.html.haml
+++ b/app/views/projects/clusters/_integration_form.html.haml
@@ -21,6 +21,12 @@
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
.form-group
+ %h5= s_('ClusterIntegration|Security')
+ %p
+ = s_("ClusterIntegration|The default cluster configuration grants access to a wide set of functionalities needed to successfully build and deploy a containerised application.")
+ = link_to s_("ClusterIntegration|Learn more about security configuration"), help_page_path('user/project/clusters/index.md', anchor: 'security-implications')
+
+ .form-group
%h5= s_('ClusterIntegration|Environment scope')
%p
= s_("ClusterIntegration|Choose which of your project's environments will use this Kubernetes cluster.")
diff --git a/app/views/projects/commit/_change.html.haml b/app/views/projects/commit/_change.html.haml
index 93407956f56..21e4664d4e4 100644
--- a/app/views/projects/commit/_change.html.haml
+++ b/app/views/projects/commit/_change.html.haml
@@ -35,6 +35,4 @@
= submit_tag label, class: 'btn btn-create'
= link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- - unless can?(current_user, :push_code, @project)
- .inline.prepend-left-10
- = commit_in_fork_help
+ = render 'shared/projects/edit_information'
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index 02395b6eb9b..5041f322612 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1,7 +1,5 @@
- @no_container = true
- page_title "Cycle Analytics"
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag('common_vue')
#cycle-analytics{ class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
- if @cycle_analytics_no_data
diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml
index 0d656b25bc8..7ebe617766f 100644
--- a/app/views/projects/environments/index.html.haml
+++ b/app/views/projects/environments/index.html.haml
@@ -2,9 +2,6 @@
- page_title "Environments"
- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag("common_vue")
-
#environments-list-view{ data: { environments_data: environments_list_data,
"can-create-deployment" => can?(current_user, :create_deployment, @project).to_s,
"can-read-environment" => can?(current_user, :read_environment, @project).to_s,
diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml
index 9d9759ebc5f..c151b5acdf7 100644
--- a/app/views/projects/environments/metrics.html.haml
+++ b/app/views/projects/environments/metrics.html.haml
@@ -15,7 +15,8 @@
"empty-getting-started-svg-path": image_path('illustrations/monitoring/getting_started.svg'),
"empty-loading-svg-path": image_path('illustrations/monitoring/loading.svg'),
"empty-unable-to-connect-svg-path": image_path('illustrations/monitoring/unable_to_connect.svg'),
- "additional-metrics": additional_metrics_project_environment_path(@project, @environment, format: :json),
+ "metrics-endpoint": additional_metrics_project_environment_path(@project, @environment, format: :json),
+ "deployment-endpoint": project_environment_deployments_path(@project, @environment, format: :json),
"project-path": project_path(@project),
"tags-path": project_tags_path(@project),
- "has-metrics": "#{@environment.has_metrics?}", deployment_endpoint: project_environment_deployments_path(@project, @environment, format: :json) } }
+ "has-metrics": "#{@environment.has_metrics?}" } }
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 2599ce5c4b8..620fd1906ba 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
@@ -53,7 +53,7 @@
- if admin
%td
- if generic_commit_status.project
- = link_to generic_commit_status.project.name_with_namespace, admin_project_path(generic_commit_status.project)
+ = link_to generic_commit_status.project.full_name, admin_project_path(generic_commit_status.project)
%td
- if generic_commit_status.try(:runner)
= runner_link(generic_commit_status.runner)
diff --git a/app/views/projects/imports/show.html.haml b/app/views/projects/imports/show.html.haml
index 8c490773a56..3b0c828ccd1 100644
--- a/app/views/projects/imports/show.html.haml
+++ b/app/views/projects/imports/show.html.haml
@@ -1,12 +1,11 @@
-- page_title @project.forked? ? "Forking in progress" : "Import in progress"
+- page_title import_in_progress_title
+
.save-project-loader
.center
%h2
%i.fa.fa-spinner.fa-spin
- - if @project.forked?
- Forking in progress.
- - else
- Import in progress.
- - if @project.external_import?
+ = import_in_progress_title
+ - if !has_ci_cd_only_params? && @project.external_import?
%p.monospace git clone --bare #{@project.safe_import_url}
- %p Please wait while we import the repository for you. Refresh at will.
+ %p
+ = import_wait_and_refresh_message
diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml
index 5f97d31f610..5c36d2202a6 100644
--- a/app/views/projects/issues/_merge_requests.html.haml
+++ b/app/views/projects/issues/_merge_requests.html.haml
@@ -18,7 +18,7 @@
- unless @issue.project.id == merge_request.target_project.id
in
- project = merge_request.target_project
- = link_to project.name_with_namespace, project_path(project)
+ = link_to project.full_name, project_path(project)
- if merge_request.merged?
%span.merge-request-status.prepend-left-10.merged
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index fb06ba58c27..c427a9eedc2 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -4,9 +4,6 @@
- page_title "Issues"
- new_issue_email = @project.new_issuable_address(current_user, 'issue')
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag 'common_vue'
-
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@project.name} issues")
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 80e4dce1a80..9c78bade254 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -4,6 +4,7 @@
- can_admin_label = can?(current_user, :admin_label, @project)
- if @labels.exists? || @prioritized_labels.exists?
+ #promote-label-modal
%div{ class: container_class }
.top-area.adjust
.nav-text
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 720ba236434..b2c0d9e1cfa 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -6,9 +6,6 @@
- page_title "Merge Requests"
- new_merge_request_email = @project.new_issuable_address(current_user, 'merge_request')
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag 'common_vue'
-
%div{ class: container_class }
= render 'projects/last_push'
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 6a7bc4b1888..5b0197ed58c 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -13,6 +13,7 @@
.milestones
#delete-milestone-modal
+ #promote-milestone-modal
%ul.content-list
= render @milestones
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index de381d489c6..b423888c875 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -27,8 +27,15 @@
Edit
- if @project.group
- = link_to promote_project_milestone_path(@milestone.project, @milestone), title: "Promote to Group Milestone", class: 'btn btn-grouped', data: { confirm: "Promoting #{@milestone.title} will make it available for all projects inside #{@project.group.name}. Existing project milestones with the same name will be merged. This action cannot be reversed.", toggle: "tooltip" }, method: :post do
- Promote
+ %button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
+ target: '#promote-milestone-modal',
+ milestone_title: @milestone.title,
+ url: promote_project_milestone_path(@milestone.project, @milestone),
+ container: 'body' },
+ disabled: true,
+ type: 'button' }
+ = _('Promote')
+ #promote-milestone-modal
- if @milestone.active?
= link_to 'Close milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-nr btn-grouped"
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 679ba23a4db..8cdb0a6aff4 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -12,11 +12,14 @@
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
%h4.prepend-top-0
- New project
+ = _('New project')
%p
- A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), #{link_to 'among other things', help_page_path("user/project/index.md", anchor: "projects-features"), target: '_blank'}.
+ - among_other_things_link = link_to _('among other things'), help_page_path("user/project/index.md", anchor: "projects-features"), target: '_blank'
+ = _('A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), %{among_other_things_link}.').html_safe % { among_other_things_link: among_other_things_link }
%p
- All features are enabled when you create a project, but you can disable the ones you don’t need in the project settings.
+ = _('All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings.')
+ -# EE-specific start
+ -# EE-specific end
.md
= brand_new_project_guidelines
%p
@@ -28,36 +31,38 @@
.col-lg-9.js-toggle-container
%ul.nav-links.gitlab-tabs{ role: 'tablist' }
- %li{ class: ('active' if active_tab == 'blank'), role: 'presentation' }
+ %li{ class: active_when(active_tab == 'blank'), role: 'presentation' }
%a{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Blank project
%span.visible-xs Blank
- %li{ class: ('active' if active_tab == 'template'), role: 'presentation' }
+ %li{ class: active_when(active_tab == 'template'), role: 'presentation' }
%a{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Create from template
%span.visible-xs Template
- %li{ class: ('active' if active_tab == 'import'), role: 'presentation' }
+ %li{ class: active_when(active_tab == 'import'), role: 'presentation' }
%a{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Import project
%span.visible-xs Import
+ -# EE-specific start
+ -# EE-specific end
.tab-content.gitlab-tab-content
- .tab-pane{ id: 'blank-project-pane', class: ('active' if active_tab == 'blank'), role: 'tabpanel' }
+ .tab-pane{ id: 'blank-project-pane', class: active_when(active_tab == 'blank'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f|
= render 'new_project_fields', f: f, project_name_id: "blank-project-name"
- .tab-pane.no-padding{ id: 'create-from-template-pane', class: ('active' if active_tab == 'template'), role: 'tabpanel' }
+ .tab-pane.no-padding{ id: 'create-from-template-pane', class: active_when(active_tab == 'template'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f|
.project-template
.form-group
%div
= render 'project_templates', f: f
- .tab-pane.import-project-pane{ id: 'import-project-pane', class: ('active' if active_tab == 'import'), role: 'tabpanel' }
+ .tab-pane.import-project-pane.js-toggle-container{ id: 'import-project-pane', class: active_when(active_tab == 'import'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f|
- if import_sources_enabled?
.project-import.row
- .col-sm-12
+ .col-lg-12
.form-group.import-btn-container.clearfix
= f.label :visibility_level, class: 'label-light' do #the label here seems wrong
Import project from
@@ -68,7 +73,7 @@
= icon('gitlab', text: 'GitLab export')
%div
- if github_import_enabled?
- = link_to new_import_github_path, class: 'btn import_github' do
+ = link_to new_import_github_path, class: 'btn js-import-github' do
= icon('github', text: 'GitHub')
%div
- if bitbucket_import_enabled?
@@ -97,7 +102,7 @@
Gitea
%div
- if git_import_enabled?
- %button.btn.js-toggle-button.import_git{ type: "button" }
+ %button.btn.js-toggle-button.js-import-git-toggle-button{ type: "button", data: { toggle_open_class: 'active' } }
= icon('git', text: 'Repo by URL')
.col-lg-12
.js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') }
@@ -105,6 +110,10 @@
= render "shared/import_form", f: f
= render 'new_project_fields', f: f, project_name_id: "import-url-name"
+
+ -# EE-specific start
+ -# EE-specific end
+
.save-project-loader.hide
.center
%h2
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
index cf95cdbfec2..3e6b3346787 100644
--- a/app/views/projects/pipelines/index.html.haml
+++ b/app/views/projects/pipelines/index.html.haml
@@ -7,8 +7,9 @@
"help-auto-devops-path" => help_page_path('topics/autodevops/index.md'),
"empty-state-svg-path" => image_path('illustrations/pipelines_empty.svg'),
"error-state-svg-path" => image_path('illustrations/pipelines_failed.svg'),
- "new-pipeline-path" => new_project_pipeline_path(@project),
+ "no-pipelines-svg-path" => image_path('illustrations/pipelines_pending.svg'),
"can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
- "has-ci" => @repository.gitlab_ci_yml,
- "ci-lint-path" => ci_lint_path,
- "reset-cache-path" => reset_cache_project_settings_ci_cd_path(@project) } }
+ "new-pipeline-path" => can?(current_user, :create_pipeline, @project) && new_project_pipeline_path(@project),
+ "ci-lint-path" => can?(current_user, :create_pipeline, @project) && ci_lint_path,
+ "reset-cache-path" => can?(current_user, :admin_pipeline, @project) && reset_cache_project_settings_ci_cd_path(@project) ,
+ "has-gitlab-ci" => (@project.has_ci? && @project.builds_enabled?).to_s } }
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
index ffb0ae95f9b..a7d7c923957 100644
--- a/app/views/projects/pipelines/show.html.haml
+++ b/app/views/projects/pipelines/show.html.haml
@@ -10,6 +10,3 @@
= render "projects/pipelines/with_tabs", pipeline: @pipeline
.js-pipeline-details-vue{ data: { endpoint: project_pipeline_path(@project, @pipeline, format: :json) } }
-
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag('common_vue')
diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml
index 27e1f9fba3e..12d56e244ce 100644
--- a/app/views/projects/registry/repositories/index.html.haml
+++ b/app/views/projects/registry/repositories/index.html.haml
@@ -14,8 +14,6 @@
.col-lg-12
#js-vue-registry-images{ data: { endpoint: project_container_registry_index_path(@project, format: :json) } }
- = webpack_bundle_tag('common_vue')
-
.row.prepend-top-10
.col-lg-12
.panel.panel-default
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index 17e804d682b..053ea24b848 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -5,6 +5,9 @@
= boolean_to_icon @service.activated?
%p= @service.description
+
+ - if @service.respond_to?(:detailed_description)
+ %p= @service.detailed_description
.col-lg-9
= form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put, html: { class: 'gl-show-field-errors form-horizontal integration-settings-form js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
= render 'shared/service_settings', form: form, subject: @service
diff --git a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
index 5dbcbf7eba6..2ab0227126a 100644
--- a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
+++ b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
@@ -1,4 +1,4 @@
-- run_actions_text = "Perform common operations on GitLab project: #{@project.name_with_namespace}"
+- run_actions_text = "Perform common operations on GitLab project: #{@project.full_name}"
%p To setup this service:
%ul.list-unstyled.indent-list
@@ -20,7 +20,7 @@
.form-group
= label_tag :display_name, 'Display name', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group
- = text_field_tag :display_name, "GitLab / #{@project.name_with_namespace}", class: 'form-control input-sm', readonly: 'readonly'
+ = text_field_tag :display_name, "GitLab / #{@project.full_name}", class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn
= clipboard_button(target: '#display_name')
diff --git a/app/views/projects/services/prometheus/_show.html.haml b/app/views/projects/services/prometheus/_show.html.haml
index 6dc2b85fd32..43e6a173108 100644
--- a/app/views/projects/services/prometheus/_show.html.haml
+++ b/app/views/projects/services/prometheus/_show.html.haml
@@ -7,21 +7,19 @@
= link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus')
.col-lg-9
- .panel.panel-default.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(@project, :json) } }
+ .panel.panel-default.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(@project, :json), metrics_help_path: help_page_path('user/project/integrations/prometheus_library/metrics') } }
.panel-heading
%h3.panel-title
- = s_('PrometheusService|Monitored')
+ = s_('PrometheusService|Common metrics')
%span.badge.js-monitored-count 0
.panel-body
- .loading-metrics.text-center.js-loading-metrics
- = icon('spinner spin 3x', class: 'metrics-load-spinner')
- %p
+ .loading-metrics.js-loading-metrics
+ %p.prepend-top-10.prepend-left-10
+ = icon('spinner spin', class: 'metrics-load-spinner')
= s_('PrometheusService|Finding and configuring metrics...')
- .empty-metrics.text-center.hidden.js-empty-metrics
- = custom_icon('icon_empty_metrics')
- %p
- = s_('PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment.')
- = link_to s_('PrometheusService|View environments'), project_environments_path(@project), class: 'btn btn-success'
+ .empty-metrics.hidden.js-empty-metrics
+ %p.text-tertiary.prepend-top-10.prepend-left-10
+ = s_('PrometheusService|Waiting for your first deployment to an environment to find common metrics')
%ul.list-unstyled.metrics-list.hidden.js-metrics-list
.panel.panel-default.hidden.js-panel-missing-env-vars
diff --git a/app/views/projects/services/slack_slash_commands/_help.html.haml b/app/views/projects/services/slack_slash_commands/_help.html.haml
index c31c95608c6..d592a5e4663 100644
--- a/app/views/projects/services/slack_slash_commands/_help.html.haml
+++ b/app/views/projects/services/slack_slash_commands/_help.html.haml
@@ -1,4 +1,4 @@
-- pretty_name = defined?(@project) ? @project.name_with_namespace : 'namespace / path'
+- pretty_name = defined?(@project) ? @project.full_name : 'namespace / path'
- run_actions_text = "Perform common operations on GitLab project: #{pretty_name}"
.well
diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml
index 235d532bf98..6bef4d19434 100644
--- a/app/views/projects/settings/repository/show.html.haml
+++ b/app/views/projects/settings/repository/show.html.haml
@@ -2,9 +2,6 @@
- page_title "Repository"
- @content_class = "limit-container-width" unless fluid_layout
-- content_for :page_specific_javascripts do
- = webpack_bundle_tag('common_vue')
-
-# Protected branches & tags use a lot of nested partials.
-# The shared parts of the views can be found in the `shared` directory.
-# Those are used throughout the actual views. These `shared` views are then
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index da364b58e36..10415d011d6 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -1,7 +1,6 @@
- @no_container = true
- @sort ||= sort_value_recently_updated
- page_title s_('TagsPage|Tags')
-- add_to_breadcrumbs("Repository", project_tree_path(@project))
.flex-list{ class: container_class }
.top-area.adjust
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index e43796e9654..e4902d368e7 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -22,7 +22,7 @@
%span.dropdown-toggle-text
Project:
- if @project.present?
- = @project.name_with_namespace
+ = @project.full_name
- else
Any
= icon("chevron-down")
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 60ef44482f0..ab56f48ba4d 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -6,7 +6,7 @@
= search_entries_info(@search_objects, @scope, @search_term)
- unless @show_snippets
- if @project
- in project #{link_to @project.name_with_namespace, [@project.namespace.becomes(Namespace), @project]}
+ in project #{link_to @project.full_name, [@project.namespace.becomes(Namespace), @project]}
- elsif @group
in group #{link_to @group.name, @group}
diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml
index b4bc8982c05..b7a27ef6be2 100644
--- a/app/views/search/results/_issue.html.haml
+++ b/app/views/search/results/_issue.html.haml
@@ -10,4 +10,4 @@
.description.term
= search_md_sanitize(issue, :description)
%span.light
- #{issue.project.name_with_namespace}
+ #{issue.project.full_name}
diff --git a/app/views/search/results/_merge_request.html.haml b/app/views/search/results/_merge_request.html.haml
index 1a5499e4d58..8b0fd74f680 100644
--- a/app/views/search/results/_merge_request.html.haml
+++ b/app/views/search/results/_merge_request.html.haml
@@ -11,4 +11,4 @@
.description.term
= search_md_sanitize(merge_request, :description)
%span.light
- #{merge_request.project.name_with_namespace}
+ #{merge_request.project.full_name}
diff --git a/app/views/search/results/_note.html.haml b/app/views/search/results/_note.html.haml
index a7e178dfa71..e4ab7b0541f 100644
--- a/app/views/search/results/_note.html.haml
+++ b/app/views/search/results/_note.html.haml
@@ -7,7 +7,7 @@
%i.fa.fa-comment
= link_to_member(project, note.author, avatar: false)
commented on
- = link_to project.name_with_namespace, project
+ = link_to project.full_name, project
&middot;
- if note.for_commit?
diff --git a/app/views/search/results/_snippet_title.html.haml b/app/views/search/results/_snippet_title.html.haml
index 65710c09a89..d46c4d11e51 100644
--- a/app/views/search/results/_snippet_title.html.haml
+++ b/app/views/search/results/_snippet_title.html.haml
@@ -11,7 +11,7 @@
%small.pull-right.cgray
- if snippet_title.project_id?
- = link_to snippet_title.project.name_with_namespace, project_path(snippet_title.project)
+ = link_to snippet_title.project.full_name, project_path(snippet_title.project)
.snippet-info
= snippet_title.to_reference
diff --git a/app/views/sent_notifications/unsubscribe.html.haml b/app/views/sent_notifications/unsubscribe.html.haml
index de52fd00157..7d3e243495f 100644
--- a/app/views/sent_notifications/unsubscribe.html.haml
+++ b/app/views/sent_notifications/unsubscribe.html.haml
@@ -1,7 +1,7 @@
- noteable = @sent_notification.noteable
- noteable_type = @sent_notification.noteable_type.titleize.downcase
- noteable_text = %(#{noteable.title} (#{noteable.to_reference}))
-- page_title "Unsubscribe", noteable_text, noteable_type.pluralize, @sent_notification.project.name_with_namespace
+- page_title "Unsubscribe", noteable_text, noteable_type.pluralize, @sent_notification.project.full_name
%h3.page-title
Unsubscribe from #{noteable_type}
diff --git a/app/views/shared/_import_form.html.haml b/app/views/shared/_import_form.html.haml
index 736afa085e8..5eaaa1448d5 100644
--- a/app/views/shared/_import_form.html.haml
+++ b/app/views/shared/_import_form.html.haml
@@ -1,17 +1,22 @@
+- ci_cd_only = local_assigns.fetch(:ci_cd_only, false)
+
.form-group.import-url-data
= f.label :import_url, class: 'label-light' do
- %span Git repository URL
+ %span
+ = _('Git repository URL')
- = f.text_field :import_url, autocomplete: 'off', class: 'form-control', placeholder: 'https://username:password@gitlab.company.com/group/project.git'
+ = f.text_field :import_url, autocomplete: 'off', class: 'form-control', placeholder: 'https://username:password@gitlab.company.com/group/project.git', required: true
.well.prepend-top-20
%ul
%li
- The repository must be accessible over <code>http://</code>, <code>https://</code> or <code>git://</code>.
+ = _('The repository must be accessible over <code>http://</code>, <code>https://</code> or <code>git://</code>.').html_safe
%li
- If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>.
+ = _('If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>.').html_safe
%li
- The import will time out after #{time_interval_in_words(Gitlab.config.gitlab_shell.git_timeout)}.
- For repositories that take longer, use a clone/push combination.
+ = import_will_timeout_message(ci_cd_only)
%li
- To migrate an SVN repository, check out #{link_to "this document", help_page_path('user/project/import/svn')}.
+ = import_svn_message(ci_cd_only)
+
+-# EE-specific start
+-# EE-specific end
diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml
index 8847d11f623..5afbc78df53 100644
--- a/app/views/shared/_label.html.haml
+++ b/app/views/shared/_label.html.haml
@@ -48,8 +48,16 @@
.pull-right.hidden-xs.hidden-sm
- if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group)
- = link_to promote_project_label_path(label.project, label), title: "Promote to Group Label", class: 'btn btn-transparent btn-action', data: {confirm: "Promoting #{label.title} will make it available for all projects inside #{label.project.group.name}. Existing project labels with the same name will be merged. This action cannot be reversed.", toggle: "tooltip"}, method: :post do
- %span.sr-only Promote to Group
+ %button.js-promote-project-label-button.btn.btn-transparent.btn-action.has-tooltip{ title: _('Promote to Group Label'),
+ disabled: true,
+ type: 'button',
+ data: { url: promote_project_label_path(label.project, label),
+ label_title: label.title,
+ label_color: label.color,
+ label_text_color: label.text_color,
+ target: '#promote-label-modal',
+ container: 'body',
+ toggle: 'modal' } }
= sprite_icon('level-up')
- if can?(current_user, :admin_label, label)
= link_to edit_label_path(label), title: "Edit", class: 'btn btn-transparent btn-action', data: {toggle: "tooltip"} do
diff --git a/app/views/shared/_new_commit_form.html.haml b/app/views/shared/_new_commit_form.html.haml
index 0a4a24ae807..9221fd1e025 100644
--- a/app/views/shared/_new_commit_form.html.haml
+++ b/app/views/shared/_new_commit_form.html.haml
@@ -1,3 +1,6 @@
+- project = @project.present(current_user: current_user)
+- branch_name = selected_branch
+
= render 'shared/commit_message_container', placeholder: placeholder
- if @project.empty_repo?
@@ -7,12 +10,14 @@
.form-group.branch
= label_tag 'branch_name', _('Target Branch'), class: 'control-label'
.col-sm-10
- = text_field_tag 'branch_name', @branch_name || tree_edit_branch, required: true, class: "form-control js-branch-name ref-name"
+ = text_field_tag 'branch_name', branch_name, required: true, class: "form-control js-branch-name ref-name"
.js-create-merge-request-container
= render 'shared/new_merge_request_checkbox'
+ - elsif project.can_current_user_push_to_branch?(branch_name)
+ = hidden_field_tag 'branch_name', branch_name
- else
- = hidden_field_tag 'branch_name', @branch_name || tree_edit_branch
+ = hidden_field_tag 'branch_name', branch_name
= hidden_field_tag 'create_merge_request', 1
= hidden_field_tag 'original_branch', @ref, class: 'js-original-branch'
diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml
index 61b39afb5d4..355b3ac75ae 100644
--- a/app/views/shared/_service_settings.html.haml
+++ b/app/views/shared/_service_settings.html.haml
@@ -13,12 +13,12 @@
.col-sm-10
= form.check_box :active, disabled: disable_fields_service?(@service)
- - if @service.supported_events.present?
+ - if @service.configurable_events.present?
.form-group
= form.label :url, "Trigger", class: 'control-label'
.col-sm-10
- - @service.supported_events.each do |event|
+ - @service.configurable_events.each do |event|
%div
= form.check_box service_event_field_name(event), class: 'pull-left'
.prepend-left-20
diff --git a/app/views/shared/boards/_show.html.haml b/app/views/shared/boards/_show.html.haml
index 014b8de1dc9..44b09545a61 100644
--- a/app/views/shared/boards/_show.html.haml
+++ b/app/views/shared/boards/_show.html.haml
@@ -1,3 +1,5 @@
+- board = local_assigns.fetch(:board, nil)
+- group = local_assigns.fetch(:group, false)
- @no_breadcrumb_container = true
- @no_container = true
- @content_class = "issue-boards-content"
@@ -5,7 +7,6 @@
- page_title "Boards"
- content_for :page_specific_javascripts do
- = webpack_bundle_tag 'common_vue'
-# haml-lint:disable InlineJavaScript
%script#js-board-template{ type: "text/x-template" }= render "shared/boards/components/board"
@@ -27,7 +28,7 @@
":root-path" => "rootPath",
":board-id" => "boardId",
":key" => "_uid" }
- = render "shared/boards/components/sidebar"
+ = render "shared/boards/components/sidebar", group: group
- 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/boards/components/_board.html.haml b/app/views/shared/boards/components/_board.html.haml
index c687e66fd43..2e9ad380012 100644
--- a/app/views/shared/boards/components/_board.html.haml
+++ b/app/views/shared/boards/components/_board.html.haml
@@ -42,6 +42,7 @@
":disabled" => "disabled",
":issue-link-base" => "issueLinkBase",
":root-path" => "rootPath",
+ ":groupId" => ((current_board_parent.id if @group) || 'null'),
"ref" => "board-list" }
- if can?(current_user, :admin_list, current_board_parent)
%board-blank-state{ "v-if" => 'list.id == "blank"' }
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 6dfabd7ba4c..4c8f03f1498 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -33,6 +33,8 @@
= render 'shared/issuable/form/merge_params', issuable: issuable
+= render 'shared/issuable/form/contribution', issuable: issuable, form: form
+
- if @merge_request_to_resolve_discussions_of
.form-group
.col-sm-10.col-sm-offset-2
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index fabb17c7340..fc6f71ef60f 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -112,6 +112,7 @@
- if can?(current_user, :admin_label, board.parent)
= render partial: "shared/issuable/label_page_create"
= dropdown_loading
- #js-add-issues-btn.prepend-left-10
+ - if @project
+ #js-add-issues-btn.prepend-left-10{ data: { can_admin_list: can?(current_user, :admin_list, @project) } }
- elsif type != :boards_modal
= render 'shared/sort_dropdown'
diff --git a/app/views/shared/issuable/form/_contribution.html.haml b/app/views/shared/issuable/form/_contribution.html.haml
new file mode 100644
index 00000000000..0f2d313a5cc
--- /dev/null
+++ b/app/views/shared/issuable/form/_contribution.html.haml
@@ -0,0 +1,20 @@
+- issuable = local_assigns.fetch(:issuable)
+- form = local_assigns.fetch(:form)
+
+- return unless issuable.is_a?(MergeRequest)
+- return unless issuable.for_fork?
+- return unless can?(current_user, :push_code, issuable.source_project)
+
+%hr
+
+.form-group
+ .control-label
+ = _('Contribution')
+ .col-sm-10
+ .checkbox
+ = form.label :allow_maintainer_to_push do
+ = form.check_box :allow_maintainer_to_push, disabled: !issuable.can_allow_maintainer_to_push?(current_user)
+ = _('Allow edits from maintainers')
+ = link_to 'About this feature', help_page_path('user/project/merge_requests/maintainer_access')
+ .help-block
+ = allow_maintainer_push_unavailable_reason(issuable)
diff --git a/app/views/shared/milestones/_issuable.html.haml b/app/views/shared/milestones/_issuable.html.haml
index 129f6ab604e..eba64daaadc 100644
--- a/app/views/shared/milestones/_issuable.html.haml
+++ b/app/views/shared/milestones/_issuable.html.haml
@@ -12,7 +12,7 @@
- if show_project_name
%strong #{project.name} &middot;
- elsif show_full_project_name
- %strong #{project.name_with_namespace} &middot;
+ %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/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index e3b2b53833e..5926867e2d7 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -27,7 +27,7 @@
- milestone.milestones.each do |milestone|
= link_to milestone_path(milestone) do
%span.label.label-gray
- = dashboard ? milestone.project.name_with_namespace : milestone.project.name
+ = dashboard ? milestone.project.full_name : milestone.project.name
- if @group
.col-sm-6.milestone-actions
- if can?(current_user, :admin_milestones, @group)
@@ -51,18 +51,25 @@
\
- if @project.group
- = link_to promote_project_milestone_path(milestone.project, milestone), title: "Promote to Group Milestone", class: 'btn btn-xs btn-grouped', data: { confirm: "Promoting #{milestone.title} will make it available for all projects inside #{@project.group.name}. Existing project milestones with the same name will be merged. This action cannot be reversed.", toggle: "tooltip" }, method: :post do
- Promote
+ %button.js-promote-project-milestone-button.btn.btn-xs.btn-grouped.has-tooltip{ title: _('Promote to Group Milestone'),
+ disabled: true,
+ type: 'button',
+ data: { url: promote_project_milestone_path(milestone.project, milestone),
+ milestone_title: milestone.title,
+ target: '#promote-milestone-modal',
+ container: 'body',
+ toggle: 'modal' } }
+ = _('Promote')
= link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-xs btn-close btn-grouped"
- %button.js-delete-milestone-button.btn.btn-xs.btn-grouped.btn-danger{ data: { toggle: 'modal',
- target: '#delete-milestone-modal',
- milestone_id: milestone.id,
- milestone_title: markdown_field(milestone, :title),
- milestone_url: project_milestone_path(milestone.project, milestone),
- milestone_issue_count: milestone.issues.count,
- milestone_merge_request_count: milestone.merge_requests.count },
- disabled: true }
- = _('Delete')
- = icon('spin spinner', class: 'js-loading-icon hidden' )
+ %button.js-delete-milestone-button.btn.btn-xs.btn-grouped.btn-danger{ data: { toggle: 'modal',
+ target: '#delete-milestone-modal',
+ milestone_id: milestone.id,
+ milestone_title: markdown_field(milestone, :title),
+ milestone_url: project_milestone_path(milestone.project, milestone),
+ milestone_issue_count: milestone.issues.count,
+ milestone_merge_request_count: milestone.merge_requests.count },
+ disabled: true }
+ = _('Delete')
+ = icon('spin spinner', class: 'js-loading-icon hidden' )
diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml
index fd0760d83a5..6006ab8b43f 100644
--- a/app/views/shared/milestones/_top.html.haml
+++ b/app/views/shared/milestones/_top.html.haml
@@ -56,7 +56,7 @@
- milestone.milestones.each do |ms|
%tr
%td
- - project_name = group ? ms.project.name : ms.project.name_with_namespace
+ - project_name = group ? ms.project.name : ms.project.full_name
= link_to project_name, project_milestone_path(ms.project, ms)
%td
= ms.issues_visible_to_user(current_user).opened.count
diff --git a/app/views/shared/plugins/_index.html.haml b/app/views/shared/plugins/_index.html.haml
new file mode 100644
index 00000000000..fc643c3ecc2
--- /dev/null
+++ b/app/views/shared/plugins/_index.html.haml
@@ -0,0 +1,23 @@
+- plugins = Gitlab::Plugin.files
+
+.row.prepend-top-default
+ .col-lg-4
+ %h4.prepend-top-0
+ Plugins
+ %p
+ #{link_to 'Plugins', help_page_path('administration/plugins')} are similar to
+ system hooks but are executed as files instead of sending data to a URL.
+
+ .col-lg-8.append-bottom-default
+ - if plugins.any?
+ .panel.panel-default
+ .panel-heading
+ Plugins (#{plugins.count})
+ %ul.content-list
+ - plugins.each do |file|
+ %li
+ .monospace
+ = File.basename(file)
+ - else
+ %p.light-well.text-center
+ No plugins found.
diff --git a/app/views/shared/projects/_edit_information.html.haml b/app/views/shared/projects/_edit_information.html.haml
new file mode 100644
index 00000000000..ec9dc8f62c2
--- /dev/null
+++ b/app/views/shared/projects/_edit_information.html.haml
@@ -0,0 +1,6 @@
+- unless can?(current_user, :push_code, @project)
+ .inline.prepend-left-10
+ - if @project.branch_allows_maintainer_push?(current_user, selected_branch)
+ = commit_in_single_accessible_branch
+ - else
+ = commit_in_fork_help
diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index 491a8a41090..3acec88c2e3 100644
--- a/app/views/shared/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -31,7 +31,7 @@
%span.hidden-xs
in
= link_to project_path(snippet.project) do
- = snippet.project.name_with_namespace
+ = snippet.project.full_name
.pull-right.snippet-updated-at
%span updated #{time_ago_with_tooltip(snippet.updated_at, placement: 'bottom')}
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 328db19be29..f65e8385ac8 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -43,12 +43,11 @@
- pipeline_cache:expire_pipeline_cache
- pipeline_creation:create_pipeline
- pipeline_creation:run_pipeline_schedule
+- pipeline_background:archive_trace
- pipeline_default:build_coverage
- pipeline_default:build_trace_sections
-- pipeline_default:create_trace_artifact
- pipeline_default:pipeline_metrics
- pipeline_default:pipeline_notification
-- pipeline_default:update_head_pipeline_for_merge_request
- pipeline_hooks:build_hooks
- pipeline_hooks:pipeline_hooks
- pipeline_processing:build_finished
@@ -58,6 +57,7 @@
- pipeline_processing:pipeline_success
- pipeline_processing:pipeline_update
- pipeline_processing:stage_update
+- pipeline_processing:update_head_pipeline_for_merge_request
- repository_check:repository_check_clear
- repository_check:repository_check_single_repository
diff --git a/app/workers/archive_trace_worker.rb b/app/workers/archive_trace_worker.rb
new file mode 100644
index 00000000000..dea7425ad88
--- /dev/null
+++ b/app/workers/archive_trace_worker.rb
@@ -0,0 +1,10 @@
+class ArchiveTraceWorker
+ include ApplicationWorker
+ include PipelineBackgroundQueue
+
+ def perform(job_id)
+ Ci::Build.find_by(id: job_id).try do |job|
+ job.trace.archive!
+ end
+ end
+end
diff --git a/app/workers/build_finished_worker.rb b/app/workers/build_finished_worker.rb
index b5ed8d607b3..46f1ac09915 100644
--- a/app/workers/build_finished_worker.rb
+++ b/app/workers/build_finished_worker.rb
@@ -12,7 +12,7 @@ class BuildFinishedWorker
# We execute that async as this are two indepentent operations that can be executed after TraceSections and Coverage
BuildHooksWorker.perform_async(build.id)
- CreateTraceArtifactWorker.perform_async(build.id)
+ ArchiveTraceWorker.perform_async(build.id)
end
end
end
diff --git a/app/workers/concerns/gitlab/github_import/object_importer.rb b/app/workers/concerns/gitlab/github_import/object_importer.rb
index 9a9fbaad653..100d86e38c8 100644
--- a/app/workers/concerns/gitlab/github_import/object_importer.rb
+++ b/app/workers/concerns/gitlab/github_import/object_importer.rb
@@ -22,7 +22,7 @@ module Gitlab
importer_class.new(object, project, client).execute
- counter.increment(project: project.path_with_namespace)
+ counter.increment(project: project.full_path)
end
def counter
diff --git a/app/workers/concerns/pipeline_background_queue.rb b/app/workers/concerns/pipeline_background_queue.rb
new file mode 100644
index 00000000000..8bf43de6b26
--- /dev/null
+++ b/app/workers/concerns/pipeline_background_queue.rb
@@ -0,0 +1,10 @@
+##
+# Concern for setting Sidekiq settings for the low priority CI pipeline workers.
+#
+module PipelineBackgroundQueue
+ extend ActiveSupport::Concern
+
+ included do
+ queue_namespace :pipeline_background
+ end
+end
diff --git a/app/workers/create_trace_artifact_worker.rb b/app/workers/create_trace_artifact_worker.rb
deleted file mode 100644
index 11cda58021e..00000000000
--- a/app/workers/create_trace_artifact_worker.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class CreateTraceArtifactWorker
- include ApplicationWorker
- include PipelineQueue
-
- def perform(job_id)
- Ci::Build.preload(:project, :user).find_by(id: job_id).try do |job|
- Ci::CreateTraceArtifactService.new(job.project, job.user).execute(job)
- end
- end
-end
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 21da27973fe..2a4d65b5cb3 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -66,7 +66,7 @@ class EmailsOnPushWorker
# These are input errors and won't be corrected even if Sidekiq retries
rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
- logger.info("Failed to send e-mail for project '#{project.name_with_namespace}' to #{recipient}: #{e}")
+ logger.info("Failed to send e-mail for project '#{project.full_name}' to #{recipient}: #{e}")
end
end
ensure
diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb
index 7ba224d74c8..55fb817ca6e 100644
--- a/app/workers/git_garbage_collect_worker.rb
+++ b/app/workers/git_garbage_collect_worker.rb
@@ -44,6 +44,10 @@ class GitGarbageCollectWorker
# Refresh the branch cache in case garbage collection caused a ref lookup to fail
flush_ref_caches(project) if task == :gc
+
+ # In case pack files are deleted, release libgit2 cache and open file
+ # descriptors ASAP instead of waiting for Ruby garbage collection
+ project.cleanup
ensure
cancel_lease(lease_key, lease_uuid) if lease_key.present? && lease_uuid.present?
end
diff --git a/app/workers/gitlab/github_import/stage/finish_import_worker.rb b/app/workers/gitlab/github_import/stage/finish_import_worker.rb
index 073d6608082..a779e631516 100644
--- a/app/workers/gitlab/github_import/stage/finish_import_worker.rb
+++ b/app/workers/gitlab/github_import/stage/finish_import_worker.rb
@@ -16,7 +16,7 @@ module Gitlab
def report_import_time(project)
duration = Time.zone.now - project.created_at
- path = project.path_with_namespace
+ path = project.full_path
histogram.observe({ project: path }, duration)
counter.increment
diff --git a/app/workers/pages_worker.rb b/app/workers/pages_worker.rb
index d3b95009364..66a0ff83bef 100644
--- a/app/workers/pages_worker.rb
+++ b/app/workers/pages_worker.rb
@@ -1,7 +1,7 @@
class PagesWorker
include ApplicationWorker
- sidekiq_options retry: false
+ sidekiq_options retry: 3
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 f2b2c4428d3..3909dbf7d7f 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -55,7 +55,7 @@ class PostReceive
end
def process_wiki_changes(post_received)
- # Nothing defined here yet.
+ post_received.project.touch(:last_activity_at, :last_repository_updated_at)
end
def log(message)
diff --git a/app/workers/process_commit_worker.rb b/app/workers/process_commit_worker.rb
index 5b25d980bdb..201e7f332b4 100644
--- a/app/workers/process_commit_worker.rb
+++ b/app/workers/process_commit_worker.rb
@@ -30,10 +30,9 @@ class ProcessCommitWorker
end
def process_commit_message(project, commit, user, author, default = false)
- # this is a GitLab generated commit message, ignore it.
- return if commit.merged_merge_request?(user)
-
- closed_issues = default ? commit.closes_issues(user) : []
+ # Ignore closing references from GitLab-generated commit messages.
+ find_closing_issues = default && !commit.merged_merge_request?(user)
+ closed_issues = find_closing_issues ? commit.closes_issues(user) : []
close_issues(project, user, author, commit, closed_issues) if closed_issues.any?
commit.create_cross_references!(author, closed_issues)
diff --git a/app/workers/update_head_pipeline_for_merge_request_worker.rb b/app/workers/update_head_pipeline_for_merge_request_worker.rb
index f09d89aa170..76f84ff920f 100644
--- a/app/workers/update_head_pipeline_for_merge_request_worker.rb
+++ b/app/workers/update_head_pipeline_for_merge_request_worker.rb
@@ -2,6 +2,8 @@ class UpdateHeadPipelineForMergeRequestWorker
include ApplicationWorker
include PipelineQueue
+ queue_namespace :pipeline_processing
+
def perform(merge_request_id)
merge_request = MergeRequest.find(merge_request_id)
pipeline = Ci::Pipeline.where(project: merge_request.source_project, ref: merge_request.source_branch).last
diff --git a/changelogs/unreleased/29130-api-project-export.yml b/changelogs/unreleased/29130-api-project-export.yml
new file mode 100644
index 00000000000..7dee349232a
--- /dev/null
+++ b/changelogs/unreleased/29130-api-project-export.yml
@@ -0,0 +1,5 @@
+---
+title: Add project export API
+merge_request: 15860
+author: Travis Miller
+type: added
diff --git a/changelogs/unreleased/38587-pipelines-empty-state.yml b/changelogs/unreleased/38587-pipelines-empty-state.yml
new file mode 100644
index 00000000000..58ea204d394
--- /dev/null
+++ b/changelogs/unreleased/38587-pipelines-empty-state.yml
@@ -0,0 +1,5 @@
+---
+title: Handle empty state in Pipelines page
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/39444-make-margin-around-dropdown-dividers-4px.yml b/changelogs/unreleased/39444-make-margin-around-dropdown-dividers-4px.yml
new file mode 100644
index 00000000000..da65cfff799
--- /dev/null
+++ b/changelogs/unreleased/39444-make-margin-around-dropdown-dividers-4px.yml
@@ -0,0 +1,5 @@
+---
+title: Set margins around dropdown dividers to 4px
+merge_request: 17517
+author:
+type: fixed
diff --git a/changelogs/unreleased/40187-project-branch-dashboard-with-active-stale-branches.yml b/changelogs/unreleased/40187-project-branch-dashboard-with-active-stale-branches.yml
new file mode 100644
index 00000000000..3833aab42dd
--- /dev/null
+++ b/changelogs/unreleased/40187-project-branch-dashboard-with-active-stale-branches.yml
@@ -0,0 +1,5 @@
+---
+title: Add overview of branches and a filter for active/stale branches
+merge_request: 15402
+author: Takuya Noguchi
+type: added
diff --git a/changelogs/unreleased/40525-listing-user-activity-timeouts.yml b/changelogs/unreleased/40525-listing-user-activity-timeouts.yml
new file mode 100644
index 00000000000..39ce873dba6
--- /dev/null
+++ b/changelogs/unreleased/40525-listing-user-activity-timeouts.yml
@@ -0,0 +1,5 @@
+---
+title: Improve database response time for user activity listing.
+merge_request: 17454
+author:
+type: performance
diff --git a/changelogs/unreleased/41719-mr-title-fix.yml b/changelogs/unreleased/41719-mr-title-fix.yml
new file mode 100644
index 00000000000..92388f30cb2
--- /dev/null
+++ b/changelogs/unreleased/41719-mr-title-fix.yml
@@ -0,0 +1,5 @@
+---
+title: Render htmlentities correctly for links not supported by Rinku
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/42921-ci-charts-include-current-day.yml b/changelogs/unreleased/42921-ci-charts-include-current-day.yml
new file mode 100644
index 00000000000..d0de6665735
--- /dev/null
+++ b/changelogs/unreleased/42921-ci-charts-include-current-day.yml
@@ -0,0 +1,5 @@
+---
+title: CI charts now include the current day
+merge_request: 17032
+author: Dakkaron
+type: changed
diff --git a/changelogs/unreleased/43261-fix-prometheus-installation.yml b/changelogs/unreleased/43261-fix-prometheus-installation.yml
deleted file mode 100644
index b5fc7980390..00000000000
--- a/changelogs/unreleased/43261-fix-prometheus-installation.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow Prometheus application to be installed from Cluster applications
-merge_request: 17372
-author:
-type: fixed
diff --git a/changelogs/unreleased/43460-track-projects-a-user-interacted-with.yml b/changelogs/unreleased/43460-track-projects-a-user-interacted-with.yml
new file mode 100644
index 00000000000..99b6ac76a3e
--- /dev/null
+++ b/changelogs/unreleased/43460-track-projects-a-user-interacted-with.yml
@@ -0,0 +1,5 @@
+---
+title: Keep track of projects a user interacted with.
+merge_request: 17327
+author:
+type: other
diff --git a/changelogs/unreleased/43510-merge-requests-and-issues-don-t-show-for-all-subgroups.yml b/changelogs/unreleased/43510-merge-requests-and-issues-don-t-show-for-all-subgroups.yml
deleted file mode 100644
index e163c04f430..00000000000
--- a/changelogs/unreleased/43510-merge-requests-and-issues-don-t-show-for-all-subgroups.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Ensure group issues and merge requests pages show results from subgroups when
- there are no results from the current group
-merge_request: 17312
-author:
-type: fixed
diff --git a/changelogs/unreleased/43531-500-error-searching-wiki-incompatible-character-encodings-utf-8-and-ascii-8bit.yml b/changelogs/unreleased/43531-500-error-searching-wiki-incompatible-character-encodings-utf-8-and-ascii-8bit.yml
deleted file mode 100644
index 173710412a5..00000000000
--- a/changelogs/unreleased/43531-500-error-searching-wiki-incompatible-character-encodings-utf-8-and-ascii-8bit.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix code and wiki search results pages when non-ASCII text is displayed
-merge_request: 17413
-author:
-type: fixed
diff --git a/changelogs/unreleased/43532-error-on-admin-applications-prometheus-template.yml b/changelogs/unreleased/43532-error-on-admin-applications-prometheus-template.yml
deleted file mode 100644
index 25bcbf2fbab..00000000000
--- a/changelogs/unreleased/43532-error-on-admin-applications-prometheus-template.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixes Prometheus admin configuration page
-merge_request: 17377
-author:
-type: fixed
diff --git a/changelogs/unreleased/43780-add-a-paragraph-about-clusters-security-implications.yml b/changelogs/unreleased/43780-add-a-paragraph-about-clusters-security-implications.yml
new file mode 100644
index 00000000000..0fa21a2013c
--- /dev/null
+++ b/changelogs/unreleased/43780-add-a-paragraph-about-clusters-security-implications.yml
@@ -0,0 +1,5 @@
+---
+title: Add a paragraph about security implications on Cluster's page
+merge_request: 17486
+author:
+type: added
diff --git a/changelogs/unreleased/43793-enable-privileged-mode-for-runner.yml b/changelogs/unreleased/43793-enable-privileged-mode-for-runner.yml
new file mode 100644
index 00000000000..08109632e8e
--- /dev/null
+++ b/changelogs/unreleased/43793-enable-privileged-mode-for-runner.yml
@@ -0,0 +1,5 @@
+---
+title: Enable privileged mode for GitLab Runner
+merge_request: 17528
+author:
+type: added
diff --git a/changelogs/unreleased/43802-ensure-foreign-keys-on-clusters-applications.yml b/changelogs/unreleased/43802-ensure-foreign-keys-on-clusters-applications.yml
new file mode 100644
index 00000000000..860a8becd65
--- /dev/null
+++ b/changelogs/unreleased/43802-ensure-foreign-keys-on-clusters-applications.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure foreign keys on clusters applications
+merge_request: 17488
+author:
+type: other
diff --git a/changelogs/unreleased/43829-update-ssh-addtion-text.yml b/changelogs/unreleased/43829-update-ssh-addtion-text.yml
new file mode 100644
index 00000000000..b7052bb171e
--- /dev/null
+++ b/changelogs/unreleased/43829-update-ssh-addtion-text.yml
@@ -0,0 +1,5 @@
+---
+title: Update SSH key link to include existing keys
+merge_request:
+author: Brendan O'Leary
+type: changed
diff --git a/changelogs/unreleased/43837-error-handle-in-updating-milestone-on-issue.yml b/changelogs/unreleased/43837-error-handle-in-updating-milestone-on-issue.yml
new file mode 100644
index 00000000000..526523964c3
--- /dev/null
+++ b/changelogs/unreleased/43837-error-handle-in-updating-milestone-on-issue.yml
@@ -0,0 +1,5 @@
+---
+title: Stop loading spinner on error of milestone update on issue
+merge_request: 17507
+author: Takuya Noguchi
+type: fixed
diff --git a/changelogs/unreleased/43924-breadcrumbs-on-project-tags.yml b/changelogs/unreleased/43924-breadcrumbs-on-project-tags.yml
new file mode 100644
index 00000000000..67c223b31c5
--- /dev/null
+++ b/changelogs/unreleased/43924-breadcrumbs-on-project-tags.yml
@@ -0,0 +1,5 @@
+---
+title: Remove extra breadcrumb on tags
+merge_request: 17562
+author: Takuya Noguchi
+type: fixed
diff --git a/changelogs/unreleased/43949-verify-job-artifacts.yml b/changelogs/unreleased/43949-verify-job-artifacts.yml
new file mode 100644
index 00000000000..45e1916ae17
--- /dev/null
+++ b/changelogs/unreleased/43949-verify-job-artifacts.yml
@@ -0,0 +1,5 @@
+---
+title: Implement foreground verification of CI artifacts
+merge_request: 17578
+author:
+type: added
diff --git a/changelogs/unreleased/an-network-controller-fix.yml b/changelogs/unreleased/an-network-controller-fix.yml
new file mode 100644
index 00000000000..cb2c447b957
--- /dev/null
+++ b/changelogs/unreleased/an-network-controller-fix.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent the graphs page from generating unnecessary Gitaly requests
+merge_request: 37602
+author:
+type: performance
diff --git a/changelogs/unreleased/bvl-allow-maintainer-to-push.yml b/changelogs/unreleased/bvl-allow-maintainer-to-push.yml
new file mode 100644
index 00000000000..a3fefc2889a
--- /dev/null
+++ b/changelogs/unreleased/bvl-allow-maintainer-to-push.yml
@@ -0,0 +1,5 @@
+---
+title: Allow maintainers to push to forks of their projects when a merge request is open
+merge_request: 17395
+author:
+type: added
diff --git a/changelogs/unreleased/bvl-port-of-ee-translations.yml b/changelogs/unreleased/bvl-port-of-ee-translations.yml
new file mode 100644
index 00000000000..8f232ec8da3
--- /dev/null
+++ b/changelogs/unreleased/bvl-port-of-ee-translations.yml
@@ -0,0 +1,5 @@
+---
+title: Started translation into Turkish, Indonesian and Filipino
+merge_request: 17526
+author:
+type: other
diff --git a/changelogs/unreleased/cache-refactor.yml b/changelogs/unreleased/cache-refactor.yml
new file mode 100644
index 00000000000..dec7a0392a5
--- /dev/null
+++ b/changelogs/unreleased/cache-refactor.yml
@@ -0,0 +1,5 @@
+---
+title: Cache MergeRequests can_be_resolved_in_ui? git operations
+merge_request: 17589
+author:
+type: performance
diff --git a/changelogs/unreleased/ce-jej-github-project-service-for-ci.yml b/changelogs/unreleased/ce-jej-github-project-service-for-ci.yml
new file mode 100644
index 00000000000..6102b7ecd93
--- /dev/null
+++ b/changelogs/unreleased/ce-jej-github-project-service-for-ci.yml
@@ -0,0 +1,5 @@
+---
+title: Hook data for pipelines includes detailed_status
+merge_request: 17607
+author:
+type: changed
diff --git a/changelogs/unreleased/ce-jej-integrations-can-hide-trigger-checkboxes.yml b/changelogs/unreleased/ce-jej-integrations-can-hide-trigger-checkboxes.yml
new file mode 100644
index 00000000000..771df06e7a6
--- /dev/null
+++ b/changelogs/unreleased/ce-jej-integrations-can-hide-trigger-checkboxes.yml
@@ -0,0 +1,6 @@
+---
+title: Avoid showing unnecessary Trigger checkboxes for project Integrations with
+ only one event
+merge_request: 17607
+author:
+type: changed
diff --git a/changelogs/unreleased/discussions-api.yml b/changelogs/unreleased/discussions-api.yml
new file mode 100644
index 00000000000..110df3aa414
--- /dev/null
+++ b/changelogs/unreleased/discussions-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add discussions API for Issues and Snippets
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/dz-plugins-project-integrations.yml b/changelogs/unreleased/dz-plugins-project-integrations.yml
new file mode 100644
index 00000000000..9dbe82f9af8
--- /dev/null
+++ b/changelogs/unreleased/dz-plugins-project-integrations.yml
@@ -0,0 +1,5 @@
+---
+title: Add plugins list to the system hooks page
+merge_request: 17518
+author:
+type: added
diff --git a/changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml b/changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml
new file mode 100644
index 00000000000..d8020592897
--- /dev/null
+++ b/changelogs/unreleased/feature--43691-count-diff-note-calendar-activity.yml
@@ -0,0 +1,5 @@
+---
+title: Count comments on diffs and discussions as contributions for the contributions calendar
+merge_request: 17418
+author: Riccardo Padovani
+type: fixed
diff --git a/changelogs/unreleased/feature-sm-add-check-sum-to-job-artifacts.yml b/changelogs/unreleased/feature-sm-add-check-sum-to-job-artifacts.yml
new file mode 100644
index 00000000000..23a870d6e9f
--- /dev/null
+++ b/changelogs/unreleased/feature-sm-add-check-sum-to-job-artifacts.yml
@@ -0,0 +1,5 @@
+---
+title: Store sha256 checksum to job artifacts
+merge_request: 17354
+author:
+type: performance
diff --git a/changelogs/unreleased/fix-mattermost-delete-team.yml b/changelogs/unreleased/fix-mattermost-delete-team.yml
new file mode 100644
index 00000000000..d14ae023114
--- /dev/null
+++ b/changelogs/unreleased/fix-mattermost-delete-team.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed group deletion linked to Mattermost
+merge_request: 16209
+author: Julien Millau
+type: fixed
diff --git a/changelogs/unreleased/fj-41174-projects-groups-badges-api.yml b/changelogs/unreleased/fj-41174-projects-groups-badges-api.yml
new file mode 100644
index 00000000000..7cb12e26332
--- /dev/null
+++ b/changelogs/unreleased/fj-41174-projects-groups-badges-api.yml
@@ -0,0 +1,5 @@
+---
+title: Implemented badge API endpoints
+merge_request: 17082
+author:
+type: added
diff --git a/changelogs/unreleased/grpc-unavailable-restart.yml b/changelogs/unreleased/grpc-unavailable-restart.yml
deleted file mode 100644
index 5ce08d66004..00000000000
--- a/changelogs/unreleased/grpc-unavailable-restart.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Restart Unicorn and Sidekiq when GRPC throws 14:Endpoint read failed
-merge_request: 17293
-author:
-type: fixed
diff --git a/changelogs/unreleased/issue-edit-shortcut.yml b/changelogs/unreleased/issue-edit-shortcut.yml
deleted file mode 100644
index 2b29b2bc03f..00000000000
--- a/changelogs/unreleased/issue-edit-shortcut.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed issue edit shortcut not opening edit form
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/issue_31081.yml b/changelogs/unreleased/issue_31081.yml
new file mode 100644
index 00000000000..ac547c285db
--- /dev/null
+++ b/changelogs/unreleased/issue_31081.yml
@@ -0,0 +1,5 @@
+---
+title: Use host URL to build JIRA remote link icon
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/issue_38337.yml b/changelogs/unreleased/issue_38337.yml
new file mode 100644
index 00000000000..df65118b65c
--- /dev/null
+++ b/changelogs/unreleased/issue_38337.yml
@@ -0,0 +1,5 @@
+---
+title: Add one group board to Libre
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/jivl-new-modal-project-labels-milestones.yml b/changelogs/unreleased/jivl-new-modal-project-labels-milestones.yml
new file mode 100644
index 00000000000..6b7e14c6cfc
--- /dev/null
+++ b/changelogs/unreleased/jivl-new-modal-project-labels-milestones.yml
@@ -0,0 +1,5 @@
+---
+title: Added new design for promotion modals
+merge_request: 17197
+author:
+type: other
diff --git a/changelogs/unreleased/kp-label-select-vue.yml b/changelogs/unreleased/kp-label-select-vue.yml
new file mode 100644
index 00000000000..1f5952f2554
--- /dev/null
+++ b/changelogs/unreleased/kp-label-select-vue.yml
@@ -0,0 +1,5 @@
+---
+title: Port Labels Select dropdown to Vue
+merge_request: 17411
+author:
+type: other
diff --git a/changelogs/unreleased/merge-request-widget-source-branch-improvements.yml b/changelogs/unreleased/merge-request-widget-source-branch-improvements.yml
new file mode 100644
index 00000000000..942eb6062fd
--- /dev/null
+++ b/changelogs/unreleased/merge-request-widget-source-branch-improvements.yml
@@ -0,0 +1,6 @@
+---
+title: Fixes remove source branch checkbox being visible when user cannot remove the
+ branch
+merge_request:
+author:
+type: changed
diff --git a/changelogs/unreleased/minimal-fix-for-artifacts-service.yml b/changelogs/unreleased/minimal-fix-for-artifacts-service.yml
deleted file mode 100644
index 11f5bc17759..00000000000
--- a/changelogs/unreleased/minimal-fix-for-artifacts-service.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Prevent trace artifact migration to incur data loss
-merge_request: 17313
-author:
-type: fixed
diff --git a/changelogs/unreleased/mk-fix-error-code-for-repo-does-not-exist.yml b/changelogs/unreleased/mk-fix-error-code-for-repo-does-not-exist.yml
deleted file mode 100644
index a761d610da1..00000000000
--- a/changelogs/unreleased/mk-fix-error-code-for-repo-does-not-exist.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Return a 404 instead of 403 if the repository does not exist on disk
-merge_request: 17341
-author:
-type: fixed
diff --git a/changelogs/unreleased/mr-commit-optimization.yml b/changelogs/unreleased/mr-commit-optimization.yml
new file mode 100644
index 00000000000..522d8951b18
--- /dev/null
+++ b/changelogs/unreleased/mr-commit-optimization.yml
@@ -0,0 +1,5 @@
+---
+title: Use persisted/memoized value for MRs shas instead of doing git lookups
+merge_request: 17555
+author:
+type: performance
diff --git a/changelogs/unreleased/oauth_generic_provider.yml b/changelogs/unreleased/oauth_generic_provider.yml
new file mode 100644
index 00000000000..3b6f8b04529
--- /dev/null
+++ b/changelogs/unreleased/oauth_generic_provider.yml
@@ -0,0 +1,4 @@
+---
+title: Make oauth provider login generic
+merge_request: 8809
+author: Horatiu Eugen Vlad \ No newline at end of file
diff --git a/changelogs/unreleased/proper-fix-for-artifacts-service.yml b/changelogs/unreleased/proper-fix-for-artifacts-service.yml
new file mode 100644
index 00000000000..e92e995dbf5
--- /dev/null
+++ b/changelogs/unreleased/proper-fix-for-artifacts-service.yml
@@ -0,0 +1,5 @@
+---
+title: Add archive feature to trace
+merge_request: 17314
+author:
+type: added
diff --git a/changelogs/unreleased/refactor-move-mr-widget-memory-usage-and-graph-components.yml b/changelogs/unreleased/refactor-move-mr-widget-memory-usage-and-graph-components.yml
new file mode 100644
index 00000000000..96e63343963
--- /dev/null
+++ b/changelogs/unreleased/refactor-move-mr-widget-memory-usage-and-graph-components.yml
@@ -0,0 +1,5 @@
+---
+title: Move MemoryGraph and MemoryUsage vue components
+merge_request: 17533
+author: George Tsiolis
+type: performance
diff --git a/changelogs/unreleased/refactor-move-sidebar-assignee-vue-component.yml b/changelogs/unreleased/refactor-move-sidebar-assignee-vue-component.yml
new file mode 100644
index 00000000000..e77b651363e
--- /dev/null
+++ b/changelogs/unreleased/refactor-move-sidebar-assignee-vue-component.yml
@@ -0,0 +1,5 @@
+---
+title: Move SidebarAssignees vue component
+merge_request: 17398
+author: George Tsiolis
+type: performance
diff --git a/changelogs/unreleased/remove-projects-finder-from-todos-finder.yml b/changelogs/unreleased/remove-projects-finder-from-todos-finder.yml
deleted file mode 100644
index 0a3fc751edb..00000000000
--- a/changelogs/unreleased/remove-projects-finder-from-todos-finder.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Don't use ProjectsFinder in TodosFinder
-merge_request:
-author:
-type: performance
diff --git a/changelogs/unreleased/replace_redcarpet_with_cmark.yml b/changelogs/unreleased/replace_redcarpet_with_cmark.yml
new file mode 100644
index 00000000000..7ce848b0bbd
--- /dev/null
+++ b/changelogs/unreleased/replace_redcarpet_with_cmark.yml
@@ -0,0 +1,5 @@
+---
+title: Add CommonMark markdown engine (experimental)
+merge_request: 14835
+author: blackst0ne
+type: added
diff --git a/changelogs/unreleased/revert-project-visibility-changes.yml b/changelogs/unreleased/revert-project-visibility-changes.yml
deleted file mode 100644
index df44fdb79b1..00000000000
--- a/changelogs/unreleased/revert-project-visibility-changes.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Revert Project.public_or_visible_to_user changes and only apply to snippets
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-add-missing-acts-as-taggable-indices.yml b/changelogs/unreleased/sh-add-missing-acts-as-taggable-indices.yml
new file mode 100644
index 00000000000..d9a1a0db9e8
--- /dev/null
+++ b/changelogs/unreleased/sh-add-missing-acts-as-taggable-indices.yml
@@ -0,0 +1,5 @@
+---
+title: Adding missing indexes on taggings table
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-add-section-name-index.yml b/changelogs/unreleased/sh-add-section-name-index.yml
new file mode 100644
index 00000000000..c822b4e851b
--- /dev/null
+++ b/changelogs/unreleased/sh-add-section-name-index.yml
@@ -0,0 +1,5 @@
+---
+title: Add index on section_name_id on ci_build_trace_sections table
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-cleanup-after-git-gc.yml b/changelogs/unreleased/sh-cleanup-after-git-gc.yml
new file mode 100644
index 00000000000..4b652f4d6ce
--- /dev/null
+++ b/changelogs/unreleased/sh-cleanup-after-git-gc.yml
@@ -0,0 +1,5 @@
+---
+title: Release libgit2 cache and open file descriptors after `git gc` run
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-dashboard-sort-fix.yml b/changelogs/unreleased/sh-dashboard-sort-fix.yml
new file mode 100644
index 00000000000..6fd252f6707
--- /dev/null
+++ b/changelogs/unreleased/sh-dashboard-sort-fix.yml
@@ -0,0 +1,5 @@
+---
+title: Fix project dashboard showing the wrong timestamps
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-43871-system-hooks.yml b/changelogs/unreleased/sh-fix-issue-43871-system-hooks.yml
new file mode 100644
index 00000000000..7c7ef39cb75
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-43871-system-hooks.yml
@@ -0,0 +1,5 @@
+---
+title: Don't error out in system hook if user has `nil` datetime columns
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-otp-backup-code-invalidation.yml b/changelogs/unreleased/sh-fix-otp-backup-code-invalidation.yml
new file mode 100644
index 00000000000..cedb09c9a7a
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-otp-backup-code-invalidation.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure that OTP backup codes are always invalidated
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/sh-make-prune-optional-in-git-fetch.yml b/changelogs/unreleased/sh-make-prune-optional-in-git-fetch.yml
new file mode 100644
index 00000000000..e961a23a031
--- /dev/null
+++ b/changelogs/unreleased/sh-make-prune-optional-in-git-fetch.yml
@@ -0,0 +1,5 @@
+---
+title: Make --prune a configurable parameter in fetching a git remote
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-remove-double-caching-repo-empty.yml b/changelogs/unreleased/sh-remove-double-caching-repo-empty.yml
new file mode 100644
index 00000000000..1684be4e5e3
--- /dev/null
+++ b/changelogs/unreleased/sh-remove-double-caching-repo-empty.yml
@@ -0,0 +1,5 @@
+---
+title: Remove double caching of Repository#empty?
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/unassign-when-leaving.yml b/changelogs/unreleased/unassign-when-leaving.yml
new file mode 100644
index 00000000000..c00a87b1749
--- /dev/null
+++ b/changelogs/unreleased/unassign-when-leaving.yml
@@ -0,0 +1,5 @@
+---
+title: Don't delete todos or unassign issues and MRs when a user leaves a project
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/upgrade-workhorse-4-0-0.yml b/changelogs/unreleased/upgrade-workhorse-4-0-0.yml
new file mode 100644
index 00000000000..f9dbdc7fc56
--- /dev/null
+++ b/changelogs/unreleased/upgrade-workhorse-4-0-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade GitLab Workhorse to 4.0.0
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/wip-new-mr-cmd.yml b/changelogs/unreleased/wip-new-mr-cmd.yml
new file mode 100644
index 00000000000..e930758ec9d
--- /dev/null
+++ b/changelogs/unreleased/wip-new-mr-cmd.yml
@@ -0,0 +1,5 @@
+---
+title: Port /wip quick action command to Merge Request creation (on description)
+merge_request: 17463
+author: Adam Pahlevi
+type: added
diff --git a/changelogs/unreleased/zj-gitaly-encoding-issue.yml b/changelogs/unreleased/zj-gitaly-encoding-issue.yml
deleted file mode 100644
index 073d8f38e4b..00000000000
--- a/changelogs/unreleased/zj-gitaly-encoding-issue.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Encode branch name as binary before creating a RPC request to copy attributes
-merge_request: 17291
-author:
-type: fixed
diff --git a/changelogs/unreleased/zj-move-opt-out-ruby-endpoints.yml b/changelogs/unreleased/zj-move-opt-out-ruby-endpoints.yml
new file mode 100644
index 00000000000..0ddb42bc80a
--- /dev/null
+++ b/changelogs/unreleased/zj-move-opt-out-ruby-endpoints.yml
@@ -0,0 +1,5 @@
+---
+title: Move Ruby endpoints to OPT_OUT
+merge_request:
+author:
+type: other
diff --git a/config.ru b/config.ru
index de0400f4f67..7b15939c6ff 100644
--- a/config.ru
+++ b/config.ru
@@ -23,5 +23,6 @@ warmup do |app|
end
map ENV['RAILS_RELATIVE_URL_ROOT'] || "/" do
+ use Gitlab::Middleware::ReleaseEnv
run Gitlab::Application
end
diff --git a/config/application.rb b/config/application.rb
index 918bd4d57cf..ac6e4be4282 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -26,6 +26,7 @@ module Gitlab
# This is a nice reference article on autoloading/eager loading:
# http://blog.arkency.com/2014/11/dont-forget-about-eager-load-when-extending-autoload
config.eager_load_paths.push(*%W[#{config.root}/lib
+ #{config.root}/app/models/badges
#{config.root}/app/models/hooks
#{config.root}/app/models/members
#{config.root}/app/models/project_services
@@ -193,4 +194,10 @@ module Gitlab
Gitlab::Routing.add_helpers(MilestonesRoutingHelper)
end
end
+
+ # This method is used for smooth upgrading from the current Rails 4.x to Rails 5.0.
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/14286
+ def self.rails5?
+ ENV["RAILS5"].in?(%w[1 true])
+ end
end
diff --git a/config/initializers/8_metrics.rb b/config/initializers/8_metrics.rb
index 45b39b2a38d..7cdf49159b4 100644
--- a/config/initializers/8_metrics.rb
+++ b/config/initializers/8_metrics.rb
@@ -94,6 +94,7 @@ def instrument_classes(instrumentation)
instrumentation.instrument_instance_methods(RepositoryCheck::SingleRepositoryWorker)
+ instrumentation.instrument_instance_methods(Rouge::Plugins::CommonMark)
instrumentation.instrument_instance_methods(Rouge::Plugins::Redcarpet)
instrumentation.instrument_instance_methods(Rouge::Formatters::HTMLGitlab)
diff --git a/config/initializers/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb
index cb611aa21df..4cf1d455eb4 100644
--- a/config/initializers/forbid_sidekiq_in_transactions.rb
+++ b/config/initializers/forbid_sidekiq_in_transactions.rb
@@ -18,13 +18,26 @@ module Sidekiq
%i(perform_async perform_at perform_in).each do |name|
define_method(name) do |*args|
if !Sidekiq::Worker.skip_transaction_check && AfterCommitQueue.inside_transaction?
- raise Sidekiq::Worker::EnqueueFromTransactionError, <<~MSG
+ begin
+ raise Sidekiq::Worker::EnqueueFromTransactionError, <<~MSG
`#{self}.#{name}` cannot be called inside a transaction as this can lead to
race conditions when the worker runs before the transaction is committed and
tries to access a model that has not been saved yet.
Use an `after_commit` hook, or include `AfterCommitQueue` and use a `run_after_commit` block instead.
- MSG
+ MSG
+ rescue Sidekiq::Worker::EnqueueFromTransactionError => e
+ if Rails.env.production?
+ Rails.logger.error(e.message)
+
+ if Gitlab::Sentry.enabled?
+ Gitlab::Sentry.context
+ Raven.capture_exception(e)
+ end
+ else
+ raise
+ end
+ end
end
super(*args)
diff --git a/config/prometheus/additional_metrics.yml b/config/prometheus/additional_metrics.yml
index 601a86490d4..c4f60eb2687 100644
--- a/config/prometheus/additional_metrics.yml
+++ b/config/prometheus/additional_metrics.yml
@@ -140,20 +140,20 @@
priority: 5
metrics:
- title: "Memory Usage"
- y_label: "Memory Usage (MB)"
+ y_label: "Memory Used per Pod"
required_metrics:
- container_memory_usage_bytes
weight: 1
queries:
- - query_range: '(sum(avg(container_memory_usage_bytes{container_name!="POD",environment="%{ci_environment_slug}"}) without (job))) / count(avg(container_memory_usage_bytes{container_name!="POD",environment="%{ci_environment_slug}"}) without (job)) /1024/1024'
+ - query_range: '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'
label: Average
unit: MB
- - title: "CPU Utilization"
- y_label: "CPU Utilization (%)"
+ - title: "CPU Usage"
+ y_label: "Cores per Pod"
required_metrics:
- container_cpu_usage_seconds_total
weight: 1
queries:
- - query_range: 'sum(avg(rate(container_cpu_usage_seconds_total{container_name!="POD",environment="%{ci_environment_slug}"}[2m])) without (job)) * 100'
+ - query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))'
label: Average
- unit: "%" \ No newline at end of file
+ unit: "cores" \ No newline at end of file
diff --git a/config/routes/git_http.rb b/config/routes/git_http.rb
index ff51823897d..ec5c68f81df 100644
--- a/config/routes/git_http.rb
+++ b/config/routes/git_http.rb
@@ -40,7 +40,7 @@ scope(path: '*namespace_id/:project_id',
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake = lambda do |request|
- ProjectUrlConstrainer.new.matches?(request) &&
+ ::Constraints::ProjectUrlConstrainer.new.matches?(request) &&
(request.query_string.blank? ||
request.query_string.match(/\Aservice=git-(upload|receive)-pack\z/))
end
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 7a4740a4df7..d89a714c7d6 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -1,10 +1,8 @@
-require 'constraints/group_url_constrainer'
-
resources :groups, only: [:index, :new, :create] do
post :preview_markdown
end
-constraints(GroupUrlConstrainer.new) do
+constraints(::Constraints::GroupUrlConstrainer.new) do
scope(path: 'groups/*id',
controller: :groups,
constraints: { id: Gitlab::PathRegex.full_namespace_route_regex, format: /(html|json|atom)/ }) do
@@ -56,6 +54,9 @@ constraints(GroupUrlConstrainer.new) do
get ":secret/:filename", action: :show, as: :show, constraints: { filename: %r{[^/]+} }
end
end
+
+ # On CE only index and show actions are needed
+ resources :boards, only: [:index, :show]
end
scope(path: '*id',
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 34636285c51..b82ed27664c 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -1,10 +1,8 @@
-require 'constraints/project_url_constrainer'
-
resources :projects, only: [:index, :new, :create]
draw :git_http
-constraints(ProjectUrlConstrainer.new) do
+constraints(::Constraints::ProjectUrlConstrainer.new) do
# If the route has a wildcard segment, the segment has a regex constraint,
# the segment is potentially followed by _another_ wildcard segment, and
# the `format` option is not set to false, we need to specify that
@@ -69,7 +67,7 @@ constraints(ProjectUrlConstrainer.new) do
end
end
- resources :services, constraints: { id: %r{[^/]+} }, only: [:index, :edit, :update] do
+ resources :services, constraints: { id: %r{[^/]+} }, only: [:edit, :update] do
member do
put :test
end
@@ -381,7 +379,8 @@ constraints(ProjectUrlConstrainer.new) do
get 'noteable/:target_type/:target_id/notes' => 'notes#index', as: 'noteable_notes'
- resources :boards, only: [:index, :show, :create, :update, :destroy]
+ # On CE only index and show are needed
+ resources :boards, only: [:index, :show]
resources :todos, only: [:create]
diff --git a/config/routes/repository.rb b/config/routes/repository.rb
index 9ffdebbcff1..eace3a615b4 100644
--- a/config/routes/repository.rb
+++ b/config/routes/repository.rb
@@ -49,6 +49,7 @@ scope format: false do
end
end
+ get '/branches/:state', to: 'branches#index', as: :branches_filtered, constraints: { state: /active|stale|all/ }
resources :branches, only: [:index, :new, :create, :destroy]
delete :merged_branches, controller: 'branches', action: :destroy_all_merged
resources :tags, only: [:index, :show, :new, :create, :destroy] do
diff --git a/config/routes/user.rb b/config/routes/user.rb
index 733a3f6ce9a..57fb37530bb 100644
--- a/config/routes/user.rb
+++ b/config/routes/user.rb
@@ -1,5 +1,3 @@
-require 'constraints/user_url_constrainer'
-
devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks,
registrations: :registrations,
passwords: :passwords,
@@ -35,7 +33,7 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
get '/u/:username/contributed', to: redirect('users/%{username}/contributed')
end
-constraints(UserUrlConstrainer.new) do
+constraints(::Constraints::UserUrlConstrainer.new) do
# Get all keys of user
get ':username.keys' => 'profiles/keys#get_keys', constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 4845dc28a4a..554502c5d83 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -69,3 +69,4 @@
- [storage_migrator, 1]
- [pages_domain_verification, 1]
- [plugin, 1]
+ - [pipeline_background, 1]
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 19eeb497a14..3403c0c207d 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -44,8 +44,6 @@ function generateEntries() {
const manualEntries = {
common: './commons/index.js',
- common_vue: './vue_shared/vue_resource_interceptor.js',
- locale: './locale/index.js',
main: './main.js',
raven: './raven/index.js',
webpack_runtime: './webpack.js',
diff --git a/db/migrate/20180214093516_create_badges.rb b/db/migrate/20180214093516_create_badges.rb
new file mode 100644
index 00000000000..6559f834484
--- /dev/null
+++ b/db/migrate/20180214093516_create_badges.rb
@@ -0,0 +1,17 @@
+class CreateBadges < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :badges do |t|
+ t.string :link_url, null: false
+ t.string :image_url, null: false
+ t.references :project, index: true, foreign_key: { on_delete: :cascade }, null: true
+ t.integer :group_id, index: true, null: true
+ t.string :type, null: false
+
+ t.timestamps_with_timezone null: false
+ end
+
+ add_foreign_key :badges, :namespaces, column: :group_id, on_delete: :cascade
+ end
+end
diff --git a/db/migrate/20180221151752_add_allow_maintainer_to_push_to_merge_requests.rb b/db/migrate/20180221151752_add_allow_maintainer_to_push_to_merge_requests.rb
new file mode 100644
index 00000000000..81acfbc3655
--- /dev/null
+++ b/db/migrate/20180221151752_add_allow_maintainer_to_push_to_merge_requests.rb
@@ -0,0 +1,18 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddAllowMaintainerToPushToMergeRequests < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column :merge_requests, :allow_maintainer_to_push, :boolean
+ end
+
+ def down
+ remove_column :merge_requests, :allow_maintainer_to_push
+ end
+end
diff --git a/db/migrate/20180223120443_create_user_interacted_projects_table.rb b/db/migrate/20180223120443_create_user_interacted_projects_table.rb
new file mode 100644
index 00000000000..20749940b1e
--- /dev/null
+++ b/db/migrate/20180223120443_create_user_interacted_projects_table.rb
@@ -0,0 +1,18 @@
+class CreateUserInteractedProjectsTable < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :user_interacted_projects, id: false do |t|
+ t.references :user, null: false
+ t.references :project, null: false
+ end
+ end
+
+ def down
+ drop_table :user_interacted_projects
+ end
+end
diff --git a/db/migrate/20180226050030_add_checksum_to_ci_job_artifacts.rb b/db/migrate/20180226050030_add_checksum_to_ci_job_artifacts.rb
new file mode 100644
index 00000000000..54e6e35449e
--- /dev/null
+++ b/db/migrate/20180226050030_add_checksum_to_ci_job_artifacts.rb
@@ -0,0 +1,7 @@
+class AddChecksumToCiJobArtifacts < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column :ci_job_artifacts, :file_sha256, :binary
+ end
+end
diff --git a/db/migrate/20180227182112_add_group_id_to_boards_ce.rb b/db/migrate/20180227182112_add_group_id_to_boards_ce.rb
new file mode 100644
index 00000000000..f54dd8d7687
--- /dev/null
+++ b/db/migrate/20180227182112_add_group_id_to_boards_ce.rb
@@ -0,0 +1,34 @@
+class AddGroupIdToBoardsCe < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ DOWNTIME = false
+
+ def up
+ return if group_id_exists?
+
+ add_column :boards, :group_id, :integer
+ add_foreign_key :boards, :namespaces, column: :group_id, on_delete: :cascade
+ add_concurrent_index :boards, :group_id
+
+ change_column_null :boards, :project_id, true
+ end
+
+ def down
+ return unless group_id_exists?
+
+ remove_foreign_key :boards, column: :group_id
+ remove_index :boards, :group_id if index_exists? :boards, :group_id
+ remove_column :boards, :group_id
+
+ execute "DELETE from boards WHERE project_id IS NULL"
+ change_column_null :boards, :project_id, false
+ end
+
+ private
+
+ def group_id_exists?
+ column_exists?(:boards, :group_id)
+ end
+end
diff --git a/db/migrate/20180302152117_ensure_foreign_keys_on_clusters_applications.rb b/db/migrate/20180302152117_ensure_foreign_keys_on_clusters_applications.rb
new file mode 100644
index 00000000000..8298979e96a
--- /dev/null
+++ b/db/migrate/20180302152117_ensure_foreign_keys_on_clusters_applications.rb
@@ -0,0 +1,50 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class EnsureForeignKeysOnClustersApplications < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ existing = Clusters::Cluster
+ .joins(:application_ingress)
+ .where('clusters.id = clusters_applications_ingress.cluster_id')
+
+ Clusters::Applications::Ingress.where('NOT EXISTS (?)', existing).in_batches do |batch|
+ batch.delete_all
+ end
+
+ unless foreign_keys_for(:clusters_applications_ingress, :cluster_id).any?
+ add_concurrent_foreign_key :clusters_applications_ingress, :clusters,
+ column: :cluster_id,
+ on_delete: :cascade
+ end
+
+ existing = Clusters::Cluster
+ .joins(:application_prometheus)
+ .where('clusters.id = clusters_applications_prometheus.cluster_id')
+
+ Clusters::Applications::Ingress.where('NOT EXISTS (?)', existing).in_batches do |batch|
+ batch.delete_all
+ end
+
+ unless foreign_keys_for(:clusters_applications_prometheus, :cluster_id).any?
+ add_concurrent_foreign_key :clusters_applications_prometheus, :clusters,
+ column: :cluster_id,
+ on_delete: :cascade
+ end
+ end
+
+ def down
+ if foreign_keys_for(:clusters_applications_ingress, :cluster_id).any?
+ remove_foreign_key :clusters_applications_ingress, column: :cluster_id
+ end
+
+ if foreign_keys_for(:clusters_applications_prometheus, :cluster_id).any?
+ remove_foreign_key :clusters_applications_prometheus, column: :cluster_id
+ end
+ end
+end
diff --git a/db/migrate/20180305144721_add_privileged_to_runner.rb b/db/migrate/20180305144721_add_privileged_to_runner.rb
new file mode 100644
index 00000000000..32e73dba8d5
--- /dev/null
+++ b/db/migrate/20180305144721_add_privileged_to_runner.rb
@@ -0,0 +1,18 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddPrivilegedToRunner < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default :clusters_applications_runners, :privileged, :boolean, default: true, allow_null: false
+ end
+
+ def down
+ remove_column :clusters_applications_runners, :privileged
+ end
+end
diff --git a/db/migrate/20180306134842_add_missing_indexes_acts_as_taggable_on_engine.rb b/db/migrate/20180306134842_add_missing_indexes_acts_as_taggable_on_engine.rb
new file mode 100644
index 00000000000..06e402adcd7
--- /dev/null
+++ b/db/migrate/20180306134842_add_missing_indexes_acts_as_taggable_on_engine.rb
@@ -0,0 +1,21 @@
+# This migration comes from acts_as_taggable_on_engine (originally 6)
+#
+# It has been modified to handle no-downtime GitLab migrations. Several
+# indexes have been removed since they are not needed for GitLab.
+class AddMissingIndexesActsAsTaggableOnEngine < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :taggings, :tag_id unless index_exists? :taggings, :tag_id
+ add_concurrent_index :taggings, [:taggable_id, :taggable_type] unless index_exists? :taggings, [:taggable_id, :taggable_type]
+ end
+
+ def down
+ remove_concurrent_index :taggings, :tag_id
+ remove_concurrent_index :taggings, [:taggable_id, :taggable_type]
+ end
+end
diff --git a/db/migrate/20180308052825_add_section_name_id_index_on_ci_build_trace_sections.rb b/db/migrate/20180308052825_add_section_name_id_index_on_ci_build_trace_sections.rb
new file mode 100644
index 00000000000..0cf665ac935
--- /dev/null
+++ b/db/migrate/20180308052825_add_section_name_id_index_on_ci_build_trace_sections.rb
@@ -0,0 +1,22 @@
+class AddSectionNameIdIndexOnCiBuildTraceSections < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ # MySQL may already have this as a foreign key
+ unless index_exists?(:ci_build_trace_sections, :section_name_id)
+ add_concurrent_index :ci_build_trace_sections, :section_name_id
+ end
+ end
+
+ def down
+ # We cannot remove index for MySQL because it's needed for foreign key
+ if Gitlab::Database.postgresql?
+ remove_concurrent_index :ci_build_trace_sections, :section_name_id
+ end
+ end
+end
diff --git a/db/post_migrate/20180223124427_build_user_interacted_projects_table.rb b/db/post_migrate/20180223124427_build_user_interacted_projects_table.rb
new file mode 100644
index 00000000000..5e729b1aa53
--- /dev/null
+++ b/db/post_migrate/20180223124427_build_user_interacted_projects_table.rb
@@ -0,0 +1,124 @@
+class BuildUserInteractedProjectsTable < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ if Gitlab::Database.postgresql?
+ PostgresStrategy.new
+ else
+ MysqlStrategy.new
+ end.up
+
+ unless index_exists?(:user_interacted_projects, [:project_id, :user_id])
+ add_concurrent_index :user_interacted_projects, [:project_id, :user_id], unique: true
+ end
+
+ unless foreign_key_exists?(:user_interacted_projects, :user_id)
+ add_concurrent_foreign_key :user_interacted_projects, :users, column: :user_id, on_delete: :cascade
+ end
+
+ unless foreign_key_exists?(:user_interacted_projects, :project_id)
+ add_concurrent_foreign_key :user_interacted_projects, :projects, column: :project_id, on_delete: :cascade
+ end
+ end
+
+ def down
+ execute "TRUNCATE user_interacted_projects"
+
+ if foreign_key_exists?(:user_interacted_projects, :user_id)
+ remove_foreign_key :user_interacted_projects, :users
+ end
+
+ if foreign_key_exists?(:user_interacted_projects, :project_id)
+ remove_foreign_key :user_interacted_projects, :projects
+ end
+
+ if index_exists_by_name?(:user_interacted_projects, 'index_user_interacted_projects_on_project_id_and_user_id')
+ remove_concurrent_index_by_name :user_interacted_projects, 'index_user_interacted_projects_on_project_id_and_user_id'
+ end
+ end
+
+ private
+
+ # Rails' index_exists? doesn't work when you only give it a table and index
+ # name. As such we have to use some extra code to check if an index exists for
+ # a given name.
+ def index_exists_by_name?(table, index)
+ indexes_for_table[table].include?(index)
+ end
+
+ def indexes_for_table
+ @indexes_for_table ||= Hash.new do |hash, table_name|
+ hash[table_name] = indexes(table_name).map(&:name)
+ end
+ end
+
+ def foreign_key_exists?(table, column)
+ foreign_keys(table).any? do |key|
+ key.options[:column] == column.to_s
+ end
+ end
+
+ class PostgresStrategy < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ BATCH_SIZE = 100_000
+ SLEEP_TIME = 5
+
+ def up
+ with_index(:events, [:author_id, :project_id], name: 'events_user_interactions_temp', where: 'project_id IS NOT NULL') do
+ iteration = 0
+ records = 0
+ begin
+ Rails.logger.info "Building user_interacted_projects table, batch ##{iteration}"
+ result = execute <<~SQL
+ INSERT INTO user_interacted_projects (user_id, project_id)
+ SELECT e.user_id, e.project_id
+ FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
+ LEFT JOIN user_interacted_projects ucp USING (user_id, project_id)
+ WHERE ucp.user_id IS NULL
+ LIMIT #{BATCH_SIZE}
+ SQL
+ iteration += 1
+ records += result.cmd_tuples
+ Rails.logger.info "Building user_interacted_projects table, batch ##{iteration} complete, created #{records} overall"
+ Kernel.sleep(SLEEP_TIME) if result.cmd_tuples > 0
+ rescue ActiveRecord::InvalidForeignKey => e
+ Rails.logger.info "Retry on InvalidForeignKey: #{e}"
+ retry
+ end while result.cmd_tuples > 0
+ end
+
+ execute "ANALYZE user_interacted_projects"
+
+ end
+
+ private
+
+ def with_index(*args)
+ add_concurrent_index(*args) unless index_exists?(*args)
+ yield
+ ensure
+ remove_concurrent_index(*args) if index_exists?(*args)
+ end
+ end
+
+ class MysqlStrategy < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ def up
+ execute <<~SQL
+ INSERT INTO user_interacted_projects (user_id, project_id)
+ SELECT e.user_id, e.project_id
+ FROM (SELECT DISTINCT author_id AS user_id, project_id FROM events WHERE project_id IS NOT NULL) AS e
+ LEFT JOIN user_interacted_projects ucp USING (user_id, project_id)
+ WHERE ucp.user_id IS NULL
+ SQL
+ end
+ end
+
+end
diff --git a/db/post_migrate/20180306074045_migrate_create_trace_artifact_sidekiq_queue.rb b/db/post_migrate/20180306074045_migrate_create_trace_artifact_sidekiq_queue.rb
new file mode 100644
index 00000000000..0af1c3bc0a5
--- /dev/null
+++ b/db/post_migrate/20180306074045_migrate_create_trace_artifact_sidekiq_queue.rb
@@ -0,0 +1,13 @@
+class MigrateCreateTraceArtifactSidekiqQueue < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ sidekiq_queue_migrate 'pipeline_default:create_trace_artifact', to: 'pipeline_background:archive_trace'
+ end
+
+ def down
+ sidekiq_queue_migrate 'pipeline_background:archive_trace', to: 'pipeline_default:create_trace_artifact'
+ end
+end
diff --git a/db/post_migrate/20180307012445_migrate_update_head_pipeline_for_merge_request_sidekiq_queue.rb b/db/post_migrate/20180307012445_migrate_update_head_pipeline_for_merge_request_sidekiq_queue.rb
new file mode 100644
index 00000000000..9728df6d409
--- /dev/null
+++ b/db/post_migrate/20180307012445_migrate_update_head_pipeline_for_merge_request_sidekiq_queue.rb
@@ -0,0 +1,15 @@
+class MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ sidekiq_queue_migrate 'pipeline_default:update_head_pipeline_for_merge_request',
+ to: 'pipeline_processing:update_head_pipeline_for_merge_request'
+ end
+
+ def down
+ sidekiq_queue_migrate 'pipeline_processing:update_head_pipeline_for_merge_request',
+ to: 'pipeline_default:update_head_pipeline_for_merge_request'
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index db8bafe9677..75a094bbbb6 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20180301084653) do
+ActiveRecord::Schema.define(version: 20180308052825) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -183,12 +183,27 @@ ActiveRecord::Schema.define(version: 20180301084653) do
add_index "award_emoji", ["awardable_type", "awardable_id"], name: "index_award_emoji_on_awardable_type_and_awardable_id", using: :btree
add_index "award_emoji", ["user_id", "name"], name: "index_award_emoji_on_user_id_and_name", using: :btree
+ create_table "badges", force: :cascade do |t|
+ t.string "link_url", null: false
+ t.string "image_url", null: false
+ t.integer "project_id"
+ t.integer "group_id"
+ t.string "type", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ end
+
+ add_index "badges", ["group_id"], name: "index_badges_on_group_id", using: :btree
+ add_index "badges", ["project_id"], name: "index_badges_on_project_id", using: :btree
+
create_table "boards", force: :cascade do |t|
- t.integer "project_id", null: false
+ t.integer "project_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.integer "group_id"
end
+ add_index "boards", ["group_id"], name: "index_boards_on_group_id", using: :btree
add_index "boards", ["project_id"], name: "index_boards_on_project_id", using: :btree
create_table "broadcast_messages", force: :cascade do |t|
@@ -249,6 +264,7 @@ ActiveRecord::Schema.define(version: 20180301084653) do
add_index "ci_build_trace_sections", ["build_id", "section_name_id"], name: "index_ci_build_trace_sections_on_build_id_and_section_name_id", unique: true, using: :btree
add_index "ci_build_trace_sections", ["project_id"], name: "index_ci_build_trace_sections_on_project_id", using: :btree
+ add_index "ci_build_trace_sections", ["section_name_id"], name: "index_ci_build_trace_sections_on_section_name_id", using: :btree
create_table "ci_builds", force: :cascade do |t|
t.string "status"
@@ -333,6 +349,7 @@ ActiveRecord::Schema.define(version: 20180301084653) do
t.datetime_with_timezone "updated_at", null: false
t.datetime_with_timezone "expire_at"
t.string "file"
+ t.binary "file_sha256"
end
add_index "ci_job_artifacts", ["expire_at", "job_id"], name: "index_ci_job_artifacts_on_expire_at_and_job_id", using: :btree
@@ -590,6 +607,7 @@ ActiveRecord::Schema.define(version: 20180301084653) do
t.datetime_with_timezone "updated_at", null: false
t.string "version", null: false
t.text "status_reason"
+ t.boolean "privileged", default: true, null: false
end
add_index "clusters_applications_runners", ["cluster_id"], name: "index_clusters_applications_runners_on_cluster_id", unique: true, using: :btree
@@ -1128,6 +1146,7 @@ ActiveRecord::Schema.define(version: 20180301084653) do
t.boolean "discussion_locked"
t.integer "latest_merge_request_diff_id"
t.string "rebase_commit_sha"
+ t.boolean "allow_maintainer_to_push"
end
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
@@ -1715,7 +1734,9 @@ ActiveRecord::Schema.define(version: 20180301084653) do
end
add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree
+ add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree
add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
+ add_index "taggings", ["taggable_id", "taggable_type"], name: "index_taggings_on_taggable_id_and_taggable_type", using: :btree
create_table "tags", force: :cascade do |t|
t.string "name"
@@ -1826,6 +1847,13 @@ ActiveRecord::Schema.define(version: 20180301084653) do
add_index "user_custom_attributes", ["key", "value"], name: "index_user_custom_attributes_on_key_and_value", using: :btree
add_index "user_custom_attributes", ["user_id", "key"], name: "index_user_custom_attributes_on_user_id_and_key", unique: true, using: :btree
+ create_table "user_interacted_projects", id: false, force: :cascade do |t|
+ t.integer "user_id", null: false
+ t.integer "project_id", null: false
+ end
+
+ add_index "user_interacted_projects", ["project_id", "user_id"], name: "index_user_interacted_projects_on_project_id_and_user_id", unique: true, using: :btree
+
create_table "user_synced_attributes_metadata", force: :cascade do |t|
t.boolean "name_synced", default: false
t.boolean "email_synced", default: false
@@ -1969,6 +1997,9 @@ ActiveRecord::Schema.define(version: 20180301084653) do
add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree
add_index "web_hooks", ["type"], name: "index_web_hooks_on_type", using: :btree
+ add_foreign_key "badges", "namespaces", column: "group_id", on_delete: :cascade
+ add_foreign_key "badges", "projects", on_delete: :cascade
+ add_foreign_key "boards", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "boards", "projects", name: "fk_f15266b5f9", on_delete: :cascade
add_foreign_key "chat_teams", "namespaces", on_delete: :cascade
add_foreign_key "ci_build_trace_section_names", "projects", on_delete: :cascade
@@ -2001,6 +2032,8 @@ ActiveRecord::Schema.define(version: 20180301084653) do
add_foreign_key "cluster_providers_gcp", "clusters", on_delete: :cascade
add_foreign_key "clusters", "users", on_delete: :nullify
add_foreign_key "clusters_applications_helm", "clusters", on_delete: :cascade
+ add_foreign_key "clusters_applications_ingress", "clusters", name: "fk_753a7b41c1", on_delete: :cascade
+ add_foreign_key "clusters_applications_prometheus", "clusters", name: "fk_557e773639", on_delete: :cascade
add_foreign_key "clusters_applications_runners", "ci_runners", column: "runner_id", name: "fk_02de2ded36", on_delete: :nullify
add_foreign_key "clusters_applications_runners", "clusters", on_delete: :cascade
add_foreign_key "container_repositories", "projects"
@@ -2095,6 +2128,8 @@ ActiveRecord::Schema.define(version: 20180301084653) do
add_foreign_key "u2f_registrations", "users"
add_foreign_key "user_callouts", "users", on_delete: :cascade
add_foreign_key "user_custom_attributes", "users", on_delete: :cascade
+ add_foreign_key "user_interacted_projects", "projects", name: "fk_722ceba4f7", on_delete: :cascade
+ add_foreign_key "user_interacted_projects", "users", name: "fk_0894651f08", on_delete: :cascade
add_foreign_key "user_synced_attributes_metadata", "users", on_delete: :cascade
add_foreign_key "users_star_projects", "projects", name: "fk_22cd27ddfc", on_delete: :cascade
add_foreign_key "web_hook_logs", "web_hooks", on_delete: :cascade
diff --git a/doc/README.md b/doc/README.md
index fb7a23e2750..05fa444657c 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -77,6 +77,7 @@ Manage your [repositories](user/project/repository/index.md) from the UI (user i
- [Discussions](user/discussions/index.md): Threads, comments, and resolvable discussions in issues, commits, and merge requests.
- [Issues](user/project/issues/index.md)
- [Project issue Board](user/project/issue_board.md)
+- [Group Issue Board](user/project/issue_board.md#group-issue-board)
- [Issues and merge requests templates](user/project/description_templates.md): Create templates for submitting new issues and merge requests.
- [Labels](user/project/labels.md): Categorize your issues or merge requests based on descriptive titles.
- [Merge Requests](user/project/merge_requests/index.md)
diff --git a/doc/administration/monitoring/index.md b/doc/administration/monitoring/index.md
index b6320aba83e..d18dddf09c0 100644
--- a/doc/administration/monitoring/index.md
+++ b/doc/administration/monitoring/index.md
@@ -7,3 +7,4 @@ Explore our features to monitor your GitLab instance:
- [GitHub imports](github_imports.md): Monitor the health and progress of GitLab's GitHub importer with various Prometheus metrics.
- [Monitoring uptime](../../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint.
- [IP whitelists](ip_whitelist.md): Configure GitLab for monitoring endpoints that provide health check information when probed.
+- [nginx_status](https://docs.gitlab.com/omnibus/settings/nginx.html#enabling-disabling-nginx_status): Monitor your Nginx server status
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index d73d9422d2c..51c62742d01 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -84,12 +84,14 @@ checks using those checksums can be run. These checks also detect missing files.
Currently, integrity checks are supported for the following types of file:
+* CI artifacts
* LFS objects
* User uploads
**Omnibus Installation**
```
+sudo gitlab-rake gitlab:artifacts:check
sudo gitlab-rake gitlab:lfs:check
sudo gitlab-rake gitlab:uploads:check
```
@@ -97,6 +99,7 @@ sudo gitlab-rake gitlab:uploads:check
**Source Installation**
```bash
+sudo -u git -H bundle exec rake gitlab:artifacts:check RAILS_ENV=production
sudo -u git -H bundle exec rake gitlab:lfs:check RAILS_ENV=production
sudo -u git -H bundle exec rake gitlab:uploads:check RAILS_ENV=production
```
@@ -112,6 +115,7 @@ Variable | Type | Description
`VERBOSE` | boolean | Causes failures to be listed individually, rather than being summarized.
```bash
+sudo gitlab-rake gitlab:artifacts:check BATCH=100 ID_FROM=50 ID_TO=250
sudo gitlab-rake gitlab:lfs:check BATCH=100 ID_FROM=50 ID_TO=250
sudo gitlab-rake gitlab:uploads:check BATCH=100 ID_FROM=50 ID_TO=250
```
diff --git a/doc/api/README.md b/doc/api/README.md
index b193ef4ab7f..ae4481b400e 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -24,9 +24,11 @@ following locations:
- [GitLab CI Config templates](templates/gitlab_ci_ymls.md)
- [Groups](groups.md)
- [Group Access Requests](access_requests.md)
+- [Group Badges](group_badges.md)
- [Group Members](members.md)
- [Issues](issues.md)
- [Issue Boards](boards.md)
+- [Group Issue Boards](group_boards.md)
- [Jobs](jobs.md)
- [Keys](keys.md)
- [Labels](labels.md)
@@ -35,6 +37,7 @@ following locations:
- [Group milestones](group_milestones.md)
- [Namespaces](namespaces.md)
- [Notes](notes.md) (comments)
+- [Discussions](discussions.md) (threaded comments)
- [Notification settings](notification_settings.md)
- [Open source license templates](templates/licenses.md)
- [Pages Domains](pages_domains.md)
@@ -43,6 +46,7 @@ following locations:
- [Pipeline Schedules](pipeline_schedules.md)
- [Projects](projects.md) including setting Webhooks
- [Project Access Requests](access_requests.md)
+- [Project Badges](project_badges.md)
- [Project import/export](project_import_export.md)
- [Project Members](members.md)
- [Project Snippets](project_snippets.md)
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
new file mode 100644
index 00000000000..c341b7f2009
--- /dev/null
+++ b/doc/api/discussions.md
@@ -0,0 +1,411 @@
+# Discussions API
+
+Discussions are set of related notes on snippets or issues.
+
+## Issues
+
+### List project issue discussions
+
+Gets a list of all discussions for a single issue.
+
+```
+GET /projects/:id/issues/:issue_iid/discussions
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ------------ |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+
+```json
+[
+ {
+ "id": "6a9c1750b37d513a43987b574953fceb50b03ce7",
+ "individual_note": false,
+ "notes": [
+ {
+ "id": 1126,
+ "type": "DiscussionNote",
+ "body": "discussion text",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-03T21:54:39.668Z",
+ "updated_at": "2018-03-03T21:54:39.668Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Issue",
+ "noteable_iid": null
+ },
+ {
+ "id": 1129,
+ "type": "DiscussionNote",
+ "body": "reply to the discussion",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-04T13:38:02.127Z",
+ "updated_at": "2018-03-04T13:38:02.127Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Issue",
+ "noteable_iid": null
+ }
+ ]
+ },
+ {
+ "id": "87805b7c09016a7058e91bdbe7b29d1f284a39e6",
+ "individual_note": true,
+ "notes": [
+ {
+ "id": 1128,
+ "type": null,
+ "body": "a single comment",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-04T09:17:22.520Z",
+ "updated_at": "2018-03-04T09:17:22.520Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Issue",
+ "noteable_iid": null
+ }
+ ]
+ }
+]
+```
+
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions
+```
+
+### Get single issue discussion
+
+Returns a single discussion for a specific project issue
+
+```
+GET /projects/:id/issues/:issue_iid/discussions/:discussion_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `discussion_id` | integer | yes | The ID of a discussion |
+
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
+```
+
+### Create new issue discussion
+
+Creates a new discussion to a single project issue. This is similar to creating
+a note but but another comments (replies) can be added to it later.
+
+```
+POST /projects/:id/issues/:issue_iid/discussions
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `body` | string | yes | The content of a discussion |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions?body=comment
+```
+
+### Add note to existing issue discussion
+
+Adds a new note to the discussion.
+
+```
+POST /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+| `body` | string | yes | The content of a discussion |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
+```
+
+### Modify existing issue discussion note
+
+Modify existing discussion note of an issue.
+
+```
+PUT /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+| `body` | string | yes | The content of a discussion |
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
+```
+
+### Delete an issue discussion note
+
+Deletes an existing discussion note of an issue.
+
+```
+DELETE /projects/:id/issues/:issue_iid/discussions/:discussion_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `issue_iid` | integer | yes | The IID of an issue |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/discussions/636
+```
+
+## Snippets
+
+### List project snippet discussions
+
+Gets a list of all discussions for a single snippet.
+
+```
+GET /projects/:id/snippets/:snippet_id/discussions
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+
+```json
+[
+ {
+ "id": "6a9c1750b37d513a43987b574953fceb50b03ce7",
+ "individual_note": false,
+ "notes": [
+ {
+ "id": 1126,
+ "type": "DiscussionNote",
+ "body": "discussion text",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-03T21:54:39.668Z",
+ "updated_at": "2018-03-03T21:54:39.668Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Snippet",
+ "noteable_id": null
+ },
+ {
+ "id": 1129,
+ "type": "DiscussionNote",
+ "body": "reply to the discussion",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-04T13:38:02.127Z",
+ "updated_at": "2018-03-04T13:38:02.127Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Snippet",
+ "noteable_id": null
+ }
+ ]
+ },
+ {
+ "id": "87805b7c09016a7058e91bdbe7b29d1f284a39e6",
+ "individual_note": true,
+ "notes": [
+ {
+ "id": 1128,
+ "type": null,
+ "body": "a single comment",
+ "attachment": null,
+ "author": {
+ "id": 1,
+ "name": "root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/00afb8fb6ab07c3ee3e9c1f38777e2f4?s=80&d=identicon",
+ "web_url": "http://localhost:3000/root"
+ },
+ "created_at": "2018-03-04T09:17:22.520Z",
+ "updated_at": "2018-03-04T09:17:22.520Z",
+ "system": false,
+ "noteable_id": 3,
+ "noteable_type": "Snippet",
+ "noteable_id": null
+ }
+ ]
+ }
+]
+```
+
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions
+```
+
+### Get single snippet discussion
+
+Returns a single discussion for a specific project snippet
+
+```
+GET /projects/:id/snippets/:snippet_id/discussions/:discussion_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `discussion_id` | integer | yes | The ID of a discussion |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7
+```
+
+### Create new snippet discussion
+
+Creates a new discussion to a single project snippet. This is similar to creating
+a note but but another comments (replies) can be added to it later.
+
+```
+POST /projects/:id/snippets/:snippet_id/discussions
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `body` | string | yes | The content of a discussion |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions?body=comment
+```
+
+### Add note to existing snippet discussion
+
+Adds a new note to the discussion.
+
+```
+POST /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+| `body` | string | yes | The content of a discussion |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes?body=comment
+```
+
+### Modify existing snippet discussion note
+
+Modify existing discussion note of an snippet.
+
+```
+PUT /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+| `body` | string | yes | The content of a discussion |
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/1108?body=comment
+```
+
+### Delete an snippet discussion note
+
+Deletes an existing discussion note of an snippet.
+
+```
+DELETE /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes/:note_id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `snippet_id` | integer | yes | The ID of an snippet |
+| `discussion_id` | integer | yes | The ID of a discussion |
+| `note_id` | integer | yes | The ID of a discussion note |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/636
+```
diff --git a/doc/api/group_badges.md b/doc/api/group_badges.md
new file mode 100644
index 00000000000..3e0683f378d
--- /dev/null
+++ b/doc/api/group_badges.md
@@ -0,0 +1,191 @@
+# Group badges API
+
+## Placeholder tokens
+
+Badges support placeholders that will be replaced in real time in both the link and image URL. The allowed placeholders are:
+
+- **%{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.
+
+Because these enpoints aren't inside a project's context, the information used to replace the placeholders will be
+from the first group's project by creation date. If the group hasn't got any project the original URL with the placeholders will be returned.
+
+## List all badges of a group
+
+Gets a list of a group's badges.
+
+```
+GET /groups/:id/badges
+```
+
+| 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 |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_image_url": "https://shields.io/my/badge",
+ "kind": "group"
+ },
+ {
+ "id": 2,
+ "link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_image_url": "https://shields.io/my/badge",
+ "kind": "group"
+ },
+]
+```
+
+## Get a badge of a group
+
+Gets a badge of a group.
+
+```
+GET /groups/:id/badges/:badge_id
+```
+
+| 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 |
+| `badge_id` | integer | yes | The badge ID |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_image_url": "https://shields.io/my/badge",
+ "kind": "group"
+}
+```
+
+## Add a badge to a group
+
+Adds a badge to a group.
+
+```
+POST /groups/:id/badges
+```
+
+| 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 |
+| `link_url` | string | yes | URL of the badge link |
+| `image_url` | string | yes | URL of the badge image |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "link_url=https://gitlab.com/gitlab-org/gitlab-ce/commits/master&image_url=https://shields.io/my/badge1&position=0" https://gitlab.example.com/api/v4/groups/:id/badges
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "link_url": "https://gitlab.com/gitlab-org/gitlab-ce/commits/master",
+ "image_url": "https://shields.io/my/badge1",
+ "rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-ce/commits/master",
+ "rendered_image_url": "https://shields.io/my/badge1",
+ "kind": "group"
+}
+```
+
+## Edit a badge of a group
+
+Updates a badge of a group.
+
+```
+PUT /groups/:id/badges/:badge_id
+```
+
+| 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 |
+| `badge_id` | integer | yes | The badge ID |
+| `link_url` | string | no | URL of the badge link |
+| `image_url` | string | no | URL of the badge image |
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "link_url": "https://gitlab.com/gitlab-org/gitlab-ce/commits/master",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-ce/commits/master",
+ "rendered_image_url": "https://shields.io/my/badge",
+ "kind": "group"
+}
+```
+
+## Remove a badge from a group
+
+Removes a badge from a group.
+
+```
+DELETE /groups/:id/badges/:badge_id
+```
+
+| 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 |
+| `badge_id` | integer | yes | The badge ID |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges/:badge_id
+```
+
+## Preview a badge from a group
+
+Returns how the `link_url` and `image_url` final URLs would be after resolving the placeholder interpolation.
+
+```
+GET /groups/:id/badges/render
+```
+
+| 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 |
+| `link_url` | string | yes | URL of the badge link|
+| `image_url` | string | yes | URL of the badge image |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/:id/badges/render?link_url=http%3A%2F%2Fexample.com%2Fci_status.svg%3Fproject%3D%25%7Bproject_path%7D%26ref%3D%25%7Bdefault_branch%7D&image_url=https%3A%2F%2Fshields.io%2Fmy%2Fbadge
+```
+
+Example response:
+
+```json
+{
+ "link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_image_url": "https://shields.io/my/badge",
+}
+```
diff --git a/doc/api/group_boards.md b/doc/api/group_boards.md
new file mode 100644
index 00000000000..45a8544d6b1
--- /dev/null
+++ b/doc/api/group_boards.md
@@ -0,0 +1,284 @@
+# Group Issue Boards API
+
+Every API call to group boards must be authenticated.
+
+If a user is not a member of a group and the group is private, a `GET`
+request will result in `404` status code.
+
+## Group Board
+
+Lists Issue Boards in the given group.
+
+```
+GET /groups/:id/boards
+```
+
+| 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 |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "group_id": 5,
+ "lists" : [
+ {
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+ },
+ {
+ "id" : 2,
+ "label" : {
+ "name" : "Ready",
+ "color" : "#FF0000",
+ "description" : null
+ },
+ "position" : 2
+ },
+ {
+ "id" : 3,
+ "label" : {
+ "name" : "Production",
+ "color" : "#FF5F00",
+ "description" : null
+ },
+ "position" : 3
+ }
+ ]
+ }
+]
+```
+
+## Single board
+
+Gets a single board.
+
+```
+GET /groups/:id/boards/:board_id
+```
+
+| 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 |
+| `board_id` | integer | yes | The ID of a board |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1
+```
+
+Example response:
+
+```json
+ {
+ "id": 1,
+ "group_id": 5,
+ "lists" : [
+ {
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+ },
+ {
+ "id" : 2,
+ "label" : {
+ "name" : "Ready",
+ "color" : "#FF0000",
+ "description" : null
+ },
+ "position" : 2
+ },
+ {
+ "id" : 3,
+ "label" : {
+ "name" : "Production",
+ "color" : "#FF5F00",
+ "description" : null
+ },
+ "position" : 3
+ }
+ ]
+ }
+```
+
+## List board lists
+
+Get a list of the board's lists.
+Does not include `backlog` and `closed` lists
+
+```
+GET /groups/:id/boards/:board_id/lists
+```
+
+| 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 |
+| `board_id` | integer | yes | The ID of a board |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1/lists
+```
+
+Example response:
+
+```json
+[
+ {
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+ },
+ {
+ "id" : 2,
+ "label" : {
+ "name" : "Ready",
+ "color" : "#FF0000",
+ "description" : null
+ },
+ "position" : 2
+ },
+ {
+ "id" : 3,
+ "label" : {
+ "name" : "Production",
+ "color" : "#FF5F00",
+ "description" : null
+ },
+ "position" : 3
+ }
+]
+```
+
+## Single board list
+
+Get a single board list.
+
+```
+GET /groups/:id/boards/:board_id/lists/:list_id
+```
+
+| 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 |
+| `board_id` | integer | yes | The ID of a board |
+| `list_id` | integer | yes | The ID of a board's list |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1/lists/1
+```
+
+Example response:
+
+```json
+{
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+}
+```
+
+## New board list
+
+Creates a new Issue Board list.
+
+```
+POST /groups/:id/boards/:board_id/lists
+```
+
+| 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 |
+| `board_id` | integer | yes | The ID of a board |
+| `label_id` | integer | yes | The ID of a label |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1/lists?label_id=5
+```
+
+Example response:
+
+```json
+{
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+}
+```
+
+## Edit board list
+
+Updates an existing Issue Board list. This call is used to change list position.
+
+```
+PUT /groups/:id/boards/:board_id/lists/:list_id
+```
+
+| 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 |
+| `board_id` | integer | yes | The ID of a board |
+| `list_id` | integer | yes | The ID of a board's list |
+| `position` | integer | yes | The position of the list |
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/group/5/boards/1/lists/1?position=2
+```
+
+Example response:
+
+```json
+{
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+}
+```
+
+## Delete a board list
+
+Only for admins and group owners. Soft deletes the board list in question.
+
+```
+DELETE /groups/:id/boards/:board_id/lists/:list_id
+```
+
+| 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 |
+| `board_id` | integer | yes | The ID of a board |
+| `list_id` | integer | yes | The ID of a board's list |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/boards/1/lists/1
+```
diff --git a/doc/api/groups.md b/doc/api/groups.md
index f50558b58a6..1aed8aac64e 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -525,3 +525,7 @@ And to switch pages add:
```
[ce-15142]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15142
+
+## Group badges
+
+Read more in the [Group Badges](group_badges.md) documentation.
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 25b0807eb18..b9a4f661777 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -529,18 +529,19 @@ Creates a new merge request.
POST /projects/:id/merge_requests
```
-| 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 |
-| `source_branch` | string | yes | The source branch |
-| `target_branch` | string | yes | The target branch |
-| `title` | string | yes | Title of MR |
-| `assignee_id` | integer | no | Assignee user ID |
-| `description` | string | no | Description of MR |
-| `target_project_id` | integer | no | The target project (numeric id) |
-| `labels` | string | no | Labels for MR as a comma-separated list |
-| `milestone_id` | integer | no | The ID of a milestone |
-| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
+| 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 |
+| `source_branch` | string | yes | The source branch |
+| `target_branch` | string | yes | The target branch |
+| `title` | string | yes | Title of MR |
+| `assignee_id` | integer | no | Assignee user ID |
+| `description` | string | no | Description of MR |
+| `target_project_id` | integer | no | The target project (numeric id) |
+| `labels` | string | no | Labels for MR as a comma-separated list |
+| `milestone_id` | integer | no | The ID of a milestone |
+| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
+| `allow_maintainer_to_push` | boolean | no | Whether or not a maintainer of the target project can push to the source branch |
```json
{
@@ -548,7 +549,7 @@ POST /projects/:id/merge_requests
"iid": 1,
"target_branch": "master",
"source_branch": "test1",
- "project_id": 3,
+ "project_id": 4,
"title": "test1",
"state": "opened",
"upvotes": 0,
@@ -569,7 +570,7 @@ POST /projects/:id/merge_requests
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
- "source_project_id": 4,
+ "source_project_id": 3,
"target_project_id": 4,
"labels": [ ],
"description": "fixed login page css paddings",
@@ -596,6 +597,7 @@ POST /projects/:id/merge_requests
"force_remove_source_branch": false,
"web_url": "http://example.com/example/example/merge_requests/1",
"discussion_locked": false,
+ "allow_maintainer_to_push": false,
"time_stats": {
"time_estimate": 0,
"total_time_spent": 0,
@@ -613,19 +615,20 @@ Updates an existing merge request. You can change the target branch, title, or e
PUT /projects/:id/merge_requests/:merge_request_iid
```
-| 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 |
-| `merge_request_iid` | integer | yes | The ID of a merge request |
-| `target_branch` | string | no | The target branch |
-| `title` | string | no | Title of MR |
-| `assignee_id` | integer | no | The ID of the user to assign the merge request to. Set to `0` or provide an empty value to unassign all assignees. |
-| `milestone_id` | integer | no | The ID of a milestone to assign the merge request to. Set to `0` or provide an empty value to unassign a milestone.|
-| `labels` | string | no | Comma-separated label names for a merge request. Set to an empty string to unassign all labels. |
-| `description` | string | no | Description of MR |
-| `state_event` | string | no | New state (close/reopen) |
-| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
-| `discussion_locked` | boolean | no | Flag indicating if the merge request's discussion is locked. If the discussion is locked only project members can add, edit or resolve comments. |
+| 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 |
+| `merge_request_iid` | integer | yes | The ID of a merge request |
+| `target_branch` | string | no | The target branch |
+| `title` | string | no | Title of MR |
+| `assignee_id` | integer | no | The ID of the user to assign the merge request to. Set to `0` or provide an empty value to unassign all assignees. |
+| `milestone_id` | integer | no | The ID of a milestone to assign the merge request to. Set to `0` or provide an empty value to unassign a milestone.|
+| `labels` | string | no | Comma-separated label names for a merge request. Set to an empty string to unassign all labels. |
+| `description` | string | no | Description of MR |
+| `state_event` | string | no | New state (close/reopen) |
+| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
+| `discussion_locked` | boolean | no | Flag indicating if the merge request's discussion is locked. If the discussion is locked only project members can add, edit or resolve comments. |
+| `allow_maintainer_to_push` | boolean | no | Whether or not a maintainer of the target project can push to the source branch |
Must include at least one non-required attribute from above.
@@ -634,7 +637,7 @@ Must include at least one non-required attribute from above.
"id": 1,
"iid": 1,
"target_branch": "master",
- "project_id": 3,
+ "project_id": 4,
"title": "test1",
"state": "opened",
"upvotes": 0,
@@ -655,7 +658,7 @@ Must include at least one non-required attribute from above.
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
- "source_project_id": 4,
+ "source_project_id": 3,
"target_project_id": 4,
"labels": [ ],
"description": "description1",
@@ -682,6 +685,7 @@ Must include at least one non-required attribute from above.
"force_remove_source_branch": false,
"web_url": "http://example.com/example/example/merge_requests/1",
"discussion_locked": false,
+ "allow_maintainer_to_push": false,
"time_stats": {
"time_estimate": 0,
"total_time_spent": 0,
diff --git a/doc/api/notes.md b/doc/api/notes.md
index 1b68bd99ce2..aa38d22845c 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -15,7 +15,7 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
| 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
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
| `issue_iid` | integer | yes | The IID of an issue
| `sort` | string | no | Return issue notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return issue notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
@@ -63,6 +63,10 @@ GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
]
```
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes
+```
+
### Get single issue note
Returns a single note for a specific project issue
@@ -73,14 +77,17 @@ GET /projects/:id/issues/:issue_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `issue_iid` (required) - The IID of a project issue
- `note_id` (required) - The ID of an issue note
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes/1
+```
+
### Create new issue note
-Creates a new note to a single project issue. If you create a note where the body
-only contains an Award Emoji, you'll receive this object back.
+Creates a new note to a single project issue.
```
POST /projects/:id/issues/:issue_iid/notes
@@ -88,11 +95,15 @@ POST /projects/:id/issues/:issue_iid/notes
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `issue_id` (required) - The IID of an issue
- `body` (required) - The content of a note
- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
+```
+
### Modify existing issue note
Modify existing note of an issue.
@@ -103,11 +114,15 @@ PUT /projects/:id/issues/:issue_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `issue_iid` (required) - The IID of an issue
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes?body=note
+```
+
### Delete an issue note
Deletes an existing note of an issue.
@@ -120,7 +135,7 @@ Parameters:
| 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 |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `issue_iid` | integer | yes | The IID of an issue |
| `note_id` | integer | yes | The ID of a note |
@@ -141,11 +156,15 @@ GET /projects/:id/snippets/:snippet_id/notes?sort=asc&order_by=updated_at
| 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
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
| `snippet_id` | integer | yes | The ID of a project snippet
| `sort` | string | no | Return snippet notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return snippet notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes
+```
+
### Get single snippet note
Returns a single note for a given snippet.
@@ -156,7 +175,7 @@ GET /projects/:id/snippets/:snippet_id/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `snippet_id` (required) - The ID of a project snippet
- `note_id` (required) - The ID of a snippet note
@@ -179,6 +198,10 @@ Parameters:
}
```
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes/11
+```
+
### Create new snippet note
Creates a new note for a single snippet. Snippet notes are comments users can post to a snippet.
@@ -190,10 +213,14 @@ POST /projects/:id/snippets/:snippet_id/notes
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `snippet_id` (required) - The ID of a snippet
- `body` (required) - The content of a note
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippet/11/notes?body=note
+```
+
### Modify existing snippet note
Modify existing note of a snippet.
@@ -204,11 +231,15 @@ PUT /projects/:id/snippets/:snippet_id/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `snippet_id` (required) - The ID of a snippet
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/notes?body=note
+```
+
### Delete a snippet note
Deletes an existing note of a snippet.
@@ -221,7 +252,7 @@ Parameters:
| 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 |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `snippet_id` | integer | yes | The ID of a snippet |
| `note_id` | integer | yes | The ID of a note |
@@ -242,11 +273,15 @@ GET /projects/:id/merge_requests/:merge_request_iid/notes?sort=asc&order_by=upda
| 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
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
| `merge_request_iid` | integer | yes | The IID of a project merge request
| `sort` | string | no | Return merge request notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return merge request notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes
+```
+
### Get single merge request note
Returns a single note for a given merge request.
@@ -257,7 +292,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `merge_request_iid` (required) - The IID of a project merge request
- `note_id` (required) - The ID of a merge request note
@@ -283,6 +318,10 @@ Parameters:
}
```
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes/1
+```
+
### Create new merge request note
Creates a new note for a single merge request.
@@ -295,7 +334,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/notes
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `merge_request_iid` (required) - The IID of a merge request
- `body` (required) - The content of a note
@@ -309,11 +348,15 @@ PUT /projects/:id/merge_requests/:merge_request_iid/notes/:note_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding)
- `merge_request_iid` (required) - The IID of a merge request
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/notes?body=note
+```
+
### Delete a merge request note
Deletes an existing note of a merge request.
@@ -326,7 +369,7 @@ Parameters:
| 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 |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `merge_request_iid` | integer | yes | The IID of a merge request |
| `note_id` | integer | yes | The ID of a note |
diff --git a/doc/api/project_badges.md b/doc/api/project_badges.md
new file mode 100644
index 00000000000..3f6e348b5b4
--- /dev/null
+++ b/doc/api/project_badges.md
@@ -0,0 +1,188 @@
+# Project badges API
+
+## Placeholder tokens
+
+Badges support placeholders that will be replaced in real time in both the link and image URL. The allowed placeholders are:
+
+- **%{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.
+
+## List all badges of a project
+
+Gets a list of a project's badges and its group badges.
+
+```
+GET /projects/:id/badges
+```
+
+| 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 |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_image_url": "https://shields.io/my/badge",
+ "kind": "project"
+ },
+ {
+ "id": 2,
+ "link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_image_url": "https://shields.io/my/badge",
+ "kind": "group"
+ },
+]
+```
+
+## Get a badge of a project
+
+Gets a badge of a project.
+
+```
+GET /projects/:id/badges/:badge_id
+```
+
+| 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 |
+| `badge_id` | integer | yes | The badge ID |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_image_url": "https://shields.io/my/badge",
+ "kind": "project"
+}
+```
+
+## Add a badge to a project
+
+Adds a badge to a project.
+
+```
+POST /projects/:id/badges
+```
+
+| 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 |
+| `link_url` | string | yes | URL of the badge link |
+| `image_url` | string | yes | URL of the badge image |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "link_url=https://gitlab.com/gitlab-org/gitlab-ce/commits/master&image_url=https://shields.io/my/badge1&position=0" https://gitlab.example.com/api/v4/projects/:id/badges
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "link_url": "https://gitlab.com/gitlab-org/gitlab-ce/commits/master",
+ "image_url": "https://shields.io/my/badge1",
+ "rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-ce/commits/master",
+ "rendered_image_url": "https://shields.io/my/badge1",
+ "kind": "project"
+}
+```
+
+## Edit a badge of a project
+
+Updates a badge of a project.
+
+```
+PUT /projects/:id/badges/:badge_id
+```
+
+| 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 |
+| `badge_id` | integer | yes | The badge ID |
+| `link_url` | string | no | URL of the badge link |
+| `image_url` | string | no | URL of the badge image |
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "link_url": "https://gitlab.com/gitlab-org/gitlab-ce/commits/master",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-ce/commits/master",
+ "rendered_image_url": "https://shields.io/my/badge",
+ "kind": "project"
+}
+```
+
+## Remove a badge from a project
+
+Removes a badge from a project. Only project's badges will be removed by using this endpoint.
+
+```
+DELETE /projects/:id/badges/:badge_id
+```
+
+| 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 |
+| `badge_id` | integer | yes | The badge ID |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id
+```
+
+## Preview a badge from a project
+
+Returns how the `link_url` and `image_url` final URLs would be after resolving the placeholder interpolation.
+
+```
+GET /projects/:id/badges/render
+```
+
+| 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 |
+| `link_url` | string | yes | URL of the badge link|
+| `image_url` | string | yes | URL of the badge image |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/badges/render?link_url=http%3A%2F%2Fexample.com%2Fci_status.svg%3Fproject%3D%25%7Bproject_path%7D%26ref%3D%25%7Bdefault_branch%7D&image_url=https%3A%2F%2Fshields.io%2Fmy%2Fbadge
+```
+
+Example response:
+
+```json
+{
+ "link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
+ "image_url": "https://shields.io/my/badge",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_image_url": "https://shields.io/my/badge",
+}
+```
diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md
index e442442c750..677765368a8 100644
--- a/doc/api/project_import_export.md
+++ b/doc/api/project_import_export.md
@@ -1,9 +1,89 @@
-# Project import API
+# Project import/export API
[Introduced][ce-41899] in GitLab 10.6
[See also the project import/export documentation](../user/project/settings/import_export.md)
+## Schedule an export
+
+Start a new export.
+
+```http
+POST /projects/:id/export
+```
+
+| 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 |
+
+```console
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/export
+```
+
+```json
+{
+ "message": "202 Accepted"
+}
+```
+
+## Export status
+
+Get the status of export.
+
+```http
+GET /projects/:id/export
+```
+
+| 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 |
+
+```console
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/export
+```
+
+Status can be one of `none`, `started`, or `finished`.
+
+`_links` are only present when export has finished.
+
+```json
+{
+ "id": 1,
+ "description": "Itaque perspiciatis minima aspernatur corporis consequatur.",
+ "name": "Gitlab Test",
+ "name_with_namespace": "Gitlab Org / Gitlab Test",
+ "path": "gitlab-test",
+ "path_with_namespace": "gitlab-org/gitlab-test",
+ "created_at": "2017-08-29T04:36:44.383Z",
+ "export_status": "finished",
+ "_links": {
+ "api_url": "https://gitlab.example.com/api/v4/projects/1/export/download",
+ "web_url": "https://gitlab.example.com/gitlab-org/gitlab-test/download_export",
+ }
+}
+```
+
+## Export download
+
+Download the finished export.
+
+```http
+GET /projects/:id/export/download
+```
+
+| 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 |
+
+```console
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --remote-header-name --remote-name https://gitlab.example.com/api/v4/projects/5/export/download
+```
+
+```console
+ls *export.tar.gz
+2017-12-05_22-11-148_namespace_project_export.tar.gz
+```
+
## Import a file
```http
diff --git a/doc/api/projects.md b/doc/api/projects.md
index b6442cfac22..271ee91dc72 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1340,3 +1340,7 @@ Read more in the [Project import/export](project_import_export.md) documentation
## Project members
Read more in the [Project members](members.md) documentation.
+
+## Project badges
+
+Read more in the [Project Badges](project_badges.md) documentation.
diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md
index ffebe1618d3..f69729f602d 100644
--- a/doc/ci/examples/README.md
+++ b/doc/ci/examples/README.md
@@ -32,34 +32,38 @@ There's also a collection of repositories with [example projects](https://gitlab
- **Debian**: [Continuous Deployment with GitLab: how to build and deploy a Debian Package with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/)
- **Maven**: [How to deploy Maven projects to Artifactory with GitLab CI/CD](artifactory_and_gitlab/index.md)
+### Game development
+
+- [DevOps and Game Dev with GitLab CI/CD](devops_and_game_dev_with_gitlab_ci_cd/index.md)
+
### Miscellaneous
- [Using `dpl` as deployment tool](deployment/README.md)
- [The `.gitlab-ci.yml` file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
-### Code quality analysis
+## Code quality analysis
[Analyze code quality with the Code Climate CLI](code_climate.md).
-### Static Application Security Testing (SAST)
+## Static Application Security Testing (SAST)
- **(Ultimate)** [Scan your code for vulnerabilities](https://docs.gitlab.com/ee/ci/examples/sast.html)
- [Scan your Docker images for vulnerabilities](sast_docker.md)
-### Dynamic Application Security Testing (DAST)
+## Dynamic Application Security Testing (DAST)
Scan your app for vulnerabilities with GitLab [Dynamic Application Security Testing (DAST)](dast.md).
-### Browser Performance Testing with Sitespeed.io
+## Browser Performance Testing with Sitespeed.io
Analyze your [browser performance with Sitespeed.io](browser_performance.md).
-### GitLab CI/CD for Review Apps
+## GitLab CI/CD for Review Apps
- [Example project](https://gitlab.com/gitlab-examples/review-apps-nginx/) that shows how to use GitLab CI/CD for [Review Apps](../review_apps/index.html).
- [Dockerizing GitLab Review Apps](https://about.gitlab.com/2017/07/11/dockerizing-review-apps/)
-### GitLab CI/CD for GitLab Pages
+## GitLab CI/CD for GitLab Pages
See the documentation on [GitLab Pages](../../user/project/pages/index.md) for a complete overview.
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.png b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.png
new file mode 100644
index 00000000000..76e0295722b
--- /dev/null
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/aws_config_window.png
Binary files differ
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.png b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.png
new file mode 100644
index 00000000000..050a97d2726
--- /dev/null
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/gitlab_config.png
Binary files differ
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.png b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.png
new file mode 100644
index 00000000000..4ab5d5f401a
--- /dev/null
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/img/test_pipeline_pass.png
Binary files differ
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
new file mode 100644
index 00000000000..bfc8558a580
--- /dev/null
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
@@ -0,0 +1,526 @@
+---
+author: Ryan Hall
+author_gitlab: blitzgren
+level: intermediary
+article_type: tutorial
+date: 2018-03-07
+---
+
+# DevOps and Game Dev with GitLab CI/CD
+
+With advances in WebGL and WebSockets, browsers are extremely viable as game development
+platforms without the use of plugins like Adobe Flash. Furthermore, by using GitLab and [AWS](https://aws.amazon.com/),
+single game developers, as well as game dev teams, can easily host browser-based games online.
+
+In this tutorial, we'll focus on DevOps, as well as testing and hosting games with Continuous
+Integration/Deployment methods. We assume you are familiar with GitLab, javascript,
+and the basics of game development.
+
+## The game
+
+Our [demo game](http://gitlab-game-demo.s3-website-us-east-1.amazonaws.com/) consists of a simple spaceship traveling in space that shoots by clicking the mouse in a given direction.
+
+Creating a strong CI/CD pipeline at the beginning of developing another game, [Dark Nova](http://darknova.io/about),
+was essential for the fast pace the team worked at. This tutorial will build upon my
+[previous introductory article](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/) and go through the following steps:
+
+1. Using code from the previous article to start with a barebones [Phaser](https://phaser.io) game built by a gulp file
+1. Adding and running unit tests
+1. Creating a `Weapon` class that can be triggered to spawn a `Bullet` in a given direction
+1. Adding a `Player` class that uses this weapon and moves around the screen
+1. Adding the sprites we will use for the `Player` and `Weapon`
+1. Testing and deploying with Continuous Integration and Continuous Deployment methods
+
+By the end, we'll have the core of a [playable game](http://gitlab-game-demo.s3-website-us-east-1.amazonaws.com/)
+that's tested and deployed on every push to the `master` branch of the [codebase](https://gitlab.com/blitzgren/gitlab-game-demo).
+This will also provide
+boilerplate code for starting a browser-based game with the following components:
+
+- Written in [Typescript](https://www.typescriptlang.org/) and [PhaserJs](https://phaser.io)
+- Building, running, and testing with [Gulp](http://gulpjs.com/)
+- Unit tests with [Chai](http://chaijs.com/) and [Mocha](https://mochajs.org/)
+- CI/CD with GitLab
+- Hosting the codebase on GitLab.com
+- Hosting the game on AWS
+- Deploying to AWS
+
+## Requirements and setup
+
+Please refer to my previous article [DevOps and Game Dev](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/) to learn the foundational
+development tools, running a Hello World-like game, and building this game using GitLab
+CI/CD from every new push to master. The `master` branch for this game's [repository](https://gitlab.com/blitzgren/gitlab-game-demo)
+contains a completed version with all configurations. If you would like to follow along
+with this article, you can clone and work from the `devops-article` branch:
+
+```sh
+git clone git@gitlab.com:blitzgren/gitlab-game-demo.git
+git checkout devops-article
+```
+
+Next, we'll create a small subset of tests that exemplify most of the states I expect
+this `Weapon` class to go through. To get started, create a folder called `lib/tests`
+and add the following code to a new file `weaponTests.ts`:
+
+```ts
+import { expect } from 'chai';
+import { Weapon, BulletFactory } from '../lib/weapon';
+
+describe('Weapon', () => {
+ var subject: Weapon;
+ var shotsFired: number = 0;
+ // Mocked bullet factory
+ var bulletFactory: BulletFactory = <BulletFactory>{
+ generate: function(px, py, vx, vy, rot) {
+ shotsFired++;
+ }
+ };
+ var parent: any = { x: 0, y: 0 };
+
+ beforeEach(() => {
+ shotsFired = 0;
+ subject = new Weapon(bulletFactory, parent, 0.25, 1);
+ });
+
+ it('should shoot if not in cooldown', () => {
+ subject.trigger(true);
+ subject.update(0.1);
+ expect(shotsFired).to.equal(1);
+ });
+
+ it('should not shoot during cooldown', () => {
+ subject.trigger(true);
+ subject.update(0.1);
+ subject.update(0.1);
+ expect(shotsFired).to.equal(1);
+ });
+
+ it('should shoot after cooldown ends', () => {
+ subject.trigger(true);
+ subject.update(0.1);
+ subject.update(0.3); // longer than timeout
+ expect(shotsFired).to.equal(2);
+ });
+
+ it('should not shoot if not triggered', () => {
+ subject.update(0.1);
+ subject.update(0.1);
+ expect(shotsFired).to.equal(0);
+ });
+});
+```
+
+To build and run these tests using gulp, let's also add the following gulp functions
+to the existing `gulpfile.js` file:
+
+```ts
+gulp.task('build-test', function () {
+ return gulp.src('src/tests/**/*.ts', { read: false })
+ .pipe(tap(function (file) {
+ // replace file contents with browserify's bundle stream
+ file.contents = browserify(file.path, { debug: true })
+ .plugin(tsify, { project: "./tsconfig.test.json" })
+ .bundle();
+ }))
+ .pipe(buffer())
+ .pipe(sourcemaps.init({loadMaps: true}) )
+ .pipe(gulp.dest('built/tests'));
+});
+
+gulp.task('run-test', function() {
+ gulp.src(['./built/tests/**/*.ts']).pipe(mocha());
+});
+```
+
+We will start implementing the first part of our game and get these `Weapon` tests to pass.
+The `Weapon` class will expose a method to trigger the generation of a bullet at a given
+direction and speed. Later we will implement a `Player` class that ties together the user input
+to trigger the weapon. In the `src/lib` folder create a `weapon.ts` file. We'll add two classes
+to it: `Weapon` and `BulletFactory` which will encapsulate Phaser's **sprite** and
+**group** objects, and the logic specific to our game.
+
+```ts
+export class Weapon {
+ private isTriggered: boolean = false;
+ private currentTimer: number = 0;
+
+ constructor(private bulletFactory: BulletFactory, private parent: Phaser.Sprite, private cooldown: number, private bulletSpeed: number) {
+ }
+
+ public trigger(on: boolean): void {
+ this.isTriggered = on;
+ }
+
+ public update(delta: number): void {
+ this.currentTimer -= delta;
+
+ if (this.isTriggered && this.currentTimer <= 0) {
+ this.shoot();
+ }
+ }
+
+ private shoot(): void {
+ // Reset timer
+ this.currentTimer = this.cooldown;
+
+ // Get velocity direction from player rotation
+ var parentRotation = this.parent.rotation + Math.PI / 2;
+ var velx = Math.cos(parentRotation);
+ var vely = Math.sin(parentRotation);
+
+ // Apply a small forward offset so bullet shoots from head of ship instead of the middle
+ var posx = this.parent.x - velx * 10
+ var posy = this.parent.y - vely * 10;
+
+ this.bulletFactory.generate(posx, posy, -velx * this.bulletSpeed, -vely * this.bulletSpeed, this.parent.rotation);
+ }
+}
+
+export class BulletFactory {
+
+ constructor(private bullets: Phaser.Group, private poolSize: number) {
+ // Set all the defaults for this BulletFactory's bullet object
+ this.bullets.enableBody = true;
+ this.bullets.physicsBodyType = Phaser.Physics.ARCADE;
+ this.bullets.createMultiple(30, 'bullet');
+ this.bullets.setAll('anchor.x', 0.5);
+ this.bullets.setAll('anchor.y', 0.5);
+ this.bullets.setAll('outOfBoundsKill', true);
+ this.bullets.setAll('checkWorldBounds', true);
+ }
+
+ public generate(posx: number, posy: number, velx: number, vely: number, rot: number): Phaser.Sprite {
+ // Pull a bullet from Phaser's Group pool
+ var bullet = this.bullets.getFirstExists(false);
+
+ // Set the few unique properties about this bullet: rotation, position, and velocity
+ if (bullet) {
+ bullet.reset(posx, posy);
+ bullet.rotation = rot;
+ bullet.body.velocity.x = velx;
+ bullet.body.velocity.y = vely;
+ }
+
+ return bullet;
+ }
+}
+```
+
+Lastly, we'll redo our entry point, `game.ts`, to tie together both `Player` and `Weapon` objects
+as well as add them to the update loop. Here is what the updated `game.ts` file looks like:
+
+```ts
+import { Player } from "./player";
+import { Weapon, BulletFactory } from "./weapon";
+
+window.onload = function() {
+ var game = new Phaser.Game(800, 600, Phaser.AUTO, 'gameCanvas', { preload: preload, create: create, update: update });
+ var player: Player;
+ var weapon: Weapon;
+
+ // Import all assets prior to loading the game
+ function preload () {
+ game.load.image('player', 'assets/player.png');
+ game.load.image('bullet', 'assets/bullet.png');
+ }
+
+ // Create all entities in the game, after Phaser loads
+ function create () {
+ // Create and position the player
+ var playerSprite = game.add.sprite(400, 550, 'player');
+ playerSprite.anchor.setTo(0.5);
+ player = new Player(game.input, playerSprite, 150);
+
+ var bulletFactory = new BulletFactory(game.add.group(), 30);
+ weapon = new Weapon(bulletFactory, player.sprite, 0.25, 1000);
+
+ player.loadWeapon(weapon);
+ }
+
+ // This function is called once every tick, default is 60fps
+ function update() {
+ var deltaSeconds = game.time.elapsedMS / 1000; // convert to seconds
+ player.update(deltaSeconds);
+ weapon.update(deltaSeconds);
+ }
+}
+```
+
+Run `gulp serve` and you can run around and shoot. Wonderful! Let's update our CI
+pipeline to include running the tests along with the existing build job.
+
+## Continuous Integration
+
+To ensure our changes don't break the build and all tests still pass, we utilize
+Continuous Integration (CI) to run these checks automatically for every push.
+Read through this article to understand [Continuous Integration, Continuous Delivery, and Continuous Deployment](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/),
+and how these methods are leveraged by GitLab.
+From the [last tutorial](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/) we already have a `gitlab-ci.yml` file set up for building our app from
+every push. We need to set up a new CI job for testing, which GitLab CI/CD will run after the build job using our generated artifacts from gulp.
+
+Please read through the [documentation on CI/CD configuration](../../../ci/yaml/README.md) file to explore its contents and adjust it to your needs.
+
+### Build your game with GitLab CI/CD
+
+We need to update our build job to ensure tests get run as well. Add `gulp build-test`
+to the end of the `script` array for the existing `build` job. Once these commands run,
+we know we will need to access everything in the `built` folder, given by GitLab CI/CD's `artifacts`.
+We'll also cache `node_modules` to avoid having to do a full re-pull of those dependencies:
+just pack them up in the cache. Here is the full `build` job:
+
+```yml
+build:
+ stage: build
+ script:
+ - npm i gulp -g
+ - npm i
+ - gulp
+ - gulp build-test
+ cache:
+ policy: push
+ paths:
+ - node_modules
+ artifacts:
+ paths:
+ - built
+```
+
+### Test your game with GitLab CI/CD
+
+For testing locally, we simply run `gulp run-tests`, which requires gulp to be installed
+globally like in the `build` job. We pull `node_modules` from the cache, so the `npm i`
+command won't have to do much. In preparation for deployment, we know we will still need
+the `built` folder in the artifacts, which will be brought over as default behavior from
+the previous job. Lastly, by convention, we let GitLab CI/CD know this needs to be run after
+the `build` job by giving it a `test` [stage](../../../ci/yaml/README.md#stages).
+Following the YAML structure, the `test` job should look like this:
+
+```yml
+test:
+ stage: test
+ script:
+ - npm i gulp -g
+ - npm i
+ - gulp run-test
+ cache:
+ policy: push
+ paths:
+ - node_modules/
+ artifacts:
+ paths:
+ - built/
+```
+
+We have added unit tests for a `Weapon` class that shoots on a specified interval.
+The `Player` class implements `Weapon` along with the ability to move around and shoot. Also,
+we've added test artifacts and a test stage to our GitLab CI/CD pipeline using `.gitlab-ci.yml`,
+allowing us to run our tests by every push.
+Our entire `.gitlab-ci.yml` file should now look like this:
+
+```yml
+image: node:6
+
+build:
+ stage: build
+ script:
+ - npm i gulp -g
+ - npm i
+ - gulp
+ - gulp build-test
+ cache:
+ policy: push
+ paths:
+ - node_modules/
+ artifacts:
+ paths:
+ - built/
+
+test:
+ stage: test
+ script:
+ - npm i gulp -g
+ - npm i
+ - gulp run-test
+ cache:
+ policy: pull
+ paths:
+ - node_modules/
+ artifacts:
+ paths:
+ - built/
+```
+
+### Run your CI/CD pipeline
+
+That's it! Add all your new files, commit, and push. For a reference of what our repo should
+look like at this point, please refer to the [final commit related to this article on my sample repository](https://gitlab.com/blitzgren/gitlab-game-demo/commit/8b36ef0ecebcf569aeb251be4ee13743337fcfe2).
+By applying both build and test stages, GitLab will run them sequentially at every push to
+our repository. If all goes well you'll end up with a green check mark on each job for the pipeline:
+
+![Passing Pipeline](img/test_pipeline_pass.png)
+
+You can confirm that the tests passed by clicking on the `test` job to enter the full build logs.
+Scroll to the bottom and observe, in all its passing glory:
+
+```sh
+$ gulp run-test
+[18:37:24] Using gulpfile /builds/blitzgren/gitlab-game-demo/gulpfile.js
+[18:37:24] Starting 'run-test'...
+[18:37:24] Finished 'run-test' after 21 ms
+
+
+ Weapon
+ ✓ should shoot if not in cooldown
+ ✓ should not shoot during cooldown
+ ✓ should shoot after cooldown ends
+ ✓ should not shoot if not triggered
+
+
+ 4 passing (18ms)
+
+Uploading artifacts...
+built/: found 17 matching files
+Uploading artifacts to coordinator... ok id=17095874 responseStatus=201 Created token=aaaaaaaa Job succeeded
+```
+
+## Continuous Deployment
+
+We have our codebase built and tested on every push. To complete the full pipeline with Continuous Deployment,
+let's set up [free web hosting with AWS S3](https://aws.amazon.com/s/dm/optimization/server-side-test/free-tier/free_np/) and a job through which our build artifacts get
+deployed. GitLab also has a free static site hosting service we could use, [GitLab Pages](https://about.gitlab.com/features/pages/),
+however Dark Nova specifically uses other AWS tools that necessitates using `AWS S3`.
+Read through this article that describes [deploying to both S3 and GitLab Pages](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/)
+and further delves into the principles of GitLab CI/CD than discussed in this article.
+
+### Set up S3 Bucket
+
+1. Log into your AWS account and go to [S3](https://console.aws.amazon.com/s3/home)
+1. Click the **Create Bucket** link at the top
+1. Enter a name of your choosing and click next
+1. Keep the default **Properties** and click next
+1. Click the **Manage group permissions** and allow **Read** for the **Everyone** group, click next
+1. Create the bucket, and select it in your S3 bucket list
+1. On the right side, click **Properties** and enable the **Static website hosting** category
+1. Update the radio button to the **Use this bucket to host a website** selection. Fill in `index.html` and `error.html` respectively
+
+### Set up AWS Secrets
+
+We need to be able to deploy to AWS with our AWS account credentials, but we certainly
+don't want to put secrets into source code. Luckily GitLab provides a solution for this
+with [Secret Variables](../../../ci/variables/README.md). This can get complicated
+due to [IAM](https://aws.amazon.com/iam/) management. As a best practice, you shouldn't
+use root security credentials. Proper IAM credential management is beyond the scope of this
+article, but AWS will remind you that using root credentials is unadvised and against their
+best practices, as they should. Feel free to follow best practices and use a custom IAM user's
+credentials, which will be the same two credentials (Key ID and Secret). It's a good idea to
+fully understand [IAM Best Practices in AWS](http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html). We need to add these credentials to GitLab:
+
+1. Log into your AWS account and go to the [Security Credentials page](https://console.aws.amazon.com/iam/home#/security_credential)
+1. Click the **Access Keys** section and **Create New Access Key**. Create the key and keep the id and secret around, you'll need them later
+ ![AWS Access Key Config](img/aws_config_window.png)
+1. Go to your GitLab project, click **Settings > CI/CD** on the left sidebar
+1. Expand the **Secret Variables** section
+ ![GitLab Secret Config](img/gitlab_config.png)
+1. Add a key named `AWS_KEY_ID` and copy the key id from Step 2 into the **Value** textbox
+1. Add a key named `AWS_KEY_SECRET` and copy the key secret from Step 2 into the **Value** textbox
+
+### Deploy your game with GitLab CI/CD
+
+To deploy our build artifacts, we need to install the [AWS CLI](https://aws.amazon.com/cli/) on
+the Shared Runner. The Shared Runner also needs to be able to authenticate with your AWS
+account to deploy the artifacts. By convention, AWS CLI will look for `AWS_ACCESS_KEY_ID`
+and `AWS_SECRET_ACCESS_KEY`. GitLab's CI gives us a way to pass the secret variables we
+set up in the prior section using the `variables` portion of the `deploy` job. At the end,
+we add directives to ensure deployment `only` happens on pushes to `master`. This way, every
+single branch still runs through CI, and only merging (or committing directly) to master will
+trigger the `deploy` job of our pipeline. Put these together to get the following:
+
+```yml
+deploy:
+ stage: deploy
+ variables:
+ AWS_ACCESS_KEY_ID: "$AWS_KEY_ID"
+ AWS_SECRET_ACCESS_KEY: "$AWS_KEY_SECRET"
+ script:
+ - apt-get update
+ - apt-get install -y python3-dev python3-pip
+ - easy_install3 -U pip
+ - pip3 install --upgrade awscli
+ - aws s3 sync ./built s3://gitlab-game-demo --region "us-east-1" --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --cache-control "no-cache, no-store, must-revalidate" --delete
+ only:
+ - master
+```
+
+Be sure to update the region and S3 URL in that last script command to fit your setup.
+Our final configuration file `.gitlab-ci.yml` looks like:
+
+```yml
+image: node:6
+
+build:
+ stage: build
+ script:
+ - npm i gulp -g
+ - npm i
+ - gulp
+ - gulp build-test
+ cache:
+ policy: push
+ paths:
+ - node_modules/
+ artifacts:
+ paths:
+ - built/
+
+test:
+ stage: test
+ script:
+ - npm i gulp -g
+ - gulp run-test
+ cache:
+ policy: pull
+ paths:
+ - node_modules/
+ artifacts:
+ paths:
+ - built/
+
+deploy:
+ stage: deploy
+ variables:
+ AWS_ACCESS_KEY_ID: "$AWS_KEY_ID"
+ AWS_SECRET_ACCESS_KEY: "$AWS_KEY_SECRET"
+ script:
+ - apt-get update
+ - apt-get install -y python3-dev python3-pip
+ - easy_install3 -U pip
+ - pip3 install --upgrade awscli
+ - aws s3 sync ./built s3://gitlab-game-demo --region "us-east-1" --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --cache-control "no-cache, no-store, must-revalidate" --delete
+ only:
+ - master
+```
+
+## Conclusion
+
+Within the [demo repository](https://gitlab.com/blitzgren/gitlab-game-demo) you can also find a handful of boilerplate code to get
+[Typescript](https://www.typescriptlang.org/), [Mocha](https://mochajs.org/), [Gulp](http://gulpjs.com/) and [Phaser](https://phaser.io) all playing
+together nicely with GitLab CI/CD, which is the result of lessons learned while making [Dark Nova](http://darknova.io/).
+Using a combination of free and open source software, we have a full CI/CD pipeline, a game foundation,
+and unit tests, all running and deployed at every push to master - with shockingly little code.
+Errors can be easily debugged through GitLab's build logs, and within minutes of a successful commit,
+you can see the changes live on your game.
+
+Setting up Continous Integration and Continuous Deployment from the start with Dark Nova enables
+rapid but stable development. We can easily test changes in a separate [environment](../../../ci/environments.md#introduction-to-environments-and-deployments),
+or multiple environments if needed. Balancing and updating a multiplayer game can be ongoing
+and tedious, but having faith in a stable deployment with GitLab CI/CD allows
+a lot of breathing room in quickly getting changes to players.
+
+## Further settings
+
+Here are some ideas to further investigate that can speed up or improve your pipeline:
+
+- [Yarn](https://yarnpkg.com) instead of npm
+- Setup a custom [Docker](../../../ci/docker/using_docker_images.md#define-image-and-services-from-gitlab-ci-yml) image that can preload dependencies and tools (like AWS CLI)
+- Forward a [custom domain](http://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html) to your game's S3 static website
+- Combine jobs if you find it unnecessary for a small project
+- Avoid the queues and set up your own [custom GitLab CI/CD runner](https://about.gitlab.com/2016/03/01/gitlab-runner-with-docker/)
diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md
index 03aa6ff8e7c..f879ed62010 100644
--- a/doc/ci/runners/README.md
+++ b/doc/ci/runners/README.md
@@ -163,8 +163,7 @@ in your `.gitlab-ci.yml`.
Behind the scenes, this works by increasing a counter in the database, and the
value of that counter is used to create the key for the cache. After a push, a
-new key is generated and the old cache is not valid anymore. Eventually, the
-Runner's garbage collector will remove it form the filesystem.
+new key is generated and the old cache is not valid anymore.
## How shared Runners pick jobs
diff --git a/doc/development/automatic_ce_ee_merge.md b/doc/development/automatic_ce_ee_merge.md
index cf6314f9521..a85e5b1b1cc 100644
--- a/doc/development/automatic_ce_ee_merge.md
+++ b/doc/development/automatic_ce_ee_merge.md
@@ -103,6 +103,99 @@ Notes:
- You can use [`git rerere`](https://git-scm.com/blog/2010/03/08/rerere.html)
to avoid resolving the same conflicts multiple times.
+### Cherry-picking from CE to EE
+
+For avoiding merge conflicts, we use a method of creating equivalent branches
+for CE and EE. If the `ee-compat-check` job fails, this process is required.
+
+This method only requires that you have cloned both CE and EE into your computer.
+If you don't have them yet, please go ahead and clone them:
+
+- Clone CE repo: `git clone git@gitlab.com:gitlab-org/gitlab-ce.git`
+- Clone EE repo: `git clone git@gitlab.com:gitlab-org/gitlab-ee.git`
+
+And the only additional setup we need is to add CE as remote of EE and vice-versa:
+
+- Open two terminal windows, one in CE, and another one in EE:
+ - In EE: `git remote add ce git@gitlab.com:gitlab-org/gitlab-ce.git`
+ - In CE: `git remote add ee git@gitlab.com:gitlab-org/gitlab-ee.git`
+
+That's all setup we need, so that we can cherry-pick a commit from CE to EE, and
+from EE to CE.
+
+Now, every time you create an MR for CE and EE:
+
+1. Open two terminal windows, one in CE, and another one in EE
+1. In the CE terminal:
+ 1. Create the CE branch, e.g., `branch-example`
+ 1. Make your changes and push a commit (commit A)
+ 1. Create the CE merge request in GitLab
+1. In the EE terminal:
+ 1. Create the EE-equivalent branch ending with `-ee`, e.g.,
+ `git checkout -b branch-example-ee`
+ 1. Fetch the CE branch: `git fetch ce branch-example`
+ 1. Cherry-pick the commit A: `git cherry-pick commit-A-SHA`
+ 1. If Git prompts you to fix the conflicts, do a `git status`
+ to check which files contain conflicts, fix them, save the files
+ 1. Add the changes with `git add .` but **DO NOT commit** them
+ 1. Continue cherry-picking: `git cherry-pick --continue`
+ 1. Push to EE: `git push origin branch-example-ee`
+1. Create the EE-equivalent MR and link to the CE MR from the
+description "Ports [CE-MR-LINK] to EE"
+1. Once all the jobs are passing in both CE and EE, you've addressed the
+feedback from your own team, and got them approved, the merge requests can be merged.
+1. When both MRs are ready, the EE merge request will be merged first, and the
+CE-equivalent will be merged next.
+
+**Important notes:**
+
+- The commit SHA can be easily found from the GitLab UI. From a merge request,
+open the tab **Commits** and click the copy icon to copy the commit SHA.
+- To cherry-pick a **commit range**, such as [A > B > C > D] use:
+
+ ```shell
+ git cherry-pick "oldest-commit-SHA^..newest-commit-SHA"
+ ```
+
+ For example, suppose the commit A is the oldest, and its SHA is `4f5e4018c09ed797fdf446b3752f82e46f5af502`,
+ and the commit D is the newest, and its SHA is `80e1c9e56783bd57bd7129828ec20b252ebc0538`.
+ The cherry-pick command will be:
+
+ ```shell
+ git cherry-pick "4f5e4018c09ed797fdf446b3752f82e46f5af502^..80e1c9e56783bd57bd7129828ec20b252ebc0538"
+ ```
+
+- To cherry-pick a **merge commit**, use the flag `-m 1`. For example, suppose that the
+merge commit SHA is `138f5e2f20289bb376caffa0303adb0cac859ce1`:
+
+ ```shell
+ git cherry-pick -m 1 138f5e2f20289bb376caffa0303adb0cac859ce1
+ ```
+- To cherry-pick multiple commits, such as B and D in a range [A > B > C > D], use:
+
+ ```shell
+ git cherry-pick commmit-B-SHA commit-D-SHA
+ ```
+
+ For example, suppose commit B SHA = `4f5e4018c09ed797fdf446b3752f82e46f5af502`,
+ and the commit D SHA = `80e1c9e56783bd57bd7129828ec20b252ebc0538`.
+ The cherry-pick command will be:
+
+ ```shell
+ git cherry-pick 4f5e4018c09ed797fdf446b3752f82e46f5af502 80e1c9e56783bd57bd7129828ec20b252ebc0538
+ ```
+
+ This case is particularly useful when you have a merge commit in a sequence of
+ commits and you want to cherry-pick all but the merge commit.
+
+- If you push more commits to the CE branch, you can safely repeat the procedure
+to cherry-pick them to the EE-equivalent branch. You can do that as many times as
+necessary, using the same CE and EE branches.
+- If you submitted the merge request to the CE repo and the `ee-compat-check` job passed,
+you are not required to submit the EE-equivalent MR, but it's still recommended. If the
+job failed, you are required to submit the EE MR so that you can fix the conflicts in EE
+before merging your changes into CE.
+
---
[Return to Development documentation](README.md)
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index c0ce49eb40b..856ef882453 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -45,7 +45,7 @@ We basically have 4 types of files:
1. Ruby files: basically Models and Controllers.
1. HAML files: these are the view files.
1. ERB files: used for email templates.
-1. JavaScript files: we mostly need to work with VUE JS templates.
+1. JavaScript files: we mostly need to work with Vue templates.
### Ruby files
diff --git a/doc/development/new_fe_guide/dependencies.md b/doc/development/new_fe_guide/dependencies.md
new file mode 100644
index 00000000000..3417d77a06d
--- /dev/null
+++ b/doc/development/new_fe_guide/dependencies.md
@@ -0,0 +1,3 @@
+# Dependencies
+
+> TODO: Add Dependencies \ No newline at end of file
diff --git a/doc/development/new_fe_guide/development/accessibility.md b/doc/development/new_fe_guide/development/accessibility.md
new file mode 100644
index 00000000000..ed35f08432f
--- /dev/null
+++ b/doc/development/new_fe_guide/development/accessibility.md
@@ -0,0 +1,3 @@
+# Accessibility
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/components.md b/doc/development/new_fe_guide/development/components.md
new file mode 100644
index 00000000000..637099d1e83
--- /dev/null
+++ b/doc/development/new_fe_guide/development/components.md
@@ -0,0 +1,3 @@
+# Components
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/design_patterns.md b/doc/development/new_fe_guide/development/design_patterns.md
new file mode 100644
index 00000000000..ee06566ed30
--- /dev/null
+++ b/doc/development/new_fe_guide/development/design_patterns.md
@@ -0,0 +1,3 @@
+# Design patterns
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/index.md b/doc/development/new_fe_guide/development/index.md
new file mode 100644
index 00000000000..cee8e43ebad
--- /dev/null
+++ b/doc/development/new_fe_guide/development/index.md
@@ -0,0 +1,29 @@
+# Development
+
+## [Design patterns](design_patterns.md)
+
+Examples of proven design patterns used in our codebase.
+
+## [Components](components.md)
+
+Documentation on existing components and how to best create a new component.
+
+## [Accessibility](accessibility.md)
+
+Learn how to implement an accessible frontend.
+
+## [Network requests](network_requests.md)
+
+Learn how to handle network requests in our codebase.
+
+## [Security](security.md)
+
+Learn how to ensure that our frontend is secure.
+
+## [Performance](performance.md)
+
+Learn how to keep our frontend performant.
+
+## [Testing](testing.md)
+
+Learn how to keep our frontend tested.
diff --git a/doc/development/new_fe_guide/development/network_requests.md b/doc/development/new_fe_guide/development/network_requests.md
new file mode 100644
index 00000000000..047c00313bc
--- /dev/null
+++ b/doc/development/new_fe_guide/development/network_requests.md
@@ -0,0 +1,3 @@
+# Network requests
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/performance.md b/doc/development/new_fe_guide/development/performance.md
new file mode 100644
index 00000000000..26b07874f0f
--- /dev/null
+++ b/doc/development/new_fe_guide/development/performance.md
@@ -0,0 +1,3 @@
+# Performance
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/security.md b/doc/development/new_fe_guide/development/security.md
new file mode 100644
index 00000000000..debda7de0c6
--- /dev/null
+++ b/doc/development/new_fe_guide/development/security.md
@@ -0,0 +1,3 @@
+# Security
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/development/testing.md b/doc/development/new_fe_guide/development/testing.md
new file mode 100644
index 00000000000..c359bd83ed1
--- /dev/null
+++ b/doc/development/new_fe_guide/development/testing.md
@@ -0,0 +1,3 @@
+# Testing
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/index.md b/doc/development/new_fe_guide/index.md
new file mode 100644
index 00000000000..08c6a266e7f
--- /dev/null
+++ b/doc/development/new_fe_guide/index.md
@@ -0,0 +1,28 @@
+# Frontend Development Guidelines
+
+This guide contains all the information to successfully contribute to GitLab's frontend.
+This is a living document, and we welcome contributions, feedback and suggestions.
+
+## [Principles](principles.md)
+
+Ensure that your frontend contribution starts off in the right direction.
+
+## [Initiatives](initiatives.md)
+
+High level overview of where we are going from a frontend perspective.
+
+## [Development](development/index.md)
+
+Guidance on topics related to development.
+
+## [Dependencies](dependencies.md)
+
+Learn about all the dependencies that make up our frontend, including some of our own custom built libraries.
+
+## [Style](style/index.md)
+
+Style guides to keep our code consistent.
+
+## [Tips](tips.md)
+
+Tips from our frontend team to develop more efficiently and effectively.
diff --git a/doc/development/new_fe_guide/initiatives.md b/doc/development/new_fe_guide/initiatives.md
new file mode 100644
index 00000000000..c81ed3579f0
--- /dev/null
+++ b/doc/development/new_fe_guide/initiatives.md
@@ -0,0 +1,3 @@
+# Initiatives
+
+> TODO: Add Initiatives
diff --git a/doc/development/new_fe_guide/principles.md b/doc/development/new_fe_guide/principles.md
new file mode 100644
index 00000000000..2126d202a7e
--- /dev/null
+++ b/doc/development/new_fe_guide/principles.md
@@ -0,0 +1,3 @@
+# Principles
+
+> TODO: Add principles
diff --git a/doc/development/new_fe_guide/style/html.md b/doc/development/new_fe_guide/style/html.md
new file mode 100644
index 00000000000..5489def5d6e
--- /dev/null
+++ b/doc/development/new_fe_guide/style/html.md
@@ -0,0 +1,3 @@
+# HTML style guide
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/style/index.md b/doc/development/new_fe_guide/style/index.md
new file mode 100644
index 00000000000..d2d576b3b46
--- /dev/null
+++ b/doc/development/new_fe_guide/style/index.md
@@ -0,0 +1,9 @@
+# Style
+
+## [HTML style guide](html.md)
+
+## [SCSS style guide](scss.md)
+
+## [JavaScript style guide](javascript.md)
+
+## [Vue style guide](vue.md)
diff --git a/doc/development/new_fe_guide/style/javascript.md b/doc/development/new_fe_guide/style/javascript.md
new file mode 100644
index 00000000000..480d50a211f
--- /dev/null
+++ b/doc/development/new_fe_guide/style/javascript.md
@@ -0,0 +1,3 @@
+# JavaScript style guide
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/style/scss.md b/doc/development/new_fe_guide/style/scss.md
new file mode 100644
index 00000000000..6f5e818d7db
--- /dev/null
+++ b/doc/development/new_fe_guide/style/scss.md
@@ -0,0 +1,3 @@
+# SCSS style guide
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/style/vue.md b/doc/development/new_fe_guide/style/vue.md
new file mode 100644
index 00000000000..fd9353e0d3f
--- /dev/null
+++ b/doc/development/new_fe_guide/style/vue.md
@@ -0,0 +1,3 @@
+# Vue style guide
+
+> TODO: Add content
diff --git a/doc/development/new_fe_guide/tips.md b/doc/development/new_fe_guide/tips.md
new file mode 100644
index 00000000000..f0cdf52d618
--- /dev/null
+++ b/doc/development/new_fe_guide/tips.md
@@ -0,0 +1,3 @@
+# Tips
+
+> TODO: Add tips
diff --git a/doc/development/writing_documentation.md b/doc/development/writing_documentation.md
index 403c9d08752..40c21e5355c 100644
--- a/doc/development/writing_documentation.md
+++ b/doc/development/writing_documentation.md
@@ -19,7 +19,7 @@ The one responsible for writing the first piece of documentation is the develope
wrote the code. It's the job of the Product Manager to ensure all features are
shipped with its docs, whether is a small or big change. At the pace GitLab evolves,
this is the only way to keep the docs up-to-date. If you have any questions about it,
-please ask a Technical Writer. Otherwise, when your content is ready, assign one of
+ask a Technical Writer. Otherwise, when your content is ready, assign one of
them to review it for you.
We use the [monthly release blog post](https://about.gitlab.com/handbook/marketing/blog/release-posts/#monthly-releases) as a changelog checklist to ensure everything
@@ -27,6 +27,8 @@ is documented.
Whenever you submit a merge request for the documentation, use the documentation MR description template.
+Please check the [documentation workflow](https://about.gitlab.com/handbook/product/technical-writing/workflow/) before getting started.
+
### Documentation directory structure
The documentation is structured based on the GitLab UI structure itself,
@@ -40,7 +42,7 @@ all docs should be linked. Every new document should be cross-linked to its rela
The directories `/workflow/`, `/gitlab-basics/`, `/university/`, and `/articles/` have
been deprecated and the majority their docs have been moved to their correct location
-in small iterations. Please don't create new docs in these folders.
+in small iterations. Don't create new docs in these folders.
To move a document from its location to another directory, read the section
[changing document location](doc_styleguide.md#changing-document-location) of the doc style guide.
@@ -116,6 +118,49 @@ choices:
If your branch name matches any of the above, it will run only the docs
tests. If it doesn't, the whole test suite will run (including docs).
+### Merge requests for GitLab documentation
+
+Before getting started, make sure you read the introductory section
+"[contributing to docs](#contributing-to-docs)" above and the
+[tech writing workflow](https://about.gitlab.com/handbook/product/technical-writing/workflow/)
+for GitLab Team members.
+
+- Use the current [merge request description template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/merge_request_templates/Documentation.md)
+- Use the correct [branch name](#branch-naming)
+- Label the MR `Documentation`
+- Assign the correct milestone (see note below)
+
+
+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
+it increases the work of the release managers.
+
+#### Cherry-picking from CE to EE
+
+As we have the `master` branch of CE merged into EE once a day, it's common to
+run into merge conflicts. To avoid them, we [test for merge conflicts against EE](#testing)
+with the `ee-compat-check` job, and use the following method of creating equivalent
+branches for CE and EE.
+
+Follow this [method for cherry-picking from CE to EE](automatic_ce_ee_merge.md#cherry-picking-from-ce-to-ee), with a few adjustments:
+
+- Create the [CE branch](#branch-naming) starting with `docs-`,
+ e.g.: `git checkout -b docs-example`
+- Create the EE-equivalent branch ending with `-ee`, e.g.,
+ `git checkout -b docs-example-ee`
+- Once all the jobs are passing in CE and EE, and you've addressed the
+feedback from your own team, assign the CE MR to a technical writer for review
+- When both MRs are ready, the EE merge request will be merged first, and the
+CE-equivalent will be merged next.
+- Note that the review will occur only in the CE MR, as the EE MR
+contains the same commits as the CE MR.
+- If you have a few more changes that apply to the EE-version only, you can submit
+a couple more commits to the EE branch, but ask the reviewer to review the EE merge request
+additionally to the CE MR. If there are many EE-only changes though, start a new MR
+to EE only.
+
### Previewing the changes live
If you want to preview the doc changes of your merge request live, you can use
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 170d92faa09..6eb767b00b3 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -299,9 +299,9 @@ sudo usermod -aG redis git
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-5-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-6-stable gitlab
-**Note:** You can change `10-5-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `10-6-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index b2c9177e6eb..1f2b4d9d3d9 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -137,6 +137,14 @@ CREATE EXTENSION pg_trgm;
On some systems you may need to install an additional package (e.g.
`postgresql-contrib`) for this extension to become available.
+#### Additional requirements for GitLab Geo
+
+If you are using [GitLab Geo](https://docs.gitlab.com/ee/development/geo.html), the [tracking database](https://docs.gitlab.com/ee/development/geo.html#geo-tracking-database) also requires the `postgres_fdw` extension.
+
+```
+CREATE EXTENSION postgres_fdw;
+```
+
## Unicorn Workers
It's possible to increase the amount of unicorn workers and this will usually help to reduce the response time of the applications and increase the ability to handle parallel requests.
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 5f5ba2b69bc..ec091549c05 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -309,6 +309,18 @@ enable them.
You can make use of [environment variables](#helm-chart-variables) to automatically
scale your pod replicas.
+It's important to note that when a project is deployed to a Kubernetes cluster,
+it relies on a Docker image that has been pushed to the
+[GitLab Container Registry](../../user/project/container_registry.md). Kubernetes
+fetches this image and uses it to run the application. If the project is public,
+the image can be accessed by Kubernetes without any authentication, allowing us
+to have deployments more usable. If the project is private/internal, the
+Registry requires credentials to pull the image. Currently, this is addressed
+by providing `CI_JOB_TOKEN` as the password that can be used, but this token will
+no longer be valid as soon as the deployment job finishes. This means that
+Kubernetes can run the application, but in case it should be restarted or
+executed somewhere else, it cannot be accessed again.
+
### Auto Monitoring
NOTE: **Note:**
diff --git a/doc/update/10.5-to-10.6.md b/doc/update/10.5-to-10.6.md
new file mode 100644
index 00000000000..af8343b5958
--- /dev/null
+++ b/doc/update/10.5-to-10.6.md
@@ -0,0 +1,361 @@
+---
+comments: false
+---
+
+# From 10.5 to 10.6
+
+Make sure you view this update guide from the tag (version) of GitLab you would
+like to install. In most cases this should be the highest numbered production
+tag (without rc in it). You can select the tag in the version dropdown at the
+top left corner of GitLab (below the menu bar).
+
+If the highest number stable branch is unclear please check the
+[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
+guide links by version.
+
+### 1. Stop server
+
+```bash
+sudo service gitlab stop
+```
+
+### 2. Backup
+
+NOTE: If you installed GitLab from source, make sure `rsync` is installed.
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 3. Update Ruby
+
+NOTE: GitLab 9.0 and higher only support Ruby 2.3.x and dropped support for Ruby 2.1.x. Be
+sure to upgrade your interpreter if necessary.
+
+You can check which version you are running with `ruby -v`.
+
+Download and compile Ruby:
+
+```bash
+mkdir /tmp/ruby && cd /tmp/ruby
+curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.6.tar.gz
+echo '4e6a0f828819e15d274ae58485585fc8b7caace0 ruby-2.3.6.tar.gz' | shasum -c - && tar xzf ruby-2.3.6.tar.gz
+cd ruby-2.3.6
+./configure --disable-install-rdoc
+make
+sudo make install
+```
+
+Install Bundler:
+
+```bash
+sudo gem install bundler --no-ri --no-rdoc
+```
+
+### 4. Update Node
+
+GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets.
+We require a minimum version of node v6.0.0.
+
+You can check which version you are running with `node -v`. If you are running
+a version older than `v6.0.0` you will need to update to a newer version. You
+can find instructions to install from community maintained packages or compile
+from source at the nodejs.org website.
+
+<https://nodejs.org/en/download/>
+
+Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage
+JavaScript dependencies.
+
+```bash
+curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+sudo apt-get update
+sudo apt-get install yarn
+```
+
+More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install).
+
+### 5. Update Go
+
+NOTE: GitLab 9.2 and higher only supports Go 1.8.3 and dropped support for Go
+1.5.x through 1.7.x. Be sure to upgrade your installation if necessary.
+
+You can check which version you are running with `go version`.
+
+Download and install Go:
+
+```bash
+# Remove former Go installation folder
+sudo rm -rf /usr/local/go
+
+curl --remote-name --progress https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz
+echo '1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772 go1.8.3.linux-amd64.tar.gz' | shasum -a256 -c - && \
+ sudo tar -C /usr/local -xzf go1.8.3.linux-amd64.tar.gz
+sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/
+rm go1.8.3.linux-amd64.tar.gz
+```
+
+### 6. Get latest code
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+sudo -u git -H git checkout -- locale
+```
+
+For GitLab Community Edition:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git checkout 10-6-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git checkout 10-6-stable-ee
+```
+
+### 7. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_SHELL_VERSION)
+sudo -u git -H bin/compile
+```
+
+### 8. Update gitlab-workhorse
+
+Install and compile gitlab-workhorse. GitLab-Workhorse uses
+[GNU Make](https://www.gnu.org/software/make/).
+If you are not using Linux you may have to run `gmake` instead of
+`make` below.
+
+```bash
+cd /home/git/gitlab-workhorse
+
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_WORKHORSE_VERSION)
+sudo -u git -H make
+```
+
+### 9. Update Gitaly
+
+#### New Gitaly configuration options required
+
+In order to function Gitaly needs some additional configuration information. Below we assume you installed Gitaly in `/home/git/gitaly` and GitLab Shell in `/home/git/gitlab-shell`.
+
+```shell
+echo '
+[gitaly-ruby]
+dir = "/home/git/gitaly/ruby"
+
+[gitlab-shell]
+dir = "/home/git/gitlab-shell"
+' | sudo -u git tee -a /home/git/gitaly/config.toml
+```
+
+#### Check Gitaly configuration
+
+Due to a bug in the `rake gitlab:gitaly:install` script your Gitaly
+configuration file may contain syntax errors. The block name
+`[[storages]]`, which may occur more than once in your `config.toml`
+file, should be `[[storage]]` instead.
+
+```shell
+sudo -u git -H sed -i.pre-10.1 's/\[\[storages\]\]/[[storage]]/' /home/git/gitaly/config.toml
+```
+
+#### Compile Gitaly
+
+```shell
+cd /home/git/gitaly
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION)
+sudo -u git -H make
+```
+
+### 10. Update MySQL permissions
+
+If you are using MySQL you need to grant the GitLab user the necessary
+permissions on the database:
+
+```bash
+mysql -u root -p -e "GRANT TRIGGER ON \`gitlabhq_production\`.* TO 'git'@'localhost';"
+```
+
+If you use MySQL with replication, or just have MySQL configured with binary logging,
+you will need to also run the following on all of your MySQL servers:
+
+```bash
+mysql -u root -p -e "SET GLOBAL log_bin_trust_function_creators = 1;"
+```
+
+You can make this setting permanent by adding it to your `my.cnf`:
+
+```
+log_bin_trust_function_creators=1
+```
+
+### 11. Update configuration files
+
+#### New configuration options for `gitlab.yml`
+
+There might be configuration options available for [`gitlab.yml`][yaml]. View them with the command below and apply them manually to your current `gitlab.yml`:
+
+```sh
+cd /home/git/gitlab
+
+git diff origin/10-5-stable:config/gitlab.yml.example origin/10-6-stable:config/gitlab.yml.example
+```
+
+#### Nginx configuration
+
+Ensure you're still up-to-date with the latest NGINX configuration changes:
+
+```sh
+cd /home/git/gitlab
+
+# For HTTPS configurations
+git diff origin/10-5-stable:lib/support/nginx/gitlab-ssl origin/10-6-stable:lib/support/nginx/gitlab-ssl
+
+# For HTTP configurations
+git diff origin/10-5-stable:lib/support/nginx/gitlab origin/10-6-stable:lib/support/nginx/gitlab
+```
+
+If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx
+configuration as GitLab application no longer handles setting it.
+
+If you are using Apache instead of NGINX please see the updated [Apache templates].
+Also note that because Apache does not support upstreams behind Unix sockets you
+will need to let gitlab-workhorse listen on a TCP port. You can do this
+via [/etc/default/gitlab].
+
+[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
+[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-6-stable/lib/support/init.d/gitlab.default.example#L38
+
+#### SMTP configuration
+
+If you're installing from source and use SMTP to deliver mail, you will need to add the following line
+to config/initializers/smtp_settings.rb:
+
+```ruby
+ActionMailer::Base.delivery_method = :smtp
+```
+
+See [smtp_settings.rb.sample] as an example.
+
+[smtp_settings.rb.sample]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-6-stable/config/initializers/smtp_settings.rb.sample#L13
+
+#### Init script
+
+There might be new configuration options available for [`gitlab.default.example`][gl-example]. View them with the command below and apply them manually to your current `/etc/default/gitlab`:
+
+```sh
+cd /home/git/gitlab
+
+git diff origin/10-5-stable:lib/support/init.d/gitlab.default.example origin/10-6-stable:lib/support/init.d/gitlab.default.example
+```
+
+Ensure you're still up-to-date with the latest init script changes:
+
+```bash
+cd /home/git/gitlab
+
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+For Ubuntu 16.04.1 LTS:
+
+```bash
+sudo systemctl daemon-reload
+```
+
+### 12. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without postgres')
+sudo -u git -H bundle install --without postgres development test --deployment
+
+# PostgreSQL installations (note: the line below states '--without mysql')
+sudo -u git -H bundle install --without mysql development test --deployment
+
+# Optional: clean up old gems
+sudo -u git -H bundle clean
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Compile GetText PO files
+
+sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
+
+# Update node dependencies and recompile assets
+sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
+
+# Clean up cache
+sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
+```
+
+**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md).
+
+### 13. Start application
+
+```bash
+sudo service gitlab start
+sudo service nginx restart
+```
+
+### 14. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+```
+
+To make sure you didn't miss anything run a more thorough check:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+```
+
+If all items are green, then congratulations, the upgrade is complete!
+
+## Things went south? Revert to previous version (10.5)
+
+### 1. Revert the code to the previous version
+
+Follow the [upgrade guide from 10.4 to 10.5](10.4-to-10.5.md), except for the
+database migration (the backup is already migrated to the previous version).
+
+### 2. Restore from the backup
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+
+If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
+
+[yaml]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-6-stable/config/gitlab.yml.example
+[gl-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-6-stable/lib/support/init.d/gitlab.default.example
diff --git a/doc/user/admin_area/settings/img/update-available.png b/doc/user/admin_area/settings/img/update-available.png
new file mode 100644
index 00000000000..0dafdad618e
--- /dev/null
+++ b/doc/user/admin_area/settings/img/update-available.png
Binary files differ
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index d874688cc29..381efdf5d67 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -8,20 +8,26 @@ under **Admin area > Settings > Usage statistics**.
## Version check
-GitLab can inform you when an update is available and the importance of it.
+If enabled, version check will inform you if a new version is available and the
+importance of it through a status. This is shown on the help page (i.e. `/help`)
+for all signed in users, and on the admin pages. The statuses are:
-No information other than the GitLab version and the instance's hostname (through the HTTP referer)
-are collected.
+* Green: You are running the latest version of GitLab.
+* Orange: An updated version of GitLab is available.
+* Red: The version of GitLab you are running is vulnerable. You should install
+ the latest version with security fixes as soon as possible.
-In the **Overview** tab you can see if your GitLab version is up to date. There
-are three cases: 1) you are up to date (green), 2) there is an update available
-(yellow) and 3) your version is vulnerable and a security fix is released (red).
+![Orange version check example](img/update-available.png)
-In any case, you will see a message informing you of the state and the
-importance of the update.
+GitLab Inc. collects your instance's version and hostname (through the HTTP
+referer) as part of the version check. No other information is collected.
-If enabled, the version status will also be shown in the help page (`/help`)
-for all signed in users.
+This information is used, among other things, to identify to which versions
+patches will need to be back ported, making sure active GitLab instances remain
+secure.
+
+If you disable version check, this information will not be collected. Enable or
+disable the version check at **Admin area > Settings > Usage statistics**.
## Usage ping
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 914a80bcd6a..a520279c29e 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -25,7 +25,8 @@ The following table depicts the various user permission levels in a project.
| Create confidential issue | ✓ [^1] | ✓ | ✓ | ✓ | ✓ |
| View confidential issues | (✓) [^2] | ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ [^1] | ✓ | ✓ | ✓ | ✓ |
-| Lock discussions (issues and merge requests) | | | | ✓ | ✓ |
+| Lock issue discussions | | ✓ | ✓ | ✓ | ✓ |
+| Lock merge request discussions | | | ✓ | ✓ | ✓ |
| See a list of jobs | ✓ [^3] | ✓ | ✓ | ✓ | ✓ |
| See a job log | ✓ [^3] | ✓ | ✓ | ✓ | ✓ |
| Download and browse job artifacts | ✓ [^3] | ✓ | ✓ | ✓ | ✓ |
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 4ac54f96aa2..661697aaeb7 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -109,6 +109,41 @@ you will be notified.
You can now proceed to install some pre-defined applications and then
enable the Kubernetes cluster integration.
+## Security implications
+
+CAUTION: **Important:**
+The whole cluster security is based on a model where [developers](../../permissions.md)
+are trusted, so **only trusted users should be allowed to control your clusters**.
+
+The default cluster configuration grants access to a wide set of
+functionalities needed to successfully build and deploy a containerized
+application. Bare in mind that the same credentials are used for all the
+applications running on the cluster.
+
+When GitLab creates the cluster, it enables and uses the legacy
+[Attribute-based access control (ABAC)](https://kubernetes.io/docs/admin/authorization/abac/).
+The newer [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)
+authorization will be supported in a
+[future release](https://gitlab.com/gitlab-org/gitlab-ce/issues/29398).
+
+### Security of GitLab Runners
+
+GitLab Runners have the [privileged mode](https://docs.gitlab.com/runner/executors/docker.html#the-privileged-mode)
+enabled by default, which allows them to execute special commands and running
+Docker in Docker. This functionality is needed to run some of the [Auto DevOps]
+jobs. This implies the containers are running in privileged mode and you should,
+therefore, be aware of some important details.
+
+The privileged flag gives all capabilities to the running container, which in
+turn can do almost everything that the host can do. Be aware of the
+inherent security risk associated with performing `docker run` operations on
+arbitrary images as they effectively have root access.
+
+If you don't want to use GitLab Runner in privileged mode, first make sure that
+you don't have it installed via the applications, and then use the
+[Runner's Helm chart](../../../install/kubernetes/gitlab_runner_chart.md) to
+install it manually.
+
## Installing applications
GitLab provides a one-click install for various applications which will be
@@ -118,16 +153,16 @@ added directly to your configured cluster. Those applications are needed for
| Application | GitLab version | Description |
| ----------- | :------------: | ----------- |
| [Helm Tiller](https://docs.helm.sh/) | 10.2+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It will be automatically installed as a dependency when you try to install a different app. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. |
-| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. 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. |
+| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps] or deploy your own web apps. |
| [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications |
-| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab 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](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. |
+| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab 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](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. |
## Getting the external IP address
NOTE: **Note:**
You need a load balancer installed in your cluster in order to obtain the
external IP address with the following procedure. It can be deployed using the
-[**Ingress** application](#installing-appplications).
+[**Ingress** application](#installing-applications).
In order to publish your web application, you first need to find the external IP
address associated to your load balancer.
@@ -329,3 +364,4 @@ the deployment variables above, ensuring any pods you create are labelled with
[permissions]: ../../permissions.md
[ee]: https://about.gitlab.com/products/
+[Auto DevOps]: ../../../topics/autodevops/index.md
diff --git a/doc/user/project/import/img/import_projects_from_repo_url.png b/doc/user/project/import/img/import_projects_from_repo_url.png
new file mode 100644
index 00000000000..ec867da1087
--- /dev/null
+++ b/doc/user/project/import/img/import_projects_from_repo_url.png
Binary files differ
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index e2b285678c3..72cc58546b7 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -10,6 +10,7 @@
1. [From Perforce](perforce.md)
1. [From SVN](svn.md)
1. [From TFS](tfs.md)
+1. [From repo by URL](repo_by_url.md)
In addition to the specific migration documentation above, you can import any
Git repository via HTTP from the New Project page. Be aware that if the
diff --git a/doc/user/project/import/perforce.md b/doc/user/project/import/perforce.md
index aa7508e1e8e..a1ea716b606 100644
--- a/doc/user/project/import/perforce.md
+++ b/doc/user/project/import/perforce.md
@@ -48,3 +48,9 @@ Here's a few links to get you started:
- [git-p4 manual page](https://www.kernel.org/pub/software/scm/git/docs/git-p4.html)
- [git-p4 example usage](https://git.wiki.kernel.org/index.php/Git-p4_Usage)
- [Git book migration guide](https://git-scm.com/book/en/v2/Git-and-Other-Systems-Migrating-to-Git#_perforce_import)
+
+Note that `git p4` and `git filter-branch` are not very good at
+creating small and efficient Git pack files. So it might be a good
+idea to spend time and CPU to properly repack your repository before
+sending it for the first time to your GitLab server. See
+[this StackOverflow question](https://stackoverflow.com/questions/28720151/git-gc-aggressive-vs-git-repack/).
diff --git a/doc/user/project/import/repo_by_url.md b/doc/user/project/import/repo_by_url.md
new file mode 100644
index 00000000000..f43e384de88
--- /dev/null
+++ b/doc/user/project/import/repo_by_url.md
@@ -0,0 +1,12 @@
+# Import project from repo by URL
+
+You can import your existing repositories by providing the Git URL:
+
+1. From your GitLab dashboard click **New project**
+1. Switch to the **Import project** tab
+1. Click on the **Repo by URL** button
+1. Fill in the "Git repository URL" and the remaining project fields
+1. Click **Create project** to being 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)
diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md
index 02adc562028..8ac753c07bf 100644
--- a/doc/user/project/integrations/prometheus_library/kubernetes.md
+++ b/doc/user/project/integrations/prometheus_library/kubernetes.md
@@ -13,21 +13,18 @@ integration services must be enabled.
| Name | Query |
| ---- | ----- |
-| Average Memory Usage (MB) | (sum(avg(container_memory_usage_bytes{container_name!="POD",environment="%{ci_environment_slug}"}) without (job))) / count(avg(container_memory_usage_bytes{container_name!="POD",environment="%{ci_environment_slug}"}) without (job)) /1024/1024 |
-| Average CPU Utilization (%) | sum(avg(rate(container_cpu_usage_seconds_total{container_name!="POD",environment="%{ci_environment_slug}"}[2m])) without (job)) * 100 |
+| Average Memory Usage (MB) | 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 |
+| Average CPU Utilization (%) | avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name)) |
-## Configuring Prometheus to monitor for Kubernetes node metrics
+## Configuring Prometheus to monitor for Kubernetes metrics
-In order for Prometheus to collect Kubernetes metrics, you first must have a
-Prometheus server up and running. You have two options here:
+Prometheus needs to be deployed into the cluster and configured properly in order to gather Kubernetes metrics. GitLab supports two methods for doing so:
-- If you have an Omnibus based GitLab installation within your Kubernetes cluster, you can leverage the bundled Prometheus server to [monitor Kubernetes](../../../../administration/monitoring/prometheus/index.md#configuring-prometheus-to-monitor-kubernetes).
-- To configure your own Prometheus server, you can follow the [Prometheus documentation](https://prometheus.io/docs/introduction/overview/) or [our guide](../../../../administration/monitoring/prometheus/index.md#configuring-your-own-prometheus-server-within-kubernetes).
+- GitLab [integrates with Kubernetes](../../clusters/index.md), and can [deploy Prometheus into a connected cluster](../prometheus.html#managed-prometheus-on-kubernetes). It is automatically configured to collect Kubernetes metrics.
+- To configure your own Prometheus server, you can follow the [Prometheus documentation](https://prometheus.io/docs/introduction/overview/).
## Specifying the Environment
In order to isolate and only display relevant CPU and Memory metrics for a given environment, GitLab needs a method to detect which containers it is running. Because these metrics are tracked at the container level, traditional Kubernetes labels are not available.
Instead, the [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) name should begin with [CI_ENVIRONMENT_SLUG](../../../../ci/variables/README.md#predefined-variables-environment-variables). It can be followed by a `-` and additional content if desired. For example, a deployment name of `review-homepage-5620p5` would match the `review/homepage` environment.
-
-If you are using [GitLab Auto-Deploy](../../../../ci/autodeploy/index.md) and one of the two [provided Kubernetes monitoring solutions](../prometheus.md#getting-started-with-prometheus-monitoring), the `environment` label will be automatically added.
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index bc6306927e1..d403d5698a9 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -235,6 +235,27 @@ to another list the label changes and a system not is recorded.
[Developers and up](../permissions.md) can use all the functionality of the
Issue Board, that is create/delete lists and drag issues around.
+## Group Issue Board
+
+>Introduced in GitLab 10.6
+
+Group issue board is analogous to project-level issue board and it is accessible at the group
+navigation level. A group-level issue board allows you to view all issues from all projects in that group
+(currently, it does not see issues from projects in 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.
+
+## Features per tier
+
+Different issue board features are available in different [GitLab tiers](https://about.gitlab.com/pricing/), as shown in the following table:
+
+| Tier | Number of project issue boards | Board with configuration in project issue boards | Number of group issue boards | Board with configuration in group issue boards |
+| --- | --- | --- | --- | --- |
+| Libre | 1 | No | 1 | No |
+| Starter | Multiple | Yes | 1 | No |
+| Premium | Multiple | Yes | Multiple | Yes |
+| Ultimate | Multiple | Yes | Multiple | Yes |
+
## Tips
A few things to remember:
diff --git a/doc/user/project/members/share_project_with_groups.md b/doc/user/project/members/share_project_with_groups.md
index f5c748a03b3..5d819998dd9 100644
--- a/doc/user/project/members/share_project_with_groups.md
+++ b/doc/user/project/members/share_project_with_groups.md
@@ -16,19 +16,29 @@ say 'Project Acme', in GitLab is to make the 'Engineering' group the owner of 'P
Acme'. But what if 'Project Acme' already belongs to another group, say 'Open Source'?
This is where the group sharing feature can be of use.
-To share 'Project Acme' with the 'Engineering' group, go to the project settings page for 'Project Acme' and use the left navigation menu to go to the **Settings > Members** section.
+To share 'Project Acme' with the 'Engineering' group:
-![share project with groups](img/share_project_with_groups.png)
+1. For 'Project Acme' use the left navigation menu to go to **Settings > Members**
-Then select the 'Share with group' tab by clicking it.
+ ![share project with groups](img/share_project_with_groups.png)
-Now you can add the 'Engineering' group with the maximum access level of your choice. Click 'Share' to share it.
+1. Select the 'Share with group' tab
+1. Add the 'Engineering' group with the maximum access level of your choice
+1. Click **Share** to share it
-![share project with groups tab](img/share_project_with_groups_tab.png)
+ ![share project with groups tab](img/share_project_with_groups_tab.png)
-After sharing 'Project Acme' with 'Engineering', the project will be listed on the group dashboard.
+1. After sharing 'Project Acme' with 'Engineering', the project will be listed
+ on the group dashboard
-!['Project Acme' is listed as a shared project for 'Engineering'](img/other_group_sees_shared_project.png)
+ !['Project Acme' is listed as a shared project for 'Engineering'](img/other_group_sees_shared_project.png)
+
+Note that you can only share a project with:
+
+- groups for which you have an explicitly defined membership
+- groups that contain a nested subgroup or project for which you have an explicitly defined role
+
+Admins are able to share projects with any group in the system.
## Maximum access level
diff --git a/doc/user/project/merge_requests/img/allow_maintainer_push.png b/doc/user/project/merge_requests/img/allow_maintainer_push.png
new file mode 100644
index 00000000000..1631527071b
--- /dev/null
+++ b/doc/user/project/merge_requests/img/allow_maintainer_push.png
Binary files differ
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index d3220598933..10d67729734 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -28,6 +28,7 @@ With GitLab merge requests, you can:
- Enable [fast-forward merge requests](#fast-forward-merge-requests)
- Enable [semi-linear history merge requests](#semi-linear-history-merge-requests) as another security layer to guarantee the pipeline is passing in the target branch
- [Create new merge requests by email](#create-new-merge-requests-by-email)
+- Allow maintainers of the target project to push directly to the fork by [allowing edits from maintainers](maintainer_access.md)
With **[GitLab Enterprise Edition][ee]**, you can also:
diff --git a/doc/user/project/merge_requests/maintainer_access.md b/doc/user/project/merge_requests/maintainer_access.md
new file mode 100644
index 00000000000..7feccc28f6b
--- /dev/null
+++ b/doc/user/project/merge_requests/maintainer_access.md
@@ -0,0 +1,13 @@
+# Allow maintainer pushes for merge requests across forks
+
+This feature is available for merge requests across forked projects that are
+publicly accessible. It makes it easier for maintainers of projects to collaborate
+on merge requests across forks.
+
+When enabling this feature for a merge request, you give can give members with push access to the target project rights to edit files on the source branch of the merge request.
+
+The feature can only be enabled by users who already have push access to the source project. And only lasts while the merge request is open.
+
+Enable this functionality while creating a merge request:
+
+![Enable maintainer edits](./img/allow_maintainer_push.png)
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index affbccccdf9..07a0e2e072c 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -82,7 +82,7 @@ module SharedProject
step 'I should see project "Shop" activity feed' do
project = Project.find_by(name: "Shop")
- expect(page).to have_content "#{@user.name} pushed new branch fix at #{project.name_with_namespace}"
+ expect(page).to have_content "#{@user.name} pushed new branch fix at #{project.full_name}"
end
step 'I should see project settings' do
@@ -113,12 +113,12 @@ module SharedProject
step 'I should not see project "Archive"' do
project = Project.find_by(name: "Archive")
- expect(page).not_to have_content project.name_with_namespace
+ expect(page).not_to have_content project.full_name
end
step 'I should see project "Archive"' do
project = Project.find_by(name: "Archive")
- expect(page).to have_content project.name_with_namespace
+ expect(page).to have_content project.full_name
end
# ----------------------------------------
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 754549f72f0..62ffebeacb0 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -108,6 +108,7 @@ module API
mount ::API::AccessRequests
mount ::API::Applications
mount ::API::AwardEmoji
+ mount ::API::Badges
mount ::API::Boards
mount ::API::Branches
mount ::API::BroadcastMessages
@@ -120,6 +121,7 @@ module API
mount ::API::Events
mount ::API::Features
mount ::API::Files
+ mount ::API::GroupBoards
mount ::API::Groups
mount ::API::GroupMilestones
mount ::API::Internal
@@ -134,10 +136,12 @@ module API
mount ::API::MergeRequests
mount ::API::Namespaces
mount ::API::Notes
+ mount ::API::Discussions
mount ::API::NotificationSettings
mount ::API::PagesDomains
mount ::API::Pipelines
mount ::API::PipelineSchedules
+ mount ::API::ProjectExport
mount ::API::ProjectImport
mount ::API::ProjectHooks
mount ::API::Projects
diff --git a/lib/api/badges.rb b/lib/api/badges.rb
new file mode 100644
index 00000000000..334948b2995
--- /dev/null
+++ b/lib/api/badges.rb
@@ -0,0 +1,134 @@
+module API
+ class Badges < Grape::API
+ include PaginationParams
+
+ before { authenticate_non_get! }
+
+ helpers ::API::Helpers::BadgesHelpers
+
+ helpers do
+ def find_source_if_admin(source_type)
+ source = find_source(source_type, params[:id])
+
+ authorize_admin_source!(source_type, source)
+
+ source
+ end
+ end
+
+ %w[group project].each do |source_type|
+ params do
+ requires :id, type: String, desc: "The ID of a #{source_type}"
+ end
+ resource source_type.pluralize, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
+ desc "Gets a list of #{source_type} badges viewable by the authenticated user." do
+ detail 'This feature was introduced in GitLab 10.6.'
+ success Entities::Badge
+ end
+ params do
+ use :pagination
+ end
+ get ":id/badges" do
+ source = find_source(source_type, params[:id])
+
+ present_badges(source, paginate(source.badges))
+ end
+
+ desc "Preview a badge from a #{source_type}." do
+ detail 'This feature was introduced in GitLab 10.6.'
+ success Entities::BasicBadgeDetails
+ end
+ params do
+ requires :link_url, type: String, desc: 'URL of the badge link'
+ requires :image_url, type: String, desc: 'URL of the badge image'
+ end
+ get ":id/badges/render" do
+ authenticate!
+
+ source = find_source_if_admin(source_type)
+
+ badge = ::Badges::BuildService.new(declared_params(include_missing: false))
+ .execute(source)
+
+ if badge.valid?
+ present_badges(source, badge, with: Entities::BasicBadgeDetails)
+ else
+ render_validation_error!(badge)
+ end
+ end
+
+ desc "Gets a badge of a #{source_type}." do
+ detail 'This feature was introduced in GitLab 10.6.'
+ success Entities::Badge
+ end
+ params do
+ requires :badge_id, type: Integer, desc: 'The badge ID'
+ end
+ get ":id/badges/:badge_id" do
+ source = find_source(source_type, params[:id])
+ badge = find_badge(source)
+
+ present_badges(source, badge)
+ end
+
+ desc "Adds a badge to a #{source_type}." do
+ detail 'This feature was introduced in GitLab 10.6.'
+ success Entities::Badge
+ end
+ params do
+ requires :link_url, type: String, desc: 'URL of the badge link'
+ requires :image_url, type: String, desc: 'URL of the badge image'
+ end
+ post ":id/badges" do
+ source = find_source_if_admin(source_type)
+
+ badge = ::Badges::CreateService.new(declared_params(include_missing: false)).execute(source)
+
+ if badge.persisted?
+ present_badges(source, badge)
+ else
+ render_validation_error!(badge)
+ end
+ end
+
+ desc "Updates a badge of a #{source_type}." do
+ detail 'This feature was introduced in GitLab 10.6.'
+ success Entities::Badge
+ end
+ params do
+ optional :link_url, type: String, desc: 'URL of the badge link'
+ optional :image_url, type: String, desc: 'URL of the badge image'
+ end
+ put ":id/badges/:badge_id" do
+ source = find_source_if_admin(source_type)
+
+ badge = ::Badges::UpdateService.new(declared_params(include_missing: false))
+ .execute(find_badge(source))
+
+ if badge.valid?
+ present_badges(source, badge)
+ else
+ render_validation_error!(badge)
+ end
+ end
+
+ desc 'Removes a badge from a project or group.' do
+ detail 'This feature was introduced in GitLab 10.6.'
+ end
+ params do
+ requires :badge_id, type: Integer, desc: 'The badge ID'
+ end
+ delete ":id/badges/:badge_id" do
+ source = find_source_if_admin(source_type)
+ badge = find_badge(source)
+
+ if badge.is_a?(GroupBadge) && source.is_a?(Project)
+ error!('To delete a Group badge please use the Group endpoint', 403)
+ end
+
+ destroy_conditionally!(badge)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/discussions.rb b/lib/api/discussions.rb
new file mode 100644
index 00000000000..6abd575b6ad
--- /dev/null
+++ b/lib/api/discussions.rb
@@ -0,0 +1,195 @@
+module API
+ class Discussions < Grape::API
+ include PaginationParams
+ helpers ::API::Helpers::NotesHelpers
+
+ before { authenticate! }
+
+ NOTEABLE_TYPES = [Issue, Snippet].freeze
+
+ NOTEABLE_TYPES.each do |noteable_type|
+ parent_type = noteable_type.parent_class.to_s.underscore
+ noteables_str = noteable_type.to_s.underscore.pluralize
+
+ params do
+ requires :id, type: String, desc: "The ID of a #{parent_type}"
+ end
+ resource parent_type.pluralize.to_sym, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
+ desc "Get a list of #{noteable_type.to_s.downcase} discussions" do
+ success Entities::Discussion
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ use :pagination
+ end
+ get ":id/#{noteables_str}/:noteable_id/discussions" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ return not_found!("Discussions") unless can?(current_user, noteable_read_ability_name(noteable), noteable)
+
+ notes = noteable.notes
+ .inc_relations_for_view
+ .includes(:noteable)
+ .fresh
+
+ notes = notes.reject { |n| n.cross_reference_not_visible_for?(current_user) }
+ discussions = Kaminari.paginate_array(Discussion.build_collection(notes, noteable))
+
+ present paginate(discussions), with: Entities::Discussion
+ end
+
+ desc "Get a single #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Discussion
+ end
+ params do
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ end
+ get ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+ notes = readable_discussion_notes(noteable, params[:discussion_id])
+
+ if notes.empty? || !can?(current_user, noteable_read_ability_name(noteable), noteable)
+ return not_found!("Discussion")
+ end
+
+ discussion = Discussion.build(notes, noteable)
+
+ present discussion, with: Entities::Discussion
+ end
+
+ desc "Create a new #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Discussion
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :body, type: String, desc: 'The content of a note'
+ optional :created_at, type: String, desc: 'The creation date of the note'
+ end
+ post ":id/#{noteables_str}/:noteable_id/discussions" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ opts = {
+ note: params[:body],
+ created_at: params[:created_at],
+ type: 'DiscussionNote',
+ noteable_type: noteables_str.classify,
+ noteable_id: noteable.id
+ }
+
+ note = create_note(noteable, opts)
+
+ if note.valid?
+ present note.discussion, with: Entities::Discussion
+ else
+ bad_request!("Note #{note.errors.messages}")
+ end
+ end
+
+ desc "Get comments in a single #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Discussion
+ end
+ params do
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ end
+ get ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+ notes = readable_discussion_notes(noteable, params[:discussion_id])
+
+ if notes.empty? || !can?(current_user, noteable_read_ability_name(noteable), noteable)
+ return not_found!("Notes")
+ end
+
+ present notes, with: Entities::Note
+ end
+
+ desc "Add a comment to a #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :body, type: String, desc: 'The content of a note'
+ optional :created_at, type: String, desc: 'The creation date of the note'
+ end
+ post ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+ notes = readable_discussion_notes(noteable, params[:discussion_id])
+
+ return not_found!("Discussion") if notes.empty?
+ return bad_request!("Discussion is an individual note.") unless notes.first.part_of_discussion?
+
+ opts = {
+ note: params[:body],
+ type: 'DiscussionNote',
+ in_reply_to_discussion_id: params[:discussion_id],
+ created_at: params[:created_at]
+ }
+ note = create_note(noteable, opts)
+
+ if note.valid?
+ present note, with: Entities::Note
+ else
+ bad_request!("Note #{note.errors.messages}")
+ end
+ end
+
+ desc "Get a comment in a #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ end
+ get ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ get_note(noteable, params[:note_id])
+ end
+
+ desc "Edit a comment in a #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ requires :body, type: String, desc: 'The content of a note'
+ end
+ put ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ update_note(noteable, params[:note_id])
+ end
+
+ desc "Delete a comment in a #{noteable_type.to_s.downcase} discussion" do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :discussion_id, type: String, desc: 'The ID of a discussion'
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ end
+ delete ":id/#{noteables_str}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+
+ delete_note(noteable, params[:note_id])
+ end
+ end
+ end
+
+ helpers do
+ def readable_discussion_notes(noteable, discussion_id)
+ notes = noteable.notes
+ .where(discussion_id: discussion_id)
+ .inc_relations_for_view
+ .includes(:noteable)
+ .fresh
+
+ notes.reject { |n| n.cross_reference_not_visible_for?(current_user) }
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 0c8ec7dd5f5..16147ee90c9 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -91,6 +91,21 @@ module API
expose :created_at
end
+ class ProjectExportStatus < ProjectIdentity
+ include ::API::Helpers::RelatedResourcesHelpers
+
+ expose :export_status
+ expose :_links, if: lambda { |project, _options| project.export_status == :finished } do
+ expose :api_url do |project|
+ expose_url(api_v4_projects_export_download_path(id: project.id))
+ end
+
+ expose :web_url do |project|
+ Gitlab::Routing.url_helpers.download_export_project_url(project)
+ end
+ end
+ end
+
class ProjectImportStatus < ProjectIdentity
expose :import_status
@@ -532,6 +547,7 @@ module API
expose :discussion_locked
expose :should_remove_source_branch?, as: :should_remove_source_branch
expose :force_remove_source_branch?, as: :force_remove_source_branch
+ expose :allow_maintainer_to_push, if: -> (merge_request, _) { merge_request.for_fork? }
expose :web_url do |merge_request, options|
Gitlab::UrlBuilder.build(merge_request)
@@ -629,6 +645,7 @@ module API
NOTEABLE_TYPES_WITH_IID = %w(Issue MergeRequest).freeze
expose :id
+ expose :type
expose :note, as: :body
expose :attachment_identifier, as: :attachment
expose :author, using: Entities::UserBasic
@@ -640,6 +657,12 @@ module API
expose(:noteable_iid) { |note| note.noteable.iid if NOTEABLE_TYPES_WITH_IID.include?(note.noteable_type) }
end
+ class Discussion < Grape::Entity
+ expose :id
+ expose :individual_note?, as: :individual_note
+ expose :notes, using: Entities::Note
+ end
+
class AwardEmoji < Grape::Entity
expose :id
expose :name
@@ -1235,5 +1258,23 @@ module API
expose :startline
expose :project_id
end
+
+ class BasicBadgeDetails < Grape::Entity
+ expose :link_url
+ expose :image_url
+ expose :rendered_link_url do |badge, options|
+ badge.rendered_link_url(options.fetch(:project, nil))
+ end
+ expose :rendered_image_url do |badge, options|
+ badge.rendered_image_url(options.fetch(:project, nil))
+ end
+ end
+
+ class Badge < BasicBadgeDetails
+ expose :id
+ expose :kind do |badge|
+ badge.type == 'ProjectBadge' ? 'project' : 'group'
+ end
+ end
end
end
diff --git a/lib/api/group_boards.rb b/lib/api/group_boards.rb
new file mode 100644
index 00000000000..aa9fff25fc8
--- /dev/null
+++ b/lib/api/group_boards.rb
@@ -0,0 +1,117 @@
+module API
+ class GroupBoards < Grape::API
+ include BoardsResponses
+ include PaginationParams
+
+ before do
+ authenticate!
+ end
+
+ helpers do
+ def board_parent
+ user_group
+ end
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of a group'
+ end
+
+ resource :groups, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
+ segment ':id/boards' do
+ desc 'Find a group board' do
+ detail 'This feature was introduced in 10.6'
+ success ::API::Entities::Board
+ end
+ get '/:board_id' do
+ present board, with: ::API::Entities::Board
+ end
+
+ desc 'Get all group boards' do
+ detail 'This feature was introduced in 10.6'
+ success Entities::Board
+ end
+ params do
+ use :pagination
+ end
+ get '/' do
+ present paginate(board_parent.boards), with: Entities::Board
+ end
+ end
+
+ params do
+ requires :board_id, type: Integer, desc: 'The ID of a board'
+ end
+ segment ':id/boards/:board_id' do
+ desc 'Get the lists of a group board' do
+ detail 'Does not include backlog and closed lists. This feature was introduced in 10.6'
+ success Entities::List
+ end
+ params do
+ use :pagination
+ end
+ get '/lists' do
+ present paginate(board_lists), with: Entities::List
+ end
+
+ desc 'Get a list of a group board' do
+ detail 'This feature was introduced in 10.6'
+ success Entities::List
+ end
+ params do
+ requires :list_id, type: Integer, desc: 'The ID of a list'
+ end
+ get '/lists/:list_id' do
+ present board_lists.find(params[:list_id]), with: Entities::List
+ end
+
+ desc 'Create a new board list' do
+ detail 'This feature was introduced in 10.6'
+ success Entities::List
+ end
+ params do
+ requires :label_id, type: Integer, desc: 'The ID of an existing label'
+ end
+ post '/lists' do
+ unless available_labels_for(board_parent).exists?(params[:label_id])
+ render_api_error!({ error: 'Label not found!' }, 400)
+ end
+
+ authorize!(:admin_list, user_group)
+
+ create_list
+ end
+
+ desc 'Moves a board list to a new position' do
+ detail 'This feature was introduced in 10.6'
+ success Entities::List
+ end
+ params do
+ requires :list_id, type: Integer, desc: 'The ID of a list'
+ requires :position, type: Integer, desc: 'The position of the list'
+ end
+ put '/lists/:list_id' do
+ list = board_lists.find(params[:list_id])
+
+ authorize!(:admin_list, user_group)
+
+ move_list(list)
+ end
+
+ desc 'Delete a board list' do
+ detail 'This feature was introduced in 10.6'
+ success Entities::List
+ end
+ params do
+ requires :list_id, type: Integer, desc: 'The ID of a board list'
+ end
+ delete "/lists/:list_id" do
+ authorize!(:admin_list, user_group)
+ list = board_lists.find(params[:list_id])
+
+ destroy_list(list)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/helpers/badges_helpers.rb b/lib/api/helpers/badges_helpers.rb
new file mode 100644
index 00000000000..1f8afbf3c90
--- /dev/null
+++ b/lib/api/helpers/badges_helpers.rb
@@ -0,0 +1,28 @@
+module API
+ module Helpers
+ module BadgesHelpers
+ include ::API::Helpers::MembersHelpers
+
+ def find_badge(source)
+ source.badges.find(params[:badge_id])
+ end
+
+ def present_badges(source, records, options = {})
+ entity_type = options[:with] || Entities::Badge
+ badge_params = badge_source_params(source).merge(with: entity_type)
+
+ present records, badge_params
+ end
+
+ def badge_source_params(source)
+ project = if source.is_a?(Project)
+ source
+ else
+ GroupProjectsFinder.new(group: source, current_user: current_user).execute.first
+ end
+
+ { project: project }
+ end
+ end
+ end
+end
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index cd59da6fc70..4b564cfdef2 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -111,13 +111,6 @@ module API
def gitaly_payload(action)
return unless %w[git-receive-pack git-upload-pack].include?(action)
- if action == 'git-receive-pack'
- return unless Gitlab::GitalyClient.feature_enabled?(
- :ssh_receive_pack,
- status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT
- )
- end
-
{
repository: repository.gitaly_repository,
address: Gitlab::GitalyClient.address(project.repository_storage),
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
new file mode 100644
index 00000000000..cd91df1ecd8
--- /dev/null
+++ b/lib/api/helpers/notes_helpers.rb
@@ -0,0 +1,76 @@
+module API
+ module Helpers
+ module NotesHelpers
+ def update_note(noteable, note_id)
+ note = noteable.notes.find(params[:note_id])
+
+ authorize! :admin_note, note
+
+ opts = {
+ note: params[:body]
+ }
+ parent = noteable_parent(noteable)
+ project = parent if parent.is_a?(Project)
+
+ note = ::Notes::UpdateService.new(project, current_user, opts).execute(note)
+
+ if note.valid?
+ present note, with: Entities::Note
+ else
+ bad_request!("Failed to save note #{note.errors.messages}")
+ end
+ end
+
+ def delete_note(noteable, note_id)
+ note = noteable.notes.find(note_id)
+
+ authorize! :admin_note, note
+
+ parent = noteable_parent(noteable)
+ project = parent if parent.is_a?(Project)
+ destroy_conditionally!(note) do |note|
+ ::Notes::DestroyService.new(project, current_user).execute(note)
+ end
+ end
+
+ def get_note(noteable, note_id)
+ note = noteable.notes.with_metadata.find(params[:note_id])
+ can_read_note = can?(current_user, noteable_read_ability_name(noteable), noteable) && !note.cross_reference_not_visible_for?(current_user)
+
+ if can_read_note
+ present note, with: Entities::Note
+ else
+ not_found!("Note")
+ end
+ end
+
+ def noteable_read_ability_name(noteable)
+ "read_#{noteable.class.to_s.underscore}".to_sym
+ end
+
+ def find_noteable(parent, noteables_str, noteable_id)
+ public_send("find_#{parent}_#{noteables_str.singularize}", noteable_id) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def noteable_parent(noteable)
+ public_send("user_#{noteable.class.parent_class.to_s.underscore}") # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def create_note(noteable, opts)
+ noteables_str = noteable.model_name.to_s.underscore.pluralize
+
+ return not_found!(noteables_str) unless can?(current_user, noteable_read_ability_name(noteable), noteable)
+
+ authorize! :create_note, noteable
+
+ parent = noteable_parent(noteable)
+ if opts[:created_at]
+ opts.delete(:created_at) unless current_user.admin? || parent.owner == current_user
+ end
+
+ project = parent if parent.is_a?(Project)
+ ::Notes::CreateService.new(project, current_user, opts).execute
+ end
+ end
+ end
+end
diff --git a/lib/api/job_artifacts.rb b/lib/api/job_artifacts.rb
index 2a8fa7659bf..47e5eeab31d 100644
--- a/lib/api/job_artifacts.rb
+++ b/lib/api/job_artifacts.rb
@@ -2,20 +2,28 @@ module API
class JobArtifacts < Grape::API
before { authenticate_non_get! }
+ # EE::API::JobArtifacts would override the following helpers
+ helpers do
+ def authorize_download_artifacts!
+ authorize_read_builds!
+ end
+ end
+
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
- desc 'Download the artifacts file from a job' do
+ desc 'Download the artifacts archive from a job' do
detail 'This feature was introduced in GitLab 8.10'
end
params do
requires :ref_name, type: String, desc: 'The ref from repository'
requires :job, type: String, desc: 'The name for the job'
end
+ route_setting :authentication, job_token_allowed: true
get ':id/jobs/artifacts/:ref_name/download',
requirements: { ref_name: /.+/ } do
- authorize_read_builds!
+ authorize_download_artifacts!
builds = user_project.latest_successful_builds_for(params[:ref_name])
latest_build = builds.find_by!(name: params[:job])
@@ -23,14 +31,15 @@ module API
present_artifacts!(latest_build.artifacts_file)
end
- desc 'Download the artifacts file from a job' do
+ desc 'Download the artifacts archive from a job' do
detail 'This feature was introduced in GitLab 8.5'
end
params do
requires :job_id, type: Integer, desc: 'The ID of a job'
end
+ route_setting :authentication, job_token_allowed: true
get ':id/jobs/:job_id/artifacts' do
- authorize_read_builds!
+ authorize_download_artifacts!
build = find_build!(params[:job_id])
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 8c02972b421..3264a26f7d2 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -6,6 +6,32 @@ module API
helpers ::Gitlab::IssuableMetadata
+ # EE::API::MergeRequests would override the following helpers
+ helpers do
+ params :optional_params_ee do
+ end
+
+ params :merge_params_ee do
+ end
+
+ def update_merge_request_ee(merge_request)
+ end
+ end
+
+ def self.update_params_at_least_one_of
+ %i[
+ assignee_id
+ description
+ labels
+ milestone_id
+ remove_source_branch
+ state_event
+ target_branch
+ title
+ discussion_locked
+ ]
+ end
+
helpers do
def find_merge_requests(args = {})
args = declared_params.merge(args)
@@ -31,6 +57,12 @@ module API
mr.all_pipelines
end
+ def check_sha_param!(params, merge_request)
+ if params[:sha] && merge_request.diff_head_sha != params[:sha]
+ render_api_error!("SHA does not match HEAD of source branch: #{merge_request.diff_head_sha}", 409)
+ end
+ end
+
params :merge_requests_params do
optional :state, type: String, values: %w[opened closed merged all], default: 'all',
desc: 'Return opened, closed, merged, or all merge requests'
@@ -106,16 +138,15 @@ module API
render_api_error!(errors, 400)
end
- params :optional_params_ce do
+ params :optional_params do
optional :description, type: String, desc: 'The description of the merge request'
optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request'
optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request'
optional :labels, type: String, desc: 'Comma-separated list of label names'
optional :remove_source_branch, type: Boolean, desc: 'Remove source branch when merging'
- end
+ optional :allow_maintainer_to_push, type: Boolean, desc: 'Whether a maintainer of the target project can push to the source project'
- params :optional_params do
- use :optional_params_ce
+ use :optional_params_ee
end
end
@@ -240,18 +271,6 @@ module API
success Entities::MergeRequest
end
params do
- # CE
- at_least_one_of_ce = [
- :assignee_id,
- :description,
- :labels,
- :milestone_id,
- :remove_source_branch,
- :state_event,
- :target_branch,
- :title,
- :discussion_locked
- ]
optional :title, type: String, allow_blank: false, desc: 'The title of the merge request'
optional :target_branch, type: String, allow_blank: false, desc: 'The target branch'
optional :state_event, type: String, values: %w[close reopen],
@@ -259,7 +278,7 @@ module API
optional :discussion_locked, type: Boolean, desc: 'Whether the MR discussion is locked'
use :optional_params
- at_least_one_of(*at_least_one_of_ce)
+ at_least_one_of(*::API::MergeRequests.update_params_at_least_one_of)
end
put ':id/merge_requests/:merge_request_iid' do
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42318')
@@ -282,13 +301,14 @@ module API
success Entities::MergeRequest
end
params do
- # CE
optional :merge_commit_message, type: String, desc: 'Custom merge commit message'
optional :should_remove_source_branch, type: Boolean,
desc: 'When true, the source branch will be deleted if possible'
optional :merge_when_pipeline_succeeds, type: Boolean,
desc: 'When true, this merge request will be merged when the pipeline succeeds'
optional :sha, type: String, desc: 'When present, must have the HEAD SHA of the source branch'
+
+ use :merge_params_ee
end
put ':id/merge_requests/:merge_request_iid/merge' do
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42317')
@@ -304,9 +324,9 @@ module API
render_api_error!('Branch cannot be merged', 406) unless merge_request.mergeable?(skip_ci_check: merge_when_pipeline_succeeds)
- if params[:sha] && merge_request.diff_head_sha != params[:sha]
- render_api_error!("SHA does not match HEAD of source branch: #{merge_request.diff_head_sha}", 409)
- end
+ check_sha_param!(params, merge_request)
+
+ update_merge_request_ee(merge_request)
merge_params = {
commit_message: params[:merge_commit_message],
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 3588dc85c9e..69f1df6b341 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -1,19 +1,23 @@
module API
class Notes < Grape::API
include PaginationParams
+ helpers ::API::Helpers::NotesHelpers
before { authenticate! }
NOTEABLE_TYPES = [Issue, MergeRequest, Snippet].freeze
- params do
- requires :id, type: String, desc: 'The ID of a project'
- end
- resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
- NOTEABLE_TYPES.each do |noteable_type|
+ NOTEABLE_TYPES.each do |noteable_type|
+ parent_type = noteable_type.parent_class.to_s.underscore
+ noteables_str = noteable_type.to_s.underscore.pluralize
+
+ params do
+ requires :id, type: String, desc: "The ID of a #{parent_type}"
+ end
+ resource parent_type.pluralize.to_sym, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
noteables_str = noteable_type.to_s.underscore.pluralize
- desc 'Get a list of project +noteable+ notes' do
+ desc "Get a list of #{noteable_type.to_s.downcase} notes" do
success Entities::Note
end
params do
@@ -25,7 +29,7 @@ module API
use :pagination
end
get ":id/#{noteables_str}/:noteable_id/notes" do
- noteable = find_project_noteable(noteables_str, params[:noteable_id])
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
if can?(current_user, noteable_read_ability_name(noteable), noteable)
# We exclude notes that are cross-references and that cannot be viewed
@@ -46,7 +50,7 @@ module API
end
end
- desc 'Get a single +noteable+ note' do
+ desc "Get a single #{noteable_type.to_s.downcase} note" do
success Entities::Note
end
params do
@@ -54,18 +58,11 @@ module API
requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
end
get ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
- noteable = find_project_noteable(noteables_str, params[:noteable_id])
- note = noteable.notes.with_metadata.find(params[:note_id])
- can_read_note = can?(current_user, noteable_read_ability_name(noteable), noteable) && !note.cross_reference_not_visible_for?(current_user)
-
- if can_read_note
- present note, with: Entities::Note
- else
- not_found!("Note")
- end
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
+ get_note(noteable, params[:note_id])
end
- desc 'Create a new +noteable+ note' do
+ desc "Create a new #{noteable_type.to_s.downcase} note" do
success Entities::Note
end
params do
@@ -74,34 +71,25 @@ module API
optional :created_at, type: String, desc: 'The creation date of the note'
end
post ":id/#{noteables_str}/:noteable_id/notes" do
- noteable = find_project_noteable(noteables_str, params[:noteable_id])
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
opts = {
note: params[:body],
noteable_type: noteables_str.classify,
- noteable_id: noteable.id
+ noteable_id: noteable.id,
+ created_at: params[:created_at]
}
- if can?(current_user, noteable_read_ability_name(noteable), noteable)
- authorize! :create_note, noteable
+ note = create_note(noteable, opts)
- if params[:created_at] && (current_user.admin? || user_project.owner == current_user)
- opts[:created_at] = params[:created_at]
- end
-
- note = ::Notes::CreateService.new(user_project, current_user, opts).execute
-
- if note.valid?
- present note, with: Entities.const_get(note.class.name)
- else
- not_found!("Note #{note.errors.messages}")
- end
+ if note.valid?
+ present note, with: Entities.const_get(note.class.name)
else
- not_found!("Note")
+ bad_request!("Note #{note.errors.messages}")
end
end
- desc 'Update an existing +noteable+ note' do
+ desc "Update an existing #{noteable_type.to_s.downcase} note" do
success Entities::Note
end
params do
@@ -110,24 +98,12 @@ module API
requires :body, type: String, desc: 'The content of a note'
end
put ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
- note = user_project.notes.find(params[:note_id])
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
- authorize! :admin_note, note
-
- opts = {
- note: params[:body]
- }
-
- note = ::Notes::UpdateService.new(user_project, current_user, opts).execute(note)
-
- if note.valid?
- present note, with: Entities::Note
- else
- render_api_error!("Failed to save note #{note.errors.messages}", 400)
- end
+ update_note(noteable, params[:note_id])
end
- desc 'Delete a +noteable+ note' do
+ desc "Delete a #{noteable_type.to_s.downcase} note" do
success Entities::Note
end
params do
@@ -135,25 +111,11 @@ module API
requires :note_id, type: Integer, desc: 'The ID of a note'
end
delete ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
- note = user_project.notes.find(params[:note_id])
-
- authorize! :admin_note, note
+ noteable = find_noteable(parent_type, noteables_str, params[:noteable_id])
- destroy_conditionally!(note) do |note|
- ::Notes::DestroyService.new(user_project, current_user).execute(note)
- end
+ delete_note(noteable, params[:note_id])
end
end
end
-
- helpers do
- def find_project_noteable(noteables_str, noteable_id)
- public_send("find_project_#{noteables_str.singularize}", noteable_id) # rubocop:disable GitlabSecurity/PublicSend
- end
-
- def noteable_read_ability_name(noteable)
- "read_#{noteable.class.to_s.underscore}".to_sym
- end
- end
end
end
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
new file mode 100644
index 00000000000..6ec2626df1a
--- /dev/null
+++ b/lib/api/project_export.rb
@@ -0,0 +1,41 @@
+module API
+ class ProjectExport < Grape::API
+ before do
+ not_found! unless Gitlab::CurrentSettings.project_export_enabled?
+ authorize_admin_project
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+ resource :projects, requirements: { id: %r{[^/]+} } do
+ desc 'Get export status' do
+ detail 'This feature was introduced in GitLab 10.6.'
+ success Entities::ProjectExportStatus
+ end
+ get ':id/export' do
+ present user_project, with: Entities::ProjectExportStatus
+ end
+
+ desc 'Download export' do
+ detail 'This feature was introduced in GitLab 10.6.'
+ end
+ get ':id/export/download' do
+ path = user_project.export_project_path
+
+ render_api_error!('404 Not found or has expired', 404) unless path
+
+ present_file!(path, File.basename(path), 'application/gzip')
+ end
+
+ desc 'Start export' do
+ detail 'This feature was introduced in GitLab 10.6.'
+ end
+ post ':id/export' do
+ user_project.add_export_job(current_user: current_user)
+
+ accepted!
+ end
+ end
+ end
+end
diff --git a/lib/api/runner.rb b/lib/api/runner.rb
index 91cdc564002..7e6c33ec33d 100644
--- a/lib/api/runner.rb
+++ b/lib/api/runner.rb
@@ -204,6 +204,7 @@ module API
optional 'file.path', type: String, desc: %q(path to locally stored body (generated by Workhorse))
optional 'file.name', type: String, desc: %q(real filename as send in Content-Disposition (generated by Workhorse))
optional 'file.type', type: String, desc: %q(real content type as send in Content-Type (generated by Workhorse))
+ optional 'file.sha256', type: String, desc: %q(sha256 checksum of the file)
optional 'metadata.path', type: String, desc: %q(path to locally stored body (generated by Workhorse))
optional 'metadata.name', type: String, desc: %q(filename (generated by Workhorse))
end
@@ -224,7 +225,7 @@ module API
expire_in = params['expire_in'] ||
Gitlab::CurrentSettings.current_application_settings.default_artifacts_expire_in
- job.build_job_artifacts_archive(project: job.project, file_type: :archive, file: artifacts, expire_in: expire_in)
+ job.build_job_artifacts_archive(project: job.project, file_type: :archive, file: artifacts, file_sha256: params['file.sha256'], expire_in: expire_in)
job.build_job_artifacts_metadata(project: job.project, file_type: :metadata, file: metadata, expire_in: expire_in) if metadata
job.artifacts_expire_in = expire_in
diff --git a/lib/banzai/filter/autolink_filter.rb b/lib/banzai/filter/autolink_filter.rb
index b8d2673c1a6..75b64ae9af2 100644
--- a/lib/banzai/filter/autolink_filter.rb
+++ b/lib/banzai/filter/autolink_filter.rb
@@ -25,8 +25,8 @@ module Banzai
# period or comma for punctuation without those characters being included
# in the generated link.
#
- # Rubular: http://rubular.com/r/cxjPyZc7Sb
- LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://\S+)(?<!,|\.)}
+ # Rubular: http://rubular.com/r/JzPhi6DCZp
+ LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://[^\s>]+)(?<!,|\.)}
# Text matching LINK_PATTERN inside these elements will not be linked
IGNORE_PARENTS = %w(a code kbd pre script style).to_set
@@ -35,53 +35,19 @@ module Banzai
TEXT_QUERY = %Q(descendant-or-self::text()[
not(#{IGNORE_PARENTS.map { |p| "ancestor::#{p}" }.join(' or ')})
and contains(., '://')
- and not(starts-with(., 'http'))
- and not(starts-with(., 'ftp'))
]).freeze
+ PUNCTUATION_PAIRS = {
+ "'" => "'",
+ '"' => '"',
+ ')' => '(',
+ ']' => '[',
+ '}' => '{'
+ }.freeze
+
def call
return doc if context[:autolink] == false
- rinku_parse
- text_parse
- end
-
- private
-
- # Run the text through Rinku as a first pass
- #
- # This will quickly autolink http(s) and ftp links.
- #
- # `@doc` will be re-parsed with the HTML String from Rinku.
- def rinku_parse
- # Convert the options from a Hash to a String that Rinku expects
- options = tag_options(link_options)
-
- # NOTE: We don't parse email links because it will erroneously match
- # external Commit and CommitRange references.
- #
- # The final argument tells Rinku to link short URLs that don't include a
- # period (e.g., http://localhost:3000/)
- rinku = Rinku.auto_link(html, :urls, options, IGNORE_PARENTS.to_a, 1)
-
- return if rinku == html
-
- # Rinku returns a String, so parse it back to a Nokogiri::XML::Document
- # for further processing.
- @doc = parse_html(rinku)
- end
-
- # Return true if any of the UNSAFE_PROTOCOLS strings are included in the URI scheme
- def contains_unsafe?(scheme)
- return false unless scheme
-
- scheme = scheme.strip.downcase
- Banzai::Filter::SanitizationFilter::UNSAFE_PROTOCOLS.any? { |protocol| scheme.include?(protocol) }
- end
-
- # Autolinks any text matching LINK_PATTERN that Rinku didn't already
- # replace
- def text_parse
doc.xpath(TEXT_QUERY).each do |node|
content = node.to_html
@@ -97,6 +63,16 @@ module Banzai
doc
end
+ private
+
+ # Return true if any of the UNSAFE_PROTOCOLS strings are included in the URI scheme
+ def contains_unsafe?(scheme)
+ return false unless scheme
+
+ scheme = scheme.strip.downcase
+ Banzai::Filter::SanitizationFilter::UNSAFE_PROTOCOLS.any? { |protocol| scheme.include?(protocol) }
+ end
+
def autolink_match(match)
# start by stripping out dangerous links
begin
@@ -112,12 +88,30 @@ module Banzai
match.gsub!(/((?:&[\w#]+;)+)\z/, '')
dropped = ($1 || '').html_safe
+ # To match the behaviour of Rinku, if the matched link ends with a
+ # closing part of a matched pair of punctuation, we remove that trailing
+ # character unless there are an equal number of closing and opening
+ # characters in the link.
+ if match.end_with?(*PUNCTUATION_PAIRS.keys)
+ close_character = match[-1]
+ close_count = match.count(close_character)
+ open_character = PUNCTUATION_PAIRS[close_character]
+ open_count = match.count(open_character)
+
+ if open_count != close_count || open_character == close_character
+ dropped += close_character
+ match = match[0..-2]
+ end
+ end
+
options = link_options.merge(href: match)
- content_tag(:a, match, options) + dropped
+ content_tag(:a, match.html_safe, options) + dropped
end
def autolink_filter(text)
- text.gsub(LINK_PATTERN) { |match| autolink_match(match) }
+ Gitlab::StringRegexMarker.new(CGI.unescapeHTML(text), text.html_safe).mark(LINK_PATTERN) do |link, left:, right:|
+ autolink_match(link)
+ end
end
def link_options
diff --git a/lib/banzai/filter/commit_reference_filter.rb b/lib/banzai/filter/commit_reference_filter.rb
index eedb95197aa..43bf4fc6565 100644
--- a/lib/banzai/filter/commit_reference_filter.rb
+++ b/lib/banzai/filter/commit_reference_filter.rb
@@ -18,7 +18,8 @@ module Banzai
def find_object(project, id)
if project && project.valid_repo?
- project.commit(id)
+ # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/43894
+ Gitlab::GitalyClient.allow_n_plus_1_calls { project.commit(id) }
end
end
diff --git a/lib/banzai/filter/markdown_engines/common_mark.rb b/lib/banzai/filter/markdown_engines/common_mark.rb
new file mode 100644
index 00000000000..bc9597df894
--- /dev/null
+++ b/lib/banzai/filter/markdown_engines/common_mark.rb
@@ -0,0 +1,45 @@
+# `CommonMark` markdown engine for GitLab's Banzai markdown filter.
+# This module is used in Banzai::Filter::MarkdownFilter.
+# Used gem is `commonmarker` which is a ruby wrapper for libcmark (CommonMark parser)
+# including GitHub's GFM extensions.
+# Homepage: https://github.com/gjtorikian/commonmarker
+
+module Banzai
+ module Filter
+ module MarkdownEngines
+ class CommonMark
+ EXTENSIONS = [
+ :autolink, # provides support for automatically converting URLs to anchor tags.
+ :strikethrough, # provides support for strikethroughs.
+ :table, # provides support for tables.
+ :tagfilter # strips out several "unsafe" HTML tags from being used: https://github.github.com/gfm/#disallowed-raw-html-extension-
+ ].freeze
+
+ PARSE_OPTIONS = [
+ :FOOTNOTES, # parse footnotes.
+ :STRIKETHROUGH_DOUBLE_TILDE, # parse strikethroughs by double tildes (as redcarpet does).
+ :VALIDATE_UTF8 # replace illegal sequences with the replacement character U+FFFD.
+ ].freeze
+
+ # The `:GITHUB_PRE_LANG` option is not used intentionally because
+ # it renders a fence block with language as `<pre lang="LANG"><code>some code\n</code></pre>`
+ # while GitLab's syntax is `<pre><code lang="LANG">some code\n</code></pre>`.
+ # If in the future the syntax is about to be made GitHub-compatible, please, add `:GITHUB_PRE_LANG` render option below
+ # and remove `code_block` method from `lib/banzai/renderer/common_mark/html.rb`.
+ RENDER_OPTIONS = [
+ :DEFAULT # default rendering system. Nothing special.
+ ].freeze
+
+ def initialize
+ @renderer = Banzai::Renderer::CommonMark::HTML.new(options: RENDER_OPTIONS)
+ end
+
+ def render(text)
+ doc = CommonMarker.render_doc(text, PARSE_OPTIONS, EXTENSIONS)
+
+ @renderer.render(doc)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/markdown_engines/redcarpet.rb b/lib/banzai/filter/markdown_engines/redcarpet.rb
new file mode 100644
index 00000000000..ac99941fefa
--- /dev/null
+++ b/lib/banzai/filter/markdown_engines/redcarpet.rb
@@ -0,0 +1,32 @@
+# `Redcarpet` markdown engine for GitLab's Banzai markdown filter.
+# This module is used in Banzai::Filter::MarkdownFilter.
+# Used gem is `redcarpet` which is a ruby library for markdown processing.
+# Homepage: https://github.com/vmg/redcarpet
+
+module Banzai
+ module Filter
+ module MarkdownEngines
+ class Redcarpet
+ OPTIONS = {
+ fenced_code_blocks: true,
+ footnotes: true,
+ lax_spacing: true,
+ no_intra_emphasis: true,
+ space_after_headers: true,
+ strikethrough: true,
+ superscript: true,
+ tables: true
+ }.freeze
+
+ def initialize
+ html_renderer = Banzai::Renderer::Redcarpet::HTML.new
+ @renderer = ::Redcarpet::Markdown.new(html_renderer, OPTIONS)
+ end
+
+ def render(text)
+ @renderer.render(text)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/markdown_filter.rb b/lib/banzai/filter/markdown_filter.rb
index 9cac303e645..c1e2b680240 100644
--- a/lib/banzai/filter/markdown_filter.rb
+++ b/lib/banzai/filter/markdown_filter.rb
@@ -1,34 +1,31 @@
module Banzai
module Filter
class MarkdownFilter < HTML::Pipeline::TextFilter
- # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
- REDCARPET_OPTIONS = {
- fenced_code_blocks: true,
- footnotes: true,
- lax_spacing: true,
- no_intra_emphasis: true,
- space_after_headers: true,
- strikethrough: true,
- superscript: true,
- tables: true
- }.freeze
-
def initialize(text, context = nil, result = nil)
- super text, context, result
- @text = @text.delete "\r"
+ super(text, context, result)
+
+ @renderer = renderer(context[:markdown_engine]).new
+ @text = @text.delete("\r")
end
def call
- html = self.class.renderer.render(@text)
- html.rstrip!
- html
+ @renderer.render(@text).rstrip
+ end
+
+ private
+
+ DEFAULT_ENGINE = :redcarpet
+
+ def engine(engine_from_context)
+ engine_from_context ||= DEFAULT_ENGINE
+
+ engine_from_context.to_s.classify
end
- def self.renderer
- Thread.current[:banzai_markdown_renderer] ||= begin
- renderer = Banzai::Renderer::HTML.new
- Redcarpet::Markdown.new(renderer, REDCARPET_OPTIONS)
- end
+ def renderer(engine_from_context)
+ "Banzai::Filter::MarkdownEngines::#{engine(engine_from_context)}".constantize
+ rescue NameError
+ raise NameError, "`#{engine_from_context}` is unknown markdown engine"
end
end
end
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index 0ac7e231b5b..6dbf0d68fe8 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -1,3 +1,4 @@
+require 'rouge/plugins/common_mark'
require 'rouge/plugins/redcarpet'
module Banzai
diff --git a/lib/banzai/renderer/common_mark/html.rb b/lib/banzai/renderer/common_mark/html.rb
new file mode 100644
index 00000000000..c7a54629f31
--- /dev/null
+++ b/lib/banzai/renderer/common_mark/html.rb
@@ -0,0 +1,21 @@
+module Banzai
+ module Renderer
+ module CommonMark
+ class HTML < CommonMarker::HtmlRenderer
+ def code_block(node)
+ block do
+ code = node.string_content
+ lang = node.fence_info
+ lang_attr = lang.present? ? %Q{ lang="#{lang}"} : ''
+ result =
+ "<pre>" \
+ "<code#{lang_attr}>#{html_escape(code)}</code>" \
+ "</pre>"
+
+ out(result)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/renderer/html.rb b/lib/banzai/renderer/html.rb
deleted file mode 100644
index 252caa35947..00000000000
--- a/lib/banzai/renderer/html.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-module Banzai
- module Renderer
- class HTML < Redcarpet::Render::HTML
- def block_code(code, lang)
- lang_attr = lang ? %Q{ lang="#{lang}"} : ''
-
- "\n<pre>" \
- "<code#{lang_attr}>#{html_escape(code)}</code>" \
- "</pre>"
- end
- end
- end
-end
diff --git a/lib/banzai/renderer/redcarpet/html.rb b/lib/banzai/renderer/redcarpet/html.rb
new file mode 100644
index 00000000000..94df5d8b1e1
--- /dev/null
+++ b/lib/banzai/renderer/redcarpet/html.rb
@@ -0,0 +1,15 @@
+module Banzai
+ module Renderer
+ module Redcarpet
+ class HTML < ::Redcarpet::Render::HTML
+ def block_code(code, lang)
+ lang_attr = lang ? %Q{ lang="#{lang}"} : ''
+
+ "\n<pre>" \
+ "<code#{lang_attr}>#{html_escape(code)}</code>" \
+ "</pre>"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/constraints/group_url_constrainer.rb b/lib/constraints/group_url_constrainer.rb
index fd2ac2db0a9..87649c50424 100644
--- a/lib/constraints/group_url_constrainer.rb
+++ b/lib/constraints/group_url_constrainer.rb
@@ -1,9 +1,11 @@
-class GroupUrlConstrainer
- def matches?(request)
- full_path = request.params[:group_id] || request.params[:id]
+module Constraints
+ class GroupUrlConstrainer
+ def matches?(request)
+ full_path = request.params[:group_id] || request.params[:id]
- return false unless NamespacePathValidator.valid_path?(full_path)
+ return false unless NamespacePathValidator.valid_path?(full_path)
- Group.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ Group.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ end
end
end
diff --git a/lib/constraints/project_url_constrainer.rb b/lib/constraints/project_url_constrainer.rb
index e90ecb5ec69..32aea98f0f7 100644
--- a/lib/constraints/project_url_constrainer.rb
+++ b/lib/constraints/project_url_constrainer.rb
@@ -1,13 +1,15 @@
-class ProjectUrlConstrainer
- def matches?(request)
- namespace_path = request.params[:namespace_id]
- project_path = request.params[:project_id] || request.params[:id]
- full_path = [namespace_path, project_path].join('/')
+module Constraints
+ class ProjectUrlConstrainer
+ def matches?(request)
+ namespace_path = request.params[:namespace_id]
+ project_path = request.params[:project_id] || request.params[:id]
+ full_path = [namespace_path, project_path].join('/')
- return false unless ProjectPathValidator.valid_path?(full_path)
+ return false unless ProjectPathValidator.valid_path?(full_path)
- # We intentionally allow SELECT(*) here so result of this query can be used
- # as cache for further Project.find_by_full_path calls within request
- Project.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ # We intentionally allow SELECT(*) here so result of this query can be used
+ # as cache for further Project.find_by_full_path calls within request
+ Project.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ end
end
end
diff --git a/lib/constraints/user_url_constrainer.rb b/lib/constraints/user_url_constrainer.rb
index 3b3ed1c6ddb..8afa04d29a4 100644
--- a/lib/constraints/user_url_constrainer.rb
+++ b/lib/constraints/user_url_constrainer.rb
@@ -1,9 +1,11 @@
-class UserUrlConstrainer
- def matches?(request)
- full_path = request.params[:username]
+module Constraints
+ class UserUrlConstrainer
+ def matches?(request)
+ full_path = request.params[:username]
- return false unless NamespacePathValidator.valid_path?(full_path)
+ return false unless NamespacePathValidator.valid_path?(full_path)
- User.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ User.find_by_full_path(full_path, follow_redirects: request.get?).present?
+ end
end
end
diff --git a/lib/declarative_policy.rb b/lib/declarative_policy.rb
index b1949d693ad..1dd2855063d 100644
--- a/lib/declarative_policy.rb
+++ b/lib/declarative_policy.rb
@@ -1,6 +1,8 @@
require_dependency 'declarative_policy/cache'
require_dependency 'declarative_policy/condition'
-require_dependency 'declarative_policy/dsl'
+require_dependency 'declarative_policy/delegate_dsl'
+require_dependency 'declarative_policy/policy_dsl'
+require_dependency 'declarative_policy/rule_dsl'
require_dependency 'declarative_policy/preferred_scope'
require_dependency 'declarative_policy/rule'
require_dependency 'declarative_policy/runner'
diff --git a/lib/declarative_policy/delegate_dsl.rb b/lib/declarative_policy/delegate_dsl.rb
new file mode 100644
index 00000000000..f544dffe888
--- /dev/null
+++ b/lib/declarative_policy/delegate_dsl.rb
@@ -0,0 +1,16 @@
+module DeclarativePolicy
+ # Used when the name of a delegate is mentioned in
+ # the rule DSL.
+ class DelegateDsl
+ def initialize(rule_dsl, delegate_name)
+ @rule_dsl = rule_dsl
+ @delegate_name = delegate_name
+ end
+
+ def method_missing(m, *a, &b)
+ return super unless a.empty? && !block_given?
+
+ @rule_dsl.delegate(@delegate_name, m)
+ end
+ end
+end
diff --git a/lib/declarative_policy/dsl.rb b/lib/declarative_policy/dsl.rb
deleted file mode 100644
index 6ba1e7a3c5c..00000000000
--- a/lib/declarative_policy/dsl.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-module DeclarativePolicy
- # The DSL evaluation context inside rule { ... } blocks.
- # Responsible for creating and combining Rule objects.
- #
- # See Base.rule
- class RuleDsl
- def initialize(context_class)
- @context_class = context_class
- end
-
- def can?(ability)
- Rule::Ability.new(ability)
- end
-
- def all?(*rules)
- Rule::And.make(rules)
- end
-
- def any?(*rules)
- Rule::Or.make(rules)
- end
-
- def none?(*rules)
- ~Rule::Or.new(rules)
- end
-
- def cond(condition)
- Rule::Condition.new(condition)
- end
-
- def delegate(delegate_name, condition)
- Rule::DelegatedCondition.new(delegate_name, condition)
- end
-
- def method_missing(m, *a, &b)
- return super unless a.size == 0 && !block_given?
-
- if @context_class.delegations.key?(m)
- DelegateDsl.new(self, m)
- else
- cond(m.to_sym)
- end
- end
- end
-
- # Used when the name of a delegate is mentioned in
- # the rule DSL.
- class DelegateDsl
- def initialize(rule_dsl, delegate_name)
- @rule_dsl = rule_dsl
- @delegate_name = delegate_name
- end
-
- def method_missing(m, *a, &b)
- return super unless a.size == 0 && !block_given?
-
- @rule_dsl.delegate(@delegate_name, m)
- end
- end
-
- # The return value of a rule { ... } declaration.
- # Can call back to register rules with the containing
- # Policy class (context_class here). See Base.rule
- #
- # Note that the #policy method just performs an #instance_eval,
- # which is useful for multiple #enable or #prevent callse.
- #
- # Also provides a #method_missing proxy to the context
- # class's class methods, so that helper methods can be
- # defined and used in a #policy { ... } block.
- class PolicyDsl
- def initialize(context_class, rule)
- @context_class = context_class
- @rule = rule
- end
-
- def policy(&b)
- instance_eval(&b)
- end
-
- def enable(*abilities)
- @context_class.enable_when(abilities, @rule)
- end
-
- def prevent(*abilities)
- @context_class.prevent_when(abilities, @rule)
- end
-
- def prevent_all
- @context_class.prevent_all_when(@rule)
- end
-
- def method_missing(m, *a, &b)
- return super unless @context_class.respond_to?(m)
-
- @context_class.__send__(m, *a, &b) # rubocop:disable GitlabSecurity/PublicSend
- end
-
- def respond_to_missing?(m)
- @context_class.respond_to?(m) || super
- end
- end
-end
diff --git a/lib/declarative_policy/policy_dsl.rb b/lib/declarative_policy/policy_dsl.rb
new file mode 100644
index 00000000000..f11b6e9f730
--- /dev/null
+++ b/lib/declarative_policy/policy_dsl.rb
@@ -0,0 +1,44 @@
+module DeclarativePolicy
+ # The return value of a rule { ... } declaration.
+ # Can call back to register rules with the containing
+ # Policy class (context_class here). See Base.rule
+ #
+ # Note that the #policy method just performs an #instance_eval,
+ # which is useful for multiple #enable or #prevent callse.
+ #
+ # Also provides a #method_missing proxy to the context
+ # class's class methods, so that helper methods can be
+ # defined and used in a #policy { ... } block.
+ class PolicyDsl
+ def initialize(context_class, rule)
+ @context_class = context_class
+ @rule = rule
+ end
+
+ def policy(&b)
+ instance_eval(&b)
+ end
+
+ def enable(*abilities)
+ @context_class.enable_when(abilities, @rule)
+ end
+
+ def prevent(*abilities)
+ @context_class.prevent_when(abilities, @rule)
+ end
+
+ def prevent_all
+ @context_class.prevent_all_when(@rule)
+ end
+
+ def method_missing(m, *a, &b)
+ return super unless @context_class.respond_to?(m)
+
+ @context_class.__send__(m, *a, &b) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def respond_to_missing?(m)
+ @context_class.respond_to?(m) || super
+ end
+ end
+end
diff --git a/lib/declarative_policy/preferred_scope.rb b/lib/declarative_policy/preferred_scope.rb
index b0754098149..5c214408dd0 100644
--- a/lib/declarative_policy/preferred_scope.rb
+++ b/lib/declarative_policy/preferred_scope.rb
@@ -1,4 +1,4 @@
-module DeclarativePolicy
+module DeclarativePolicy # rubocop:disable Naming/FileName
PREFERRED_SCOPE_KEY = :"DeclarativePolicy.preferred_scope"
class << self
diff --git a/lib/declarative_policy/rule_dsl.rb b/lib/declarative_policy/rule_dsl.rb
new file mode 100644
index 00000000000..e948b7f2de1
--- /dev/null
+++ b/lib/declarative_policy/rule_dsl.rb
@@ -0,0 +1,45 @@
+module DeclarativePolicy
+ # The DSL evaluation context inside rule { ... } blocks.
+ # Responsible for creating and combining Rule objects.
+ #
+ # See Base.rule
+ class RuleDsl
+ def initialize(context_class)
+ @context_class = context_class
+ end
+
+ def can?(ability)
+ Rule::Ability.new(ability)
+ end
+
+ def all?(*rules)
+ Rule::And.make(rules)
+ end
+
+ def any?(*rules)
+ Rule::Or.make(rules)
+ end
+
+ def none?(*rules)
+ ~Rule::Or.new(rules)
+ end
+
+ def cond(condition)
+ Rule::Condition.new(condition)
+ end
+
+ def delegate(delegate_name, condition)
+ Rule::DelegatedCondition.new(delegate_name, condition)
+ end
+
+ def method_missing(m, *a, &b)
+ return super unless a.empty? && !block_given?
+
+ if @context_class.delegations.key?(m)
+ DelegateDsl.new(self, m)
+ else
+ cond(m.to_sym)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 86393ee254d..f5ccf952cf9 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -40,8 +40,8 @@ module Gitlab
end
def find_with_user_password(login, password)
- # Avoid resource intensive login checks if password is not provided
- return unless password.present?
+ # Avoid resource intensive checks if login credentials are not provided
+ return unless login.present? && password.present?
# Nothing to do here if internal auth is disabled and LDAP is
# not configured
@@ -50,14 +50,26 @@ module Gitlab
Gitlab::Auth::UniqueIpsLimiter.limit_user! do
user = User.by_login(login)
- # If no user is found, or it's an LDAP server, try LDAP.
- # LDAP users are only authenticated via LDAP
- if user.nil? || user.ldap_user?
- # Second chance - try LDAP authentication
- Gitlab::Auth::LDAP::Authentication.login(login, password)
- elsif Gitlab::CurrentSettings.password_authentication_enabled_for_git?
- user if user.active? && user.valid_password?(password)
+ return if user && !user.active?
+
+ authenticators = []
+
+ if user
+ authenticators << Gitlab::Auth::OAuth::Provider.authentication(user, 'database')
+
+ # Add authenticators for all identities if user is not nil
+ user&.identities&.each do |identity|
+ authenticators << Gitlab::Auth::OAuth::Provider.authentication(user, identity.provider)
+ end
+ else
+ # If no user is provided, try LDAP.
+ # LDAP users are only authenticated via LDAP
+ authenticators << Gitlab::Auth::LDAP::Authentication
end
+
+ authenticators.compact!
+
+ user if authenticators.find { |auth| auth.login(login, password) }
end
end
diff --git a/lib/gitlab/auth/database/authentication.rb b/lib/gitlab/auth/database/authentication.rb
new file mode 100644
index 00000000000..260a77058a4
--- /dev/null
+++ b/lib/gitlab/auth/database/authentication.rb
@@ -0,0 +1,16 @@
+# These calls help to authenticate to OAuth provider by providing username and password
+#
+
+module Gitlab
+ module Auth
+ module Database
+ class Authentication < Gitlab::Auth::OAuth::Authentication
+ def login(login, password)
+ return false unless Gitlab::CurrentSettings.password_authentication_enabled_for_git?
+
+ user&.valid_password?(password)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/ldap/authentication.rb b/lib/gitlab/auth/ldap/authentication.rb
index cbb9cf4bb9c..e70c3ab6b46 100644
--- a/lib/gitlab/auth/ldap/authentication.rb
+++ b/lib/gitlab/auth/ldap/authentication.rb
@@ -7,7 +7,7 @@
module Gitlab
module Auth
module LDAP
- class Authentication
+ class Authentication < Gitlab::Auth::OAuth::Authentication
def self.login(login, password)
return unless Gitlab::Auth::LDAP::Config.enabled?
return unless login.present? && password.present?
@@ -28,11 +28,7 @@ module Gitlab
Gitlab::Auth::LDAP::Config.providers
end
- attr_accessor :provider, :ldap_user
-
- def initialize(provider)
- @provider = provider
- end
+ attr_accessor :ldap_user
def login(login, password)
@ldap_user = adapter.bind_as(
@@ -62,7 +58,7 @@ module Gitlab
end
def user
- return nil unless ldap_user
+ return unless ldap_user
Gitlab::Auth::LDAP::User.find_by_uid_and_provider(ldap_user.dn, provider)
end
diff --git a/lib/gitlab/auth/o_auth/authentication.rb b/lib/gitlab/auth/o_auth/authentication.rb
new file mode 100644
index 00000000000..ed03b9f8b40
--- /dev/null
+++ b/lib/gitlab/auth/o_auth/authentication.rb
@@ -0,0 +1,21 @@
+# These calls help to authenticate to OAuth provider by providing username and password
+#
+
+module Gitlab
+ module Auth
+ module OAuth
+ class Authentication
+ attr_reader :provider, :user
+
+ def initialize(provider, user = nil)
+ @provider = provider
+ @user = user
+ end
+
+ def login(login, password)
+ raise NotImplementedError
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/o_auth/provider.rb b/lib/gitlab/auth/o_auth/provider.rb
index f8ab8ee1388..5fb61ffe00d 100644
--- a/lib/gitlab/auth/o_auth/provider.rb
+++ b/lib/gitlab/auth/o_auth/provider.rb
@@ -8,11 +8,28 @@ module Gitlab
"google_oauth2" => "Google"
}.freeze
+ def self.authentication(user, provider)
+ return unless user
+ return unless enabled?(provider)
+
+ authenticator =
+ case provider
+ when /^ldap/
+ Gitlab::Auth::LDAP::Authentication
+ when 'database'
+ Gitlab::Auth::Database::Authentication
+ end
+
+ authenticator&.new(provider, user)
+ end
+
def self.providers
Devise.omniauth_providers
end
def self.enabled?(name)
+ return true if name == 'database'
+
providers.include?(name.to_sym)
end
diff --git a/lib/gitlab/auth/o_auth/user.rb b/lib/gitlab/auth/o_auth/user.rb
index acd785bb02d..b6a96081278 100644
--- a/lib/gitlab/auth/o_auth/user.rb
+++ b/lib/gitlab/auth/o_auth/user.rb
@@ -161,7 +161,7 @@ module Gitlab
def find_by_uid_and_provider
identity = Identity.with_extern_uid(auth_hash.provider, auth_hash.uid).take
- identity && identity.user
+ identity&.user
end
def build_new_user
diff --git a/lib/gitlab/auth/result.rb b/lib/gitlab/auth/result.rb
index 75451cf8aa9..00cdc94a9ef 100644
--- a/lib/gitlab/auth/result.rb
+++ b/lib/gitlab/auth/result.rb
@@ -1,4 +1,4 @@
-module Gitlab
+module Gitlab # rubocop:disable Naming/FileName
module Auth
Result = Struct.new(:actor, :project, :type, :authentication_abilities) do
def ci?(for_project)
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index d48ae17aeaf..bffbcb86137 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -135,7 +135,7 @@ module Gitlab
if label.valid?
@labels[label_params[:title]] = label
else
- raise "Failed to create label \"#{label_params[:title]}\" for project \"#{project.name_with_namespace}\""
+ raise "Failed to create label \"#{label_params[:title]}\" for project \"#{project.full_name}\""
end
end
end
diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb
index 3ce5f807989..51ba09aa129 100644
--- a/lib/gitlab/checks/change_access.rb
+++ b/lib/gitlab/checks/change_access.rb
@@ -47,7 +47,7 @@ module Gitlab
protected
def push_checks
- if user_access.cannot_do_action?(:push_code)
+ unless can_push?
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_code]
end
end
@@ -183,6 +183,11 @@ module Gitlab
def commits
@commits ||= project.repository.new_commits(newrev)
end
+
+ def can_push?
+ user_access.can_do_action?(:push_code) ||
+ user_access.can_push_to_branch?(branch_name)
+ end
end
end
end
diff --git a/lib/gitlab/ci/charts.rb b/lib/gitlab/ci/charts.rb
index 525563a97f5..46ed330dbbf 100644
--- a/lib/gitlab/ci/charts.rb
+++ b/lib/gitlab/ci/charts.rb
@@ -68,10 +68,11 @@ module Gitlab
class YearChart < Chart
include MonthlyInterval
+ attr_reader :to, :from
def initialize(*)
- @to = Date.today.end_of_month
- @from = @to.years_ago(1).beginning_of_month
+ @to = Date.today.end_of_month.end_of_day
+ @from = @to.years_ago(1).beginning_of_month.beginning_of_day
@format = '%d %B %Y'
super
@@ -80,10 +81,11 @@ module Gitlab
class MonthChart < Chart
include DailyInterval
+ attr_reader :to, :from
def initialize(*)
- @to = Date.today
- @from = @to - 30.days
+ @to = Date.today.end_of_day
+ @from = 1.month.ago.beginning_of_day
@format = '%d %B'
super
@@ -92,10 +94,11 @@ module Gitlab
class WeekChart < Chart
include DailyInterval
+ attr_reader :to, :from
def initialize(*)
- @to = Date.today
- @from = @to - 7.days
+ @to = Date.today.end_of_day
+ @from = 1.week.ago.beginning_of_day
@format = '%d %B'
super
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index 7b19b10e05b..a1849b01c5d 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -1,4 +1,4 @@
-module Gitlab
+module Gitlab # rubocop:disable Naming/FileName
module Ci
module Pipeline
module Chain
diff --git a/lib/gitlab/ci/trace.rb b/lib/gitlab/ci/trace.rb
index f2e5124c8a8..cedf4171ab1 100644
--- a/lib/gitlab/ci/trace.rb
+++ b/lib/gitlab/ci/trace.rb
@@ -1,6 +1,8 @@
module Gitlab
module Ci
class Trace
+ ArchiveError = Class.new(StandardError)
+
attr_reader :job
delegate :old_trace, to: :job
@@ -93,8 +95,53 @@ module Gitlab
job.erase_old_trace!
end
+ def archive!
+ raise ArchiveError, 'Already archived' if trace_artifact
+ raise ArchiveError, 'Job is not finished yet' unless job.complete?
+
+ if current_path
+ File.open(current_path) do |stream|
+ archive_stream!(stream)
+ FileUtils.rm(current_path)
+ end
+ elsif old_trace
+ StringIO.new(old_trace, 'rb').tap do |stream|
+ archive_stream!(stream)
+ job.erase_old_trace!
+ end
+ end
+ end
+
private
+ def archive_stream!(stream)
+ clone_file!(stream, JobArtifactUploader.workhorse_upload_path) do |clone_path|
+ create_job_trace!(job, clone_path)
+ end
+ end
+
+ def clone_file!(src_stream, temp_dir)
+ FileUtils.mkdir_p(temp_dir)
+ Dir.mktmpdir('tmp-trace', temp_dir) do |dir_path|
+ temp_path = File.join(dir_path, "job.log")
+ FileUtils.touch(temp_path)
+ size = IO.copy_stream(src_stream, temp_path)
+ raise ArchiveError, 'Failed to copy stream' unless size == src_stream.size
+
+ yield(temp_path)
+ end
+ end
+
+ def create_job_trace!(job, path)
+ File.open(path) do |stream|
+ job.create_job_artifacts_trace!(
+ project: job.project,
+ file_type: :trace,
+ file: stream,
+ file_sha256: Digest::SHA256.file(path).hexdigest)
+ end
+ end
+
def ensure_path
return current_path if current_path
diff --git a/lib/gitlab/conflict/file_collection.rb b/lib/gitlab/conflict/file_collection.rb
index 0a3ae2c3760..3ccfd9a739d 100644
--- a/lib/gitlab/conflict/file_collection.rb
+++ b/lib/gitlab/conflict/file_collection.rb
@@ -1,14 +1,18 @@
module Gitlab
module Conflict
class FileCollection
+ include Gitlab::RepositoryCacheAdapter
+
attr_reader :merge_request, :resolver
def initialize(merge_request)
our_commit = merge_request.source_branch_head.raw
their_commit = merge_request.target_branch_head.raw
- target_repo = merge_request.target_project.repository.raw
+ @target_repo = merge_request.target_project.repository
@source_repo = merge_request.source_project.repository.raw
- @resolver = Gitlab::Git::Conflict::Resolver.new(target_repo, our_commit.id, their_commit.id)
+ @our_commit_id = our_commit.id
+ @their_commit_id = their_commit.id
+ @resolver = Gitlab::Git::Conflict::Resolver.new(@target_repo.raw, @our_commit_id, @their_commit_id)
@merge_request = merge_request
end
@@ -30,6 +34,17 @@ module Gitlab
end
end
+ def can_be_resolved_in_ui?
+ # Try to parse each conflict. If the MR's mergeable status hasn't been
+ # updated, ensure that we don't say there are conflicts to resolve
+ # when there are no conflict files.
+ files.each(&:lines)
+ files.any?
+ rescue Gitlab::Git::CommandError, Gitlab::Git::Conflict::Parser::UnresolvableError, Gitlab::Git::Conflict::Resolver::ConflictSideMissing
+ false
+ end
+ cache_method :can_be_resolved_in_ui?
+
def file_for_path(old_path, new_path)
files.find { |file| file.their_path == old_path && file.our_path == new_path }
end
@@ -56,6 +71,19 @@ Merge branch '#{merge_request.target_branch}' into '#{merge_request.source_branc
#{conflict_filenames.join("\n")}
EOM
end
+
+ private
+
+ def cache
+ @cache ||= begin
+ # Use the commit ids as a namespace so if the MR branches get
+ # updated we instantiate the cache under a different namespace. That
+ # way don't have to worry about explicitly invalidating the cache
+ namespace = "#{@our_commit_id}:#{@their_commit_id}"
+
+ Gitlab::RepositoryCache.new(@target_repo, extra_namespace: namespace)
+ end
+ end
end
end
end
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 9576d5a3fd8..d7369060cc5 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -23,7 +23,7 @@ module Gitlab
mr_events = event_counts(date_from, :merge_requests)
.having(action: [Event::MERGED, Event::CREATED, Event::CLOSED], target_type: "MergeRequest")
note_events = event_counts(date_from, :merge_requests)
- .having(action: [Event::COMMENTED], target_type: "Note")
+ .having(action: [Event::COMMENTED])
union = Gitlab::SQL::Union.new([repo_events, issue_events, mr_events, note_events])
events = Event.find_by_sql(union.to_sql).map(&:attributes)
diff --git a/lib/gitlab/data_builder/build.rb b/lib/gitlab/data_builder/build.rb
index 8e74e18a311..2f1445a050a 100644
--- a/lib/gitlab/data_builder/build.rb
+++ b/lib/gitlab/data_builder/build.rb
@@ -31,7 +31,7 @@ module Gitlab
# TODO: do we still need it?
project_id: project.id,
- project_name: project.name_with_namespace,
+ project_name: project.full_name,
user: {
id: user.try(:id),
diff --git a/lib/gitlab/data_builder/pipeline.rb b/lib/gitlab/data_builder/pipeline.rb
index e47fb85b5ee..1e283cc092b 100644
--- a/lib/gitlab/data_builder/pipeline.rb
+++ b/lib/gitlab/data_builder/pipeline.rb
@@ -22,6 +22,7 @@ module Gitlab
sha: pipeline.sha,
before_sha: pipeline.before_sha,
status: pipeline.status,
+ detailed_status: pipeline.detailed_status(nil).label,
stages: pipeline.stages_names,
created_at: pipeline.created_at,
finished_at: pipeline.finished_at,
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index b2fca2c16de..eabcf46cf58 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -238,9 +238,9 @@ module Gitlab
self.__send__("#{key}=", options[key.to_sym]) # rubocop:disable GitlabSecurity/PublicSend
end
- @loaded_all_data = false
# Retain the actual size before it is encoded
@loaded_size = @data.bytesize if @data
+ @loaded_all_data = @loaded_size == size
end
def binary?
@@ -255,10 +255,15 @@ module Gitlab
# memory as a Ruby string.
def load_all_data!(repository)
return if @data == '' # don't mess with submodule blobs
- return @data if @loaded_all_data
- Gitlab::GitalyClient.migrate(:git_blob_load_all_data) do |is_enabled|
- @data = begin
+ # Even if we return early, recalculate wether this blob is binary in
+ # case a blob was initialized as text but the full data isn't
+ @binary = nil
+
+ return if @loaded_all_data
+
+ @data = Gitlab::GitalyClient.migrate(:git_blob_load_all_data) do |is_enabled|
+ begin
if is_enabled
repository.gitaly_blob_client.get_blob(oid: id, limit: -1).data
else
@@ -269,7 +274,6 @@ module Gitlab
@loaded_all_data = true
@loaded_size = @data.bytesize
- @binary = nil
end
def name
diff --git a/lib/gitlab/git/branch.rb b/lib/gitlab/git/branch.rb
index ae7e88f0503..6351cfb83e3 100644
--- a/lib/gitlab/git/branch.rb
+++ b/lib/gitlab/git/branch.rb
@@ -1,6 +1,8 @@
module Gitlab
module Git
class Branch < Ref
+ STALE_BRANCH_THRESHOLD = 3.months
+
def self.find(repo, branch_name)
if branch_name.is_a?(Gitlab::Git::Branch)
branch_name
@@ -12,6 +14,18 @@ module Gitlab
def initialize(repository, name, target, target_commit)
super(repository, name, target, target_commit)
end
+
+ def active?
+ self.dereferenced_target.committed_date >= STALE_BRANCH_THRESHOLD.ago
+ end
+
+ def stale?
+ !active?
+ end
+
+ def state
+ active? ? :active : :stale
+ end
end
end
end
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index 594b6a9cbc5..93037ed8d90 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -347,7 +347,7 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/324
def to_diff
- Gitlab::GitalyClient.migrate(:commit_patch) do |is_enabled|
+ Gitlab::GitalyClient.migrate(:commit_patch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
@repository.gitaly_commit_client.patch(id)
else
diff --git a/lib/gitlab/git/gitlab_projects.rb b/lib/gitlab/git/gitlab_projects.rb
index e5a747cb987..5e1e22ae65c 100644
--- a/lib/gitlab/git/gitlab_projects.rb
+++ b/lib/gitlab/git/gitlab_projects.rb
@@ -63,11 +63,12 @@ module Gitlab
end
end
- def fetch_remote(name, timeout, force:, tags:, ssh_key: nil, known_hosts: nil)
+ def fetch_remote(name, timeout, force:, tags:, ssh_key: nil, known_hosts: nil, prune: true)
tags_option = tags ? '--tags' : '--no-tags'
logger.info "Fetching remote #{name} for repository #{repository_absolute_path}."
- cmd = %W(git fetch #{name} --prune --quiet)
+ cmd = %W(git fetch #{name} --quiet)
+ cmd << '--prune' if prune
cmd << '--force' if force
cmd << tags_option
diff --git a/lib/gitlab/git/lfs_changes.rb b/lib/gitlab/git/lfs_changes.rb
index 48434047fce..b9e5cf258f4 100644
--- a/lib/gitlab/git/lfs_changes.rb
+++ b/lib/gitlab/git/lfs_changes.rb
@@ -7,6 +7,28 @@ module Gitlab
end
def new_pointers(object_limit: nil, not_in: nil)
+ @repository.gitaly_migrate(:blob_get_new_lfs_pointers) do |is_enabled|
+ if is_enabled
+ @repository.gitaly_blob_client.get_new_lfs_pointers(@newrev, object_limit, not_in)
+ else
+ git_new_pointers(object_limit, not_in)
+ end
+ end
+ end
+
+ def all_pointers
+ @repository.gitaly_migrate(:blob_get_all_lfs_pointers) do |is_enabled|
+ if is_enabled
+ @repository.gitaly_blob_client.get_all_lfs_pointers(@newrev)
+ else
+ git_all_pointers
+ end
+ end
+ end
+
+ private
+
+ def git_new_pointers(object_limit, not_in)
@new_pointers ||= begin
rev_list.new_objects(not_in: not_in, require_path: true) do |object_ids|
object_ids = object_ids.take(object_limit) if object_limit
@@ -16,14 +38,12 @@ module Gitlab
end
end
- def all_pointers
+ def git_all_pointers
rev_list.all_objects(require_path: true) do |object_ids|
Gitlab::Git::Blob.batch_lfs_pointers(@repository, object_ids)
end
end
- private
-
def rev_list
Gitlab::Git::RevList.new(@repository, newrev: @newrev)
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index d7c373ccd6f..fbc93542619 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -228,7 +228,7 @@ module Gitlab
end
def has_local_branches?
- gitaly_migrate(:has_local_branches) do |is_enabled|
+ gitaly_migrate(:has_local_branches, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_repository_client.has_local_branches?
else
@@ -479,9 +479,8 @@ module Gitlab
raise ArgumentError.new("invalid Repository#log limit: #{limit.inspect}")
end
- # TODO support options[:all] in Gitaly https://gitlab.com/gitlab-org/gitaly/issues/1049
gitaly_migrate(:find_commits) do |is_enabled|
- if is_enabled && !options[:all]
+ if is_enabled
gitaly_commit_client.find_commits(options)
else
raw_log(options).map { |c| Commit.decorate(self, c) }
@@ -508,9 +507,8 @@ module Gitlab
def count_commits(options)
count_commits_options = process_count_commits_options(options)
- # TODO add support for options[:all] in Gitaly https://gitlab.com/gitlab-org/gitaly/issues/1050
gitaly_migrate(:count_commits) do |is_enabled|
- if is_enabled && !options[:all]
+ if is_enabled
count_commits_by_gitaly(count_commits_options)
else
count_commits_by_shelling_out(count_commits_options)
@@ -717,7 +715,7 @@ module Gitlab
end
def add_branch(branch_name, user:, target:)
- gitaly_migrate(:operation_user_create_branch) do |is_enabled|
+ gitaly_migrate(:operation_user_create_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_add_branch(branch_name, user, target)
else
@@ -727,7 +725,7 @@ module Gitlab
end
def add_tag(tag_name, user:, target:, message: nil)
- gitaly_migrate(:operation_user_add_tag) do |is_enabled|
+ gitaly_migrate(:operation_user_add_tag, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_add_tag(tag_name, user: user, target: target, message: message)
else
@@ -737,7 +735,7 @@ module Gitlab
end
def rm_branch(branch_name, user:)
- gitaly_migrate(:operation_user_delete_branch) do |is_enabled|
+ gitaly_migrate(:operation_user_delete_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_operations_client.user_delete_branch(branch_name, user)
else
@@ -812,7 +810,7 @@ module Gitlab
end
def revert(user:, commit:, branch_name:, message:, start_branch_name:, start_repository:)
- gitaly_migrate(:revert) do |is_enabled|
+ gitaly_migrate(:revert, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
args = {
user: user,
commit: commit,
@@ -878,7 +876,7 @@ module Gitlab
# Delete the specified branch from the repository
def delete_branch(branch_name)
- gitaly_migrate(:delete_branch) do |is_enabled|
+ gitaly_migrate(:delete_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_ref_client.delete_branch(branch_name)
else
@@ -905,7 +903,7 @@ module Gitlab
# create_branch("feature")
# create_branch("other-feature", "master")
def create_branch(ref, start_point = "HEAD")
- gitaly_migrate(:create_branch) do |is_enabled|
+ gitaly_migrate(:create_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_ref_client.create_branch(ref, start_point)
else
@@ -1012,7 +1010,7 @@ module Gitlab
end
def languages(ref = nil)
- Gitlab::GitalyClient.migrate(:commit_languages) do |is_enabled|
+ gitaly_migrate(:commit_languages, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_commit_client.languages(ref)
else
@@ -1191,15 +1189,9 @@ module Gitlab
end
def fsck
- gitaly_migrate(:git_fsck) do |is_enabled|
- msg, status = if is_enabled
- gitaly_fsck
- else
- shell_fsck
- end
+ msg, status = gitaly_repository_client.fsck
- raise GitError.new("Could not fsck repository: #{msg}") unless status.zero?
- end
+ raise GitError.new("Could not fsck repository: #{msg}") unless status.zero?
end
def create_from_bundle(bundle_path)
@@ -1435,22 +1427,12 @@ module Gitlab
output
end
- def can_be_merged?(source_sha, target_branch)
- gitaly_migrate(:can_be_merged) do |is_enabled|
- if is_enabled
- gitaly_can_be_merged?(source_sha, find_branch(target_branch).target)
- else
- rugged_can_be_merged?(source_sha, target_branch)
- end
- end
- end
-
- def last_commit_id_for_path(sha, path)
+ def last_commit_for_path(sha, path)
gitaly_migrate(:last_commit_for_path) do |is_enabled|
if is_enabled
- last_commit_for_path_by_gitaly(sha, path).id
+ last_commit_for_path_by_gitaly(sha, path)
else
- last_commit_id_for_path_by_shelling_out(sha, path)
+ last_commit_for_path_by_rugged(sha, path)
end
end
end
@@ -1608,14 +1590,6 @@ module Gitlab
File.write(File.join(worktree_info_path, 'sparse-checkout'), files)
end
- def gitaly_fsck
- gitaly_repository_client.fsck
- end
-
- def shell_fsck
- run_git(%W[--git-dir=#{path} fsck], nice: true)
- end
-
def rugged_fetch_source_branch(source_repository, source_branch, local_ref)
with_repo_branch_commit(source_repository, source_branch) do |commit|
if commit
@@ -1898,7 +1872,7 @@ module Gitlab
end
def last_commit_for_path_by_rugged(sha, path)
- sha = last_commit_id_for_path(sha, path)
+ sha = last_commit_id_for_path_by_shelling_out(sha, path)
commit(sha)
end
@@ -2406,14 +2380,6 @@ module Gitlab
.map { |c| commit(c) }
end
- def gitaly_can_be_merged?(their_commit, our_commit)
- !gitaly_conflicts_client(our_commit, their_commit).conflicts?
- end
-
- def rugged_can_be_merged?(their_commit, our_commit)
- !rugged.merge_commits(our_commit, their_commit).conflicts?
- end
-
def last_commit_for_path_by_gitaly(sha, path)
gitaly_commit_client.last_commit_for_path(sha, path)
end
diff --git a/lib/gitlab/gitaly_client/blob_service.rb b/lib/gitlab/gitaly_client/blob_service.rb
index dfa0fa43b0f..28554208984 100644
--- a/lib/gitlab/gitaly_client/blob_service.rb
+++ b/lib/gitlab/gitaly_client/blob_service.rb
@@ -45,16 +45,7 @@ module Gitlab
response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_lfs_pointers, request)
- response.flat_map do |message|
- message.lfs_pointers.map do |lfs_pointer|
- Gitlab::Git::Blob.new(
- id: lfs_pointer.oid,
- size: lfs_pointer.size,
- data: lfs_pointer.data,
- binary: Gitlab::Git::Blob.binary?(lfs_pointer.data)
- )
- end
- end
+ map_lfs_pointers(response)
end
def get_blobs(revision_paths, limit = -1)
@@ -80,6 +71,50 @@ module Gitlab
GitalyClient::BlobsStitcher.new(response)
end
+
+ def get_new_lfs_pointers(revision, limit, not_in)
+ request = Gitaly::GetNewLFSPointersRequest.new(
+ repository: @gitaly_repo,
+ revision: encode_binary(revision),
+ limit: limit || 0
+ )
+
+ if not_in.nil? || not_in == :all
+ request.not_in_all = true
+ else
+ request.not_in_refs += not_in
+ end
+
+ response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_new_lfs_pointers, request)
+
+ map_lfs_pointers(response)
+ end
+
+ def get_all_lfs_pointers(revision)
+ request = Gitaly::GetNewLFSPointersRequest.new(
+ repository: @gitaly_repo,
+ revision: encode_binary(revision)
+ )
+
+ response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_all_lfs_pointers, request)
+
+ map_lfs_pointers(response)
+ end
+
+ private
+
+ def map_lfs_pointers(response)
+ response.flat_map do |message|
+ message.lfs_pointers.map do |lfs_pointer|
+ Gitlab::Git::Blob.new(
+ id: lfs_pointer.oid,
+ size: lfs_pointer.size,
+ data: lfs_pointer.data,
+ binary: Gitlab::Git::Blob.binary?(lfs_pointer.data)
+ )
+ end
+ end
+ end
end
end
end
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 1ad0bf1d060..456a8a1a2d6 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -134,7 +134,8 @@ module Gitlab
def commit_count(ref, options = {})
request = Gitaly::CountCommitsRequest.new(
repository: @gitaly_repo,
- revision: encode_binary(ref)
+ revision: encode_binary(ref),
+ all: !!options[:all]
)
request.after = Google::Protobuf::Timestamp.new(seconds: options[:after].to_i) if options[:after].present?
request.before = Google::Protobuf::Timestamp.new(seconds: options[:before].to_i) if options[:before].present?
@@ -269,6 +270,7 @@ module Gitlab
offset: options[:offset],
follow: options[:follow],
skip_merges: options[:skip_merges],
+ all: !!options[:all],
disable_walk: true # This option is deprecated. The 'walk' implementation is being removed.
)
request.after = GitalyClient.timestamp(options[:after]) if options[:after]
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index fdb3247cf4d..e1bc2f9ab61 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -45,10 +45,10 @@ module Gitlab
GitalyClient.call(@storage, :repository_service, :apply_gitattributes, request)
end
- def fetch_remote(remote, ssh_auth:, forced:, no_tags:, timeout:)
+ def fetch_remote(remote, ssh_auth:, forced:, no_tags:, timeout:, prune: true)
request = Gitaly::FetchRemoteRequest.new(
repository: @gitaly_repo, remote: remote, force: forced,
- no_tags: no_tags, timeout: timeout
+ no_tags: no_tags, timeout: timeout, no_prune: !prune
)
if ssh_auth&.ssh_import?
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 92f0e0402a8..a7e055ac444 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -20,6 +20,7 @@ module Gitlab
gon.sprite_icons = IconsHelper.sprite_icon_path
gon.sprite_file_icons = IconsHelper.sprite_file_icons_path
gon.test_env = Rails.env.test?
+ gon.suggested_label_colors = LabelsHelper.suggested_colors
if current_user
gon.current_user_id = current_user.id
diff --git a/lib/gitlab/health_checks/metric.rb b/lib/gitlab/health_checks/metric.rb
index 1a2eab0b005..d62d9136886 100644
--- a/lib/gitlab/health_checks/metric.rb
+++ b/lib/gitlab/health_checks/metric.rb
@@ -1,3 +1,3 @@
-module Gitlab::HealthChecks
+module Gitlab::HealthChecks # rubocop:disable Naming/FileName
Metric = Struct.new(:name, :value, :labels)
end
diff --git a/lib/gitlab/health_checks/result.rb b/lib/gitlab/health_checks/result.rb
index 8086760023e..e323e2c9723 100644
--- a/lib/gitlab/health_checks/result.rb
+++ b/lib/gitlab/health_checks/result.rb
@@ -1,3 +1,3 @@
-module Gitlab::HealthChecks
+module Gitlab::HealthChecks # rubocop:disable Naming/FileName
Result = Struct.new(:success, :message, :labels)
end
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index bdc0f04b56b..3772ef11c7f 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -18,7 +18,10 @@ module Gitlab
'uk' => 'УкраїнÑька',
'ja' => '日本語',
'ko' => '한국어',
- 'nl_NL' => 'Nederlands'
+ 'nl_NL' => 'Nederlands',
+ 'tr_TR' => 'Türkçe',
+ 'id_ID' => 'Bahasa Indonesia',
+ 'fil_PH' => 'Filipino'
}.freeze
def available_locales
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 9f404003125..4bdd01f5e94 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -65,6 +65,7 @@ project_tree:
- :create_access_levels
- :project_feature
- :custom_attributes
+ - :project_badges
# Only include the following attributes for the models specified.
included_attributes:
@@ -125,6 +126,8 @@ excluded_attributes:
- :when
push_event_payload:
- :event_id
+ project_badges:
+ - :group_id
methods:
labels:
@@ -147,3 +150,5 @@ methods:
- :action
push_event_payload:
- :action
+ project_badges:
+ - :type
diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb
index a00795f553e..c38df9102eb 100644
--- a/lib/gitlab/import_export/importer.rb
+++ b/lib/gitlab/import_export/importer.rb
@@ -9,7 +9,7 @@ module Gitlab
@archive_file = project.import_source
@current_user = project.creator
@project = project
- @shared = Gitlab::ImportExport::Shared.new(relative_path: path_with_namespace)
+ @shared = project.import_export_shared
end
def execute
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index 759833a5ee5..cf6b7e306dd 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -16,7 +16,8 @@ module Gitlab
priorities: :label_priorities,
auto_devops: :project_auto_devops,
label: :project_label,
- custom_attributes: 'ProjectCustomAttribute' }.freeze
+ custom_attributes: 'ProjectCustomAttribute',
+ project_badges: 'Badge' }.freeze
USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id].freeze
diff --git a/lib/gitlab/import_export/shared.rb b/lib/gitlab/import_export/shared.rb
index b34cafc6876..3d3d998a6a3 100644
--- a/lib/gitlab/import_export/shared.rb
+++ b/lib/gitlab/import_export/shared.rb
@@ -1,13 +1,17 @@
module Gitlab
module ImportExport
class Shared
- attr_reader :errors, :opts
+ attr_reader :errors, :project
- def initialize(opts)
- @opts = opts
+ def initialize(project)
+ @project = project
@errors = []
end
+ def active_export_count
+ Dir[File.join(archive_path, '*')].count { |name| File.directory?(name) }
+ end
+
def export_path
@export_path ||= Gitlab::ImportExport.export_path(relative_path: relative_path)
end
@@ -31,11 +35,11 @@ module Gitlab
private
def relative_path
- File.join(opts[:relative_path], SecureRandom.hex)
+ File.join(relative_archive_path, SecureRandom.hex)
end
def relative_archive_path
- File.join(opts[:relative_path], '..')
+ @project.disk_path
end
def error_out(message, caller)
diff --git a/lib/gitlab/legacy_github_import/project_creator.rb b/lib/gitlab/legacy_github_import/project_creator.rb
index cbabe5454ca..3ce245a8050 100644
--- a/lib/gitlab/legacy_github_import/project_creator.rb
+++ b/lib/gitlab/legacy_github_import/project_creator.rb
@@ -12,9 +12,8 @@ module Gitlab
@type = type
end
- def execute
- ::Projects::CreateService.new(
- current_user,
+ def execute(extra_attrs = {})
+ attrs = {
name: name,
path: name,
description: repo.description,
@@ -24,7 +23,9 @@ module Gitlab
import_source: repo.full_name,
import_url: import_url,
skip_wiki: skip_wiki
- ).execute
+ }.merge!(extra_attrs)
+
+ ::Projects::CreateService.new(current_user, attrs).execute
end
private
diff --git a/lib/gitlab/middleware/read_only.rb b/lib/gitlab/middleware/read_only.rb
index c26656704d7..d9d5f90596f 100644
--- a/lib/gitlab/middleware/read_only.rb
+++ b/lib/gitlab/middleware/read_only.rb
@@ -1,90 +1,19 @@
module Gitlab
module Middleware
class ReadOnly
- DISALLOWED_METHODS = %w(POST PATCH PUT DELETE).freeze
- APPLICATION_JSON = 'application/json'.freeze
API_VERSIONS = (3..4)
+ def self.internal_routes
+ @internal_routes ||=
+ API_VERSIONS.map { |version| "api/v#{version}/internal" }
+ end
+
def initialize(app)
@app = app
- @whitelisted = internal_routes
end
def call(env)
- @env = env
- @route_hash = nil
-
- if disallowed_request? && Gitlab::Database.read_only?
- Rails.logger.debug('GitLab ReadOnly: preventing possible non read-only operation')
- error_message = 'You cannot do writing operations on a read-only GitLab instance'
-
- if json_request?
- return [403, { 'Content-Type' => 'application/json' }, [{ 'message' => error_message }.to_json]]
- else
- rack_flash.alert = error_message
- rack_session['flash'] = rack_flash.to_session_value
-
- return [301, { 'Location' => last_visited_url }, []]
- end
- end
-
- @app.call(env)
- end
-
- private
-
- def internal_routes
- API_VERSIONS.flat_map { |version| "api/v#{version}/internal" }
- end
-
- def disallowed_request?
- DISALLOWED_METHODS.include?(@env['REQUEST_METHOD']) && !whitelisted_routes
- end
-
- def json_request?
- request.media_type == APPLICATION_JSON
- end
-
- def rack_flash
- @rack_flash ||= ActionDispatch::Flash::FlashHash.from_session_value(rack_session)
- end
-
- def rack_session
- @env['rack.session']
- end
-
- def request
- @env['rack.request'] ||= Rack::Request.new(@env)
- end
-
- def last_visited_url
- @env['HTTP_REFERER'] || rack_session['user_return_to'] || Gitlab::Routing.url_helpers.root_url
- end
-
- def route_hash
- @route_hash ||= Rails.application.routes.recognize_path(request.url, { method: request.request_method }) rescue {}
- end
-
- def whitelisted_routes
- grack_route || @whitelisted.any? { |path| request.path.include?(path) } || lfs_route || sidekiq_route
- end
-
- def sidekiq_route
- request.path.start_with?('/admin/sidekiq')
- end
-
- def grack_route
- # Calling route_hash may be expensive. Only do it if we think there's a possible match
- return false unless request.path.end_with?('.git/git-upload-pack')
-
- route_hash[:controller] == 'projects/git_http' && route_hash[:action] == 'git_upload_pack'
- end
-
- def lfs_route
- # Calling route_hash may be expensive. Only do it if we think there's a possible match
- return false unless request.path.end_with?('/info/lfs/objects/batch')
-
- route_hash[:controller] == 'projects/lfs_api' && route_hash[:action] == 'batch'
+ ReadOnly::Controller.new(@app, env).call
end
end
end
diff --git a/lib/gitlab/middleware/read_only/controller.rb b/lib/gitlab/middleware/read_only/controller.rb
new file mode 100644
index 00000000000..45b644e6510
--- /dev/null
+++ b/lib/gitlab/middleware/read_only/controller.rb
@@ -0,0 +1,86 @@
+module Gitlab
+ module Middleware
+ class ReadOnly
+ class Controller
+ DISALLOWED_METHODS = %w(POST PATCH PUT DELETE).freeze
+ APPLICATION_JSON = 'application/json'.freeze
+ ERROR_MESSAGE = 'You cannot perform write operations on a read-only instance'.freeze
+
+ def initialize(app, env)
+ @app = app
+ @env = env
+ end
+
+ def call
+ if disallowed_request? && Gitlab::Database.read_only?
+ Rails.logger.debug('GitLab ReadOnly: preventing possible non read-only operation')
+
+ if json_request?
+ return [403, { 'Content-Type' => APPLICATION_JSON }, [{ 'message' => ERROR_MESSAGE }.to_json]]
+ else
+ rack_flash.alert = ERROR_MESSAGE
+ rack_session['flash'] = rack_flash.to_session_value
+
+ return [301, { 'Location' => last_visited_url }, []]
+ end
+ end
+
+ @app.call(@env)
+ end
+
+ private
+
+ def disallowed_request?
+ DISALLOWED_METHODS.include?(@env['REQUEST_METHOD']) &&
+ !whitelisted_routes
+ end
+
+ def json_request?
+ request.media_type == APPLICATION_JSON
+ end
+
+ def rack_flash
+ @rack_flash ||= ActionDispatch::Flash::FlashHash.from_session_value(rack_session)
+ end
+
+ def rack_session
+ @env['rack.session']
+ end
+
+ def request
+ @env['rack.request'] ||= Rack::Request.new(@env)
+ end
+
+ def last_visited_url
+ @env['HTTP_REFERER'] || rack_session['user_return_to'] || Gitlab::Routing.url_helpers.root_url
+ end
+
+ def route_hash
+ @route_hash ||= Rails.application.routes.recognize_path(request.url, { method: request.request_method }) rescue {}
+ end
+
+ def whitelisted_routes
+ grack_route || ReadOnly.internal_routes.any? { |path| request.path.include?(path) } || lfs_route || sidekiq_route
+ end
+
+ def sidekiq_route
+ request.path.start_with?('/admin/sidekiq')
+ end
+
+ def grack_route
+ # Calling route_hash may be expensive. Only do it if we think there's a possible match
+ return false unless request.path.end_with?('.git/git-upload-pack')
+
+ route_hash[:controller] == 'projects/git_http' && route_hash[:action] == 'git_upload_pack'
+ end
+
+ def lfs_route
+ # Calling route_hash may be expensive. Only do it if we think there's a possible match
+ return false unless request.path.end_with?('/info/lfs/objects/batch')
+
+ route_hash[:controller] == 'projects/lfs_api' && route_hash[:action] == 'batch'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/middleware/release_env.rb b/lib/gitlab/middleware/release_env.rb
new file mode 100644
index 00000000000..bfe8e113b5e
--- /dev/null
+++ b/lib/gitlab/middleware/release_env.rb
@@ -0,0 +1,14 @@
+module Gitlab # rubocop:disable Naming/FileName
+ module Middleware
+ # Some of middleware would hold env for no good reason even after the
+ # request had already been processed, and we could not garbage collect
+ # them due to this. Put this middleware as the first middleware so that
+ # it would clear the env after the request is done, allowing GC gets a
+ # chance to release memory for the last request.
+ ReleaseEnv = Struct.new(:app) do
+ def call(env)
+ app.call(env).tap { env.clear }
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/prometheus/additional_metrics_parser.rb b/lib/gitlab/prometheus/additional_metrics_parser.rb
index cb95daf2260..bb1172f82a1 100644
--- a/lib/gitlab/prometheus/additional_metrics_parser.rb
+++ b/lib/gitlab/prometheus/additional_metrics_parser.rb
@@ -1,10 +1,12 @@
module Gitlab
module Prometheus
module AdditionalMetricsParser
+ CONFIG_ROOT = 'config/prometheus'.freeze
+ MUTEX = Mutex.new
extend self
- def load_groups_from_yaml
- additional_metrics_raw.map(&method(:group_from_entry))
+ def load_groups_from_yaml(file_name = 'additional_metrics.yml')
+ yaml_metrics_raw(file_name).map(&method(:group_from_entry))
end
private
@@ -22,13 +24,20 @@ module Gitlab
MetricGroup.new(entry).tap(&method(:validate!))
end
- def additional_metrics_raw
- load_yaml_file&.map(&:deep_symbolize_keys).freeze
+ def yaml_metrics_raw(file_name)
+ load_yaml_file(file_name)&.map(&:deep_symbolize_keys).freeze
end
- def load_yaml_file
- @loaded_yaml_file ||= YAML.load_file(Rails.root.join('config/prometheus/additional_metrics.yml'))
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ def load_yaml_file(file_name)
+ return YAML.load_file(Rails.root.join(CONFIG_ROOT, file_name)) if Rails.env.development?
+
+ MUTEX.synchronize do
+ @loaded_yaml_cache ||= {}
+ @loaded_yaml_cache[file_name] ||= YAML.load_file(Rails.root.join(CONFIG_ROOT, file_name))
+ end
end
+ # rubocop:enable Gitlab/ModuleWithInstanceVariables
end
end
end
diff --git a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb
index 972ab75d1d5..e677ec84cd4 100644
--- a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb
+++ b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb
@@ -4,7 +4,7 @@ module Gitlab
class AdditionalMetricsDeploymentQuery < BaseQuery
include QueryAdditionalMetrics
- def query(environment_id, deployment_id)
+ def query(deployment_id)
Deployment.find_by(id: deployment_id).try do |deployment|
query_metrics(
deployment.project,
diff --git a/lib/gitlab/prometheus/queries/base_query.rb b/lib/gitlab/prometheus/queries/base_query.rb
index c60828165bd..29cab6e9c15 100644
--- a/lib/gitlab/prometheus/queries/base_query.rb
+++ b/lib/gitlab/prometheus/queries/base_query.rb
@@ -20,6 +20,10 @@ module Gitlab
def query(*args)
raise NotImplementedError
end
+
+ def self.transform_reactive_result(result)
+ result
+ end
end
end
end
diff --git a/lib/gitlab/prometheus/queries/deployment_query.rb b/lib/gitlab/prometheus/queries/deployment_query.rb
index 6e6da593178..c2626581897 100644
--- a/lib/gitlab/prometheus/queries/deployment_query.rb
+++ b/lib/gitlab/prometheus/queries/deployment_query.rb
@@ -2,7 +2,7 @@ module Gitlab
module Prometheus
module Queries
class DeploymentQuery < BaseQuery
- def query(environment_id, deployment_id)
+ def query(deployment_id)
Deployment.find_by(id: deployment_id).try do |deployment|
environment_slug = deployment.environment.slug
@@ -25,6 +25,11 @@ module Gitlab
}
end
end
+
+ def self.transform_reactive_result(result)
+ result[:metrics] = result.delete :data
+ result
+ end
end
end
end
diff --git a/lib/gitlab/prometheus/queries/environment_query.rb b/lib/gitlab/prometheus/queries/environment_query.rb
index 1d17d3cfd56..b62910c8de6 100644
--- a/lib/gitlab/prometheus/queries/environment_query.rb
+++ b/lib/gitlab/prometheus/queries/environment_query.rb
@@ -19,6 +19,11 @@ module Gitlab
}
end
end
+
+ def self.transform_reactive_result(result)
+ result[:metrics] = result.delete :data
+ result
+ end
end
end
end
diff --git a/lib/gitlab/prometheus/queries/matched_metrics_query.rb b/lib/gitlab/prometheus/queries/matched_metric_query.rb
index 5710ad47c1a..d920e9a749f 100644
--- a/lib/gitlab/prometheus/queries/matched_metrics_query.rb
+++ b/lib/gitlab/prometheus/queries/matched_metric_query.rb
@@ -1,7 +1,7 @@
module Gitlab
module Prometheus
module Queries
- class MatchedMetricsQuery < BaseQuery
+ class MatchedMetricQuery < BaseQuery
MAX_QUERY_ITEMS = 40.freeze
def query
diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb
index 0c280dc9a3c..aad76e335af 100644
--- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb
+++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb
@@ -3,9 +3,16 @@ module Gitlab
module Queries
module QueryAdditionalMetrics
def query_metrics(project, query_context)
+ matched_metrics(project).map(&query_group(query_context))
+ .select(&method(:group_with_any_metrics))
+ end
+
+ protected
+
+ def query_group(query_context)
query_processor = method(:process_query).curry[query_context]
- groups = matched_metrics(project).map do |group|
+ lambda do |group|
metrics = group.metrics.map do |metric|
{
title: metric.title,
@@ -21,8 +28,6 @@ module Gitlab
metrics: metrics.select(&method(:metric_with_any_queries))
}
end
-
- groups.select(&method(:group_with_any_metrics))
end
private
@@ -72,12 +77,17 @@ module Gitlab
end
def common_query_context(environment, timeframe_start:, timeframe_end:)
- {
- timeframe_start: timeframe_start,
- timeframe_end: timeframe_end,
+ base_query_context(timeframe_start, timeframe_end).merge({
ci_environment_slug: environment.slug,
kube_namespace: environment.project.deployment_platform&.actual_namespace || '',
environment_filter: %{container_name!="POD",environment="#{environment.slug}"}
+ })
+ end
+
+ def base_query_context(timeframe_start, timeframe_end)
+ {
+ timeframe_start: timeframe_start,
+ timeframe_end: timeframe_end
}
end
end
diff --git a/lib/gitlab/prometheus_client.rb b/lib/gitlab/prometheus_client.rb
index 659021c9ac9..b66253a10e0 100644
--- a/lib/gitlab/prometheus_client.rb
+++ b/lib/gitlab/prometheus_client.rb
@@ -57,7 +57,11 @@ module Gitlab
rescue OpenSSL::SSL::SSLError
raise PrometheusClient::Error, "#{rest_client.url} contains invalid SSL data"
rescue RestClient::ExceptionWithResponse => ex
- handle_exception_response(ex.response)
+ if ex.response
+ handle_exception_response(ex.response)
+ else
+ raise PrometheusClient::Error, "Network connection error"
+ end
rescue RestClient::Exception
raise PrometheusClient::Error, "Network connection error"
end
diff --git a/lib/gitlab/repository_cache.rb b/lib/gitlab/repository_cache.rb
new file mode 100644
index 00000000000..b1bf3ca4143
--- /dev/null
+++ b/lib/gitlab/repository_cache.rb
@@ -0,0 +1,33 @@
+# Interface to the Redis-backed cache store
+module Gitlab
+ class RepositoryCache
+ attr_reader :repository, :namespace, :backend
+
+ def initialize(repository, extra_namespace: nil, backend: Rails.cache)
+ @repository = repository
+ @namespace = "#{repository.full_path}:#{repository.project.id}"
+ @namespace += ":#{extra_namespace}" if extra_namespace
+ @backend = backend
+ end
+
+ def cache_key(type)
+ "#{type}:#{namespace}"
+ end
+
+ def expire(key)
+ backend.delete(cache_key(key))
+ end
+
+ def fetch(key, &block)
+ backend.fetch(cache_key(key), &block)
+ end
+
+ def exist?(key)
+ backend.exist?(cache_key(key))
+ end
+
+ def read(key)
+ backend.read(cache_key(key))
+ end
+ end
+end
diff --git a/lib/gitlab/repository_cache_adapter.rb b/lib/gitlab/repository_cache_adapter.rb
new file mode 100644
index 00000000000..7f64a8c9e46
--- /dev/null
+++ b/lib/gitlab/repository_cache_adapter.rb
@@ -0,0 +1,84 @@
+module Gitlab
+ module RepositoryCacheAdapter
+ extend ActiveSupport::Concern
+
+ class_methods do
+ # Wraps around the given method and caches its output in Redis and an instance
+ # variable.
+ #
+ # This only works for methods that do not take any arguments.
+ def cache_method(name, fallback: nil, memoize_only: false)
+ original = :"_uncached_#{name}"
+
+ alias_method(original, name)
+
+ define_method(name) do
+ cache_method_output(name, fallback: fallback, memoize_only: memoize_only) do
+ __send__(original) # rubocop:disable GitlabSecurity/PublicSend
+ end
+ end
+ end
+ end
+
+ # RepositoryCache to be used. Should be overridden by the including class
+ def cache
+ raise NotImplementedError
+ end
+
+ # Caches the supplied block both in a cache and in an instance variable.
+ #
+ # The cache key and instance variable are named the same way as the value of
+ # the `key` argument.
+ #
+ # This method will return `nil` if the corresponding instance variable is also
+ # set to `nil`. This ensures we don't keep yielding the block when it returns
+ # `nil`.
+ #
+ # key - The name of the key to cache the data in.
+ # fallback - A value to fall back to in the event of a Git error.
+ def cache_method_output(key, fallback: nil, memoize_only: false, &block)
+ ivar = cache_instance_variable_name(key)
+
+ if instance_variable_defined?(ivar)
+ instance_variable_get(ivar)
+ else
+ # If the repository doesn't exist and a fallback was specified we return
+ # that value inmediately. This saves us Rugged/gRPC invocations.
+ return fallback unless fallback.nil? || cache.repository.exists?
+
+ begin
+ value =
+ if memoize_only
+ yield
+ else
+ cache.fetch(key, &block)
+ end
+
+ instance_variable_set(ivar, value)
+ rescue Gitlab::Git::Repository::NoRepository
+ # Even if the above `#exists?` check passes these errors might still
+ # occur (for example because of a non-existing HEAD). We want to
+ # gracefully handle this and not cache anything
+ fallback
+ end
+ end
+ end
+
+ # Expires the caches of a specific set of methods
+ def expire_method_caches(methods)
+ methods.each do |key|
+ cache.expire(key)
+
+ ivar = cache_instance_variable_name(key)
+
+ remove_instance_variable(ivar) if instance_variable_defined?(ivar)
+ end
+ end
+
+ private
+
+ def cache_instance_variable_name(key)
+ :"@#{key.to_s.tr('?!', '')}"
+ end
+ end
+end
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 4ba44e0feef..dda7afc0999 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -125,13 +125,13 @@ module Gitlab
# Ex.
# fetch_remote(my_repo, "upstream")
#
- def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false)
+ def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false, prune: true)
gitaly_migrate(:fetch_remote) do |is_enabled|
if is_enabled
- repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, timeout: git_timeout)
+ repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, timeout: git_timeout, prune: prune)
else
storage_path = Gitlab.config.repositories.storages[repository.storage]["path"]
- local_fetch_remote(storage_path, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags)
+ local_fetch_remote(storage_path, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, prune: prune)
end
end
end
@@ -428,8 +428,8 @@ module Gitlab
)
end
- def local_fetch_remote(storage_path, repository_relative_path, remote, ssh_auth: nil, forced: false, no_tags: false)
- vars = { force: forced, tags: !no_tags }
+ def local_fetch_remote(storage_path, repository_relative_path, remote, ssh_auth: nil, forced: false, no_tags: false, prune: true)
+ vars = { force: forced, tags: !no_tags, prune: prune }
if ssh_auth&.ssh_import?
if ssh_auth.ssh_key_auth? && ssh_auth.ssh_private_key.present?
diff --git a/lib/gitlab/slash_commands/presenters/issue_new.rb b/lib/gitlab/slash_commands/presenters/issue_new.rb
index 86490a39cc1..5964bfe9960 100644
--- a/lib/gitlab/slash_commands/presenters/issue_new.rb
+++ b/lib/gitlab/slash_commands/presenters/issue_new.rb
@@ -38,7 +38,7 @@ module Gitlab
end
def project_link
- "[#{project.name_with_namespace}](#{project.web_url})"
+ "[#{project.full_name}](#{project.web_url})"
end
def author_profile_link
diff --git a/lib/gitlab/slash_commands/presenters/issue_show.rb b/lib/gitlab/slash_commands/presenters/issue_show.rb
index c99316df667..562f15f403c 100644
--- a/lib/gitlab/slash_commands/presenters/issue_show.rb
+++ b/lib/gitlab/slash_commands/presenters/issue_show.rb
@@ -53,7 +53,7 @@ module Gitlab
end
def pretext
- "Issue *#{@resource.to_reference}* from #{project.name_with_namespace}"
+ "Issue *#{@resource.to_reference}* from #{project.full_name}"
end
end
end
diff --git a/lib/gitlab/slash_commands/result.rb b/lib/gitlab/slash_commands/result.rb
index 7021b4b01b2..3669dedf0fe 100644
--- a/lib/gitlab/slash_commands/result.rb
+++ b/lib/gitlab/slash_commands/result.rb
@@ -1,4 +1,4 @@
-module Gitlab
+module Gitlab # rubocop:disable Naming/FileName
module SlashCommands
Result = Struct.new(:type, :message)
end
diff --git a/lib/gitlab/string_placeholder_replacer.rb b/lib/gitlab/string_placeholder_replacer.rb
new file mode 100644
index 00000000000..9a2219b7d77
--- /dev/null
+++ b/lib/gitlab/string_placeholder_replacer.rb
@@ -0,0 +1,27 @@
+module Gitlab
+ class StringPlaceholderReplacer
+ # This method accepts the following paras
+ # - string: the string to be analyzed
+ # - placeholder_regex: i.e. /%{project_path|project_id|default_branch|commit_sha}/
+ # - block: this block will be called with each placeholder found in the string using
+ # the placeholder regex. If the result of the block is nil, the original
+ # placeholder will be returned.
+
+ def self.replace_string_placeholders(string, placeholder_regex = nil, &block)
+ return string if string.blank? || placeholder_regex.blank? || !block_given?
+
+ replace_placeholders(string, placeholder_regex, &block)
+ end
+
+ class << self
+ private
+
+ # If the result of the block is nil, then the placeholder is returned
+ def replace_placeholders(string, placeholder_regex, &block)
+ string.gsub(/%{(#{placeholder_regex})}/) do |arg|
+ yield($~[1]) || arg
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/string_range_marker.rb b/lib/gitlab/string_range_marker.rb
index f9faa134206..c6ad997a4d4 100644
--- a/lib/gitlab/string_range_marker.rb
+++ b/lib/gitlab/string_range_marker.rb
@@ -14,7 +14,7 @@ module Gitlab
end
def mark(marker_ranges)
- return rich_line unless marker_ranges
+ return rich_line unless marker_ranges&.any?
if html_escaped
rich_marker_ranges = []
diff --git a/lib/gitlab/string_regex_marker.rb b/lib/gitlab/string_regex_marker.rb
index 7ebf1c0428c..b19aa6dea35 100644
--- a/lib/gitlab/string_regex_marker.rb
+++ b/lib/gitlab/string_regex_marker.rb
@@ -1,13 +1,15 @@
module Gitlab
class StringRegexMarker < StringRangeMarker
def mark(regex, group: 0, &block)
- regex_match = raw_line.match(regex)
- return rich_line unless regex_match
+ ranges = []
- begin_index, end_index = regex_match.offset(group)
- name_range = begin_index..(end_index - 1)
+ raw_line.scan(regex) do
+ begin_index, end_index = Regexp.last_match.offset(group)
- super([name_range], &block)
+ ranges << (begin_index..(end_index - 1))
+ end
+
+ super(ranges, &block)
end
end
end
diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb
index 91b8bb2a83f..24393f96d96 100644
--- a/lib/gitlab/user_access.rb
+++ b/lib/gitlab/user_access.rb
@@ -63,13 +63,12 @@ module Gitlab
request_cache def can_push_to_branch?(ref)
return false unless can_access_git?
+ return false unless user.can?(:push_code, project) || project.branch_allows_maintainer_push?(user, ref)
if protected?(ProtectedBranch, project, ref)
- return true if project.user_can_push_to_empty_repo?(user)
-
- protected_branch_accessible_to?(ref, action: :push)
+ project.user_can_push_to_empty_repo?(user) || protected_branch_accessible_to?(ref, action: :push)
else
- user.can?(:push_code, project)
+ true
end
end
diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb
index fa22f0e37b2..dc9391f32cf 100644
--- a/lib/gitlab/utils.rb
+++ b/lib/gitlab/utils.rb
@@ -67,5 +67,13 @@ module Gitlab
nil
end
+
+ # Used in EE
+ # Accepts either an Array or a String and returns an array
+ def ensure_array_from_string(string_or_array)
+ return string_or_array if string_or_array.is_a?(Array)
+
+ string_or_array.split(',').map(&:strip)
+ end
end
end
diff --git a/lib/gitlab/verify/job_artifacts.rb b/lib/gitlab/verify/job_artifacts.rb
new file mode 100644
index 00000000000..03500a61074
--- /dev/null
+++ b/lib/gitlab/verify/job_artifacts.rb
@@ -0,0 +1,27 @@
+module Gitlab
+ module Verify
+ class JobArtifacts < BatchVerifier
+ def name
+ 'Job artifacts'
+ end
+
+ def describe(object)
+ "Job artifact: #{object.id}"
+ end
+
+ private
+
+ def relation
+ ::Ci::JobArtifact.all
+ end
+
+ def expected_checksum(artifact)
+ artifact.file_sha256
+ end
+
+ def actual_checksum(artifact)
+ Digest::SHA256.file(artifact.file.path).hexdigest
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 823df67ea39..0b0d667d4fd 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -10,6 +10,7 @@ module Gitlab
INTERNAL_API_CONTENT_TYPE = 'application/vnd.gitlab-workhorse+json'.freeze
INTERNAL_API_REQUEST_HEADER = 'Gitlab-Workhorse-Api-Request'.freeze
NOTIFICATION_CHANNEL = 'workhorse:notifications'.freeze
+ ALLOWED_GIT_HTTP_ACTIONS = %w[git_receive_pack git_upload_pack info_refs].freeze
# Supposedly the effective key size for HMAC-SHA256 is 256 bits, i.e. 32
# bytes https://tools.ietf.org/html/rfc4868#section-2.6
@@ -17,6 +18,8 @@ module Gitlab
class << self
def git_http_ok(repository, is_wiki, user, action, show_all_refs: false)
+ raise "Unsupported action: #{action}" unless ALLOWED_GIT_HTTP_ACTIONS.include?(action.to_s)
+
project = repository.project
repo_path = repository.path_to_repo
params = {
@@ -31,24 +34,7 @@ module Gitlab
token: Gitlab::GitalyClient.token(project.repository_storage)
}
params[:Repository] = repository.gitaly_repository.to_h
-
- feature_enabled = case action.to_s
- when 'git_receive_pack'
- Gitlab::GitalyClient.feature_enabled?(
- :post_receive_pack,
- status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT
- )
- when 'git_upload_pack'
- true
- when 'info_refs'
- true
- else
- raise "Unsupported action: #{action}"
- end
-
- if feature_enabled
- params[:GitalyServer] = server
- end
+ params[:GitalyServer] = server
params
end
diff --git a/lib/haml_lint/inline_javascript.rb b/lib/haml_lint/inline_javascript.rb
index 4f776330e80..adbed20f152 100644
--- a/lib/haml_lint/inline_javascript.rb
+++ b/lib/haml_lint/inline_javascript.rb
@@ -1,4 +1,4 @@
-unless Rails.env.production?
+unless Rails.env.production? # rubocop:disable Naming/FileName
require 'haml_lint/haml_visitor'
require 'haml_lint/linter'
require 'haml_lint/linter_registry'
diff --git a/lib/mattermost/session.rb b/lib/mattermost/session.rb
index ef08bd46e17..65ccdb3c347 100644
--- a/lib/mattermost/session.rb
+++ b/lib/mattermost/session.rb
@@ -83,6 +83,12 @@ module Mattermost
end
end
+ def delete(path, options = {})
+ handle_exceptions do
+ self.class.delete(path, options.merge(headers: @headers))
+ end
+ end
+
private
def create
diff --git a/lib/mattermost/team.rb b/lib/mattermost/team.rb
index b2511f3af1d..75513a9ba04 100644
--- a/lib/mattermost/team.rb
+++ b/lib/mattermost/team.rb
@@ -16,10 +16,9 @@ module Mattermost
end
# The deletion is done async, so the response is fast.
- # On the mattermost side, this triggers an soft deletion first, after which
- # the actuall data is removed
+ # On the mattermost side, this triggers an soft deletion
def destroy(team_id:)
- session_delete("/api/v4/teams/#{team_id}?permanent=true")
+ session_delete("/api/v4/teams/#{team_id}")
end
end
end
diff --git a/lib/repository_cache.rb b/lib/repository_cache.rb
deleted file mode 100644
index 068a95790c0..00000000000
--- a/lib/repository_cache.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# Interface to the Redis-backed cache store used by the Repository model
-class RepositoryCache
- attr_reader :namespace, :backend, :project_id
-
- def initialize(namespace, project_id, backend = Rails.cache)
- @namespace = namespace
- @backend = backend
- @project_id = project_id
- end
-
- def cache_key(type)
- "#{type}:#{namespace}:#{project_id}"
- end
-
- def expire(key)
- backend.delete(cache_key(key))
- end
-
- def fetch(key, &block)
- backend.fetch(cache_key(key), &block)
- end
-
- def exist?(key)
- backend.exist?(cache_key(key))
- end
-
- def read(key)
- backend.read(cache_key(key))
- end
-end
diff --git a/lib/rouge/plugins/common_mark.rb b/lib/rouge/plugins/common_mark.rb
new file mode 100644
index 00000000000..8f9de061124
--- /dev/null
+++ b/lib/rouge/plugins/common_mark.rb
@@ -0,0 +1,20 @@
+# A rouge plugin for CommonMark markdown engine.
+# Used to highlight code generated by CommonMark.
+
+module Rouge
+ module Plugins
+ module CommonMark
+ def code_block(code, language)
+ lexer = Lexer.find_fancy(language, code) || Lexers::PlainText
+
+ formatter = rouge_formatter(lexer)
+ formatter.format(lexer.lex(code))
+ end
+
+ # override this method for custom formatting behavior
+ def rouge_formatter(lexer)
+ Formatters::HTMLLegacy.new(css_class: "highlight #{lexer.tag}")
+ end
+ end
+ end
+end
diff --git a/lib/system_check/helpers.rb b/lib/system_check/helpers.rb
index 914ed794601..6227e461d24 100644
--- a/lib/system_check/helpers.rb
+++ b/lib/system_check/helpers.rb
@@ -50,7 +50,7 @@ module SystemCheck
if should_sanitize?
"#{project.namespace_id.to_s.color(:yellow)}/#{project.id.to_s.color(:yellow)} ... "
else
- "#{project.name_with_namespace.color(:yellow)} ... "
+ "#{project.full_name.color(:yellow)} ... "
end
end
diff --git a/lib/tasks/gitlab/artifacts/check.rake b/lib/tasks/gitlab/artifacts/check.rake
new file mode 100644
index 00000000000..a105261ed51
--- /dev/null
+++ b/lib/tasks/gitlab/artifacts/check.rake
@@ -0,0 +1,8 @@
+namespace :gitlab do
+ namespace :artifacts do
+ desc 'GitLab | Artifacts | Check integrity of uploaded job artifacts'
+ task check: :environment do
+ Gitlab::Verify::RakeTask.run!(Gitlab::Verify::JobArtifacts)
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/traces.rake b/lib/tasks/gitlab/traces.rake
new file mode 100644
index 00000000000..fd2a4f2d11a
--- /dev/null
+++ b/lib/tasks/gitlab/traces.rake
@@ -0,0 +1,24 @@
+require 'logger'
+require 'resolv-replace'
+
+desc "GitLab | Archive legacy traces to trace artifacts"
+namespace :gitlab do
+ namespace :traces do
+ task archive: :environment do
+ logger = Logger.new(STDOUT)
+ logger.info('Archiving legacy traces')
+
+ Ci::Build.finished
+ .where('NOT EXISTS (?)',
+ Ci::JobArtifact.select(1).trace.where('ci_builds.id = ci_job_artifacts.job_id'))
+ .order(id: :asc)
+ .find_in_batches(batch_size: 1000) do |jobs|
+ job_ids = jobs.map { |job| [job.id] }
+
+ ArchiveTraceWorker.bulk_perform_async(job_ids)
+
+ logger.info("Scheduled #{job_ids.count} jobs. From #{job_ids.min} to #{job_ids.max}")
+ end
+ end
+ end
+end
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index badd665c08c..c996b30d7fa 100644
--- a/locale/bg/gitlab.po
+++ b/locale/bg/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 03:58-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:19-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Bulgarian\n"
"Language: bg_BG\n"
@@ -49,6 +49,9 @@ msgid_plural "%s additional commits have been omitted to prevent performance iss
msgstr[0] "%s подаване беше пропуÑнато, за да не Ñе натоварва ÑиÑтемата."
msgstr[1] "%s Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð±Ñха пропуÑнати, за да не Ñе натоварва ÑиÑтемата."
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -57,6 +60,9 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -66,6 +72,9 @@ msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr ""
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] ""
@@ -130,9 +139,15 @@ msgstr "ДобавÑне на ръководÑтво за ÑътрудничеÑ
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "ДобавÑне на лиценз"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "ДобавÑне на нова папка"
@@ -151,12 +166,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -181,6 +229,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -190,12 +244,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -208,6 +286,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -232,15 +316,15 @@ msgstr "Ðрхивиран проект! Хранилището е Ñамо за
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "ÐаиÑтина ли иÑкате да изтриете този план за Ñхема?"
-msgid "Are you sure you want to discard your changes?"
-msgstr ""
-
msgid "Are you sure you want to reset registration token?"
msgstr ""
msgid "Are you sure you want to reset the health check token?"
msgstr ""
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr ""
@@ -280,6 +364,9 @@ msgstr ""
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -304,7 +391,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -316,6 +409,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -370,13 +466,10 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "Клон"
-msgstr[1] "Клони"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "Клонът <strong>%{branch_name}</strong> беше Ñъздаден. За да наÑтроите автоматичното внедрÑване, изберете Yaml шаблон за GitLab CI и подайте промените Ñи. %{link_to_autodeploy_doc}"
@@ -669,6 +762,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -723,6 +819,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -771,6 +870,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -822,9 +924,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -960,6 +1059,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr ""
@@ -968,6 +1073,11 @@ msgid_plural "Commits"
msgstr[0] "Подаване"
msgstr[1] "ПодаваниÑ"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Commit Message"
msgstr ""
@@ -980,6 +1090,9 @@ msgstr "Съобщение за подаването"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "Подаване"
@@ -1121,6 +1234,9 @@ msgstr "Копиране на адреÑа в буфера за обмен"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "Копиране на идентификатора на подаването в буфера за обмен"
@@ -1133,9 +1249,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "Създаване на нова папка"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Създайте Ñи личен жетон за доÑтъп в акаунта Ñи, за да можете да изтеглÑте и изпращате промени чрез %{protocol}."
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "Създаване на папка"
@@ -1154,6 +1279,9 @@ msgstr ""
msgid "Create merge request"
msgstr "Създаване на заÑвка за Ñливане"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr ""
@@ -1178,6 +1306,12 @@ msgstr "Етикет"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Ñи Ñъздадете личен жетон за доÑтъп"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1232,6 +1366,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Задайте потребителÑки шаблон, използвайки ÑинтакÑиÑа на „Cron“"
@@ -1264,7 +1401,7 @@ msgstr "Име на папката"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
+msgid "Discard draft"
msgstr ""
msgid "Discover GitLab Geo."
@@ -1324,6 +1461,9 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1378,9 +1518,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1447,12 +1596,36 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "СобÑтвеникът не може да бъде променен"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "Планът за Ñхема не може да бъде премахнат"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1468,6 +1641,9 @@ msgstr ""
msgid "Files"
msgstr "Файлове"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "Филтриране по Ñъобщение"
@@ -1503,6 +1679,9 @@ msgstr "От Ñъздаването на проблема до внедрÑваÐ
msgid "From merge request merge until deploy to production"
msgstr "От прилагането на заÑвката за Ñливане до внедрÑването в крайната верÑиÑ"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr ""
@@ -1650,6 +1829,24 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -1748,6 +1945,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr "ОÑвежаването започна уÑпешно"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "ВнаÑÑне на хранилище"
@@ -1760,6 +1960,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr ""
@@ -1810,6 +2013,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1840,6 +2046,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1887,6 +2096,12 @@ msgstr ""
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "Ðаучете повече в"
@@ -1905,6 +2120,9 @@ msgstr "ÐапуÑкане на проекта"
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1914,6 +2132,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1923,6 +2144,9 @@ msgstr ""
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr ""
@@ -1953,9 +2177,6 @@ msgstr "Медиана"
msgid "Members"
msgstr ""
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr ""
@@ -1968,6 +2189,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1992,9 +2216,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "добавите SSH ключ"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -2090,9 +2323,6 @@ msgstr "ÐÑма хранилище"
msgid "No schedules"
msgstr "ÐÑма планове"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr ""
@@ -2108,6 +2338,9 @@ msgstr ""
msgid "Not enough data"
msgstr "ÐÑма доÑтатъчно данни"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "Ð¡ÑŠÐ±Ð¸Ñ‚Ð¸Ñ Ð·Ð° извеÑÑ‚Ñване"
@@ -2210,6 +2443,9 @@ msgstr ""
msgid "Options"
msgstr "Опции"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr ""
@@ -2315,6 +2551,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "вÑички"
@@ -2348,6 +2602,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr ""
@@ -2510,12 +2767,30 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2537,9 +2812,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2558,6 +2842,12 @@ msgstr ""
msgid "Push events"
msgstr ""
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2621,6 +2911,9 @@ msgstr ""
msgid "Repository"
msgstr ""
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "ЗаÑвка за доÑтъп"
@@ -2633,6 +2926,9 @@ msgstr ""
msgid "Reset runners registration token"
msgstr ""
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2644,6 +2940,9 @@ msgstr "ОтмÑна на това подаване"
msgid "Revert this merge request"
msgstr "ОтмÑна на тази заÑвка за Ñливане"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2689,12 +2988,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "Изберете формата на архива"
msgid "Select a timezone"
msgstr "Изберете чаÑова зона"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2707,6 +3012,9 @@ msgstr "Изберете целеви клон"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2719,6 +3027,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Задайте парола на акаунта Ñи, за да можете да изтеглÑте и изпращате промени чрез %{protocol}."
@@ -2728,15 +3039,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "ÐаÑтройка на „Koding“"
-msgid "Set up auto deploy"
-msgstr "ÐаÑтройка на авт. внедрÑване"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "зададете парола"
msgid "Settings"
msgstr ""
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2746,6 +3057,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2787,12 +3101,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2898,6 +3224,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "Изходен код"
@@ -2937,10 +3266,10 @@ msgstr "Преминаване към клон/етикет"
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "Етикет"
-msgstr[1] "Етикети"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Tags"
msgstr "Етикети"
@@ -3071,9 +3400,15 @@ msgstr "Ð’Ñеки може да има доÑтъп до проекта, без
msgid "The repository for this project does not exist."
msgstr "Хранилището за този проект не ÑъщеÑтвува."
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "Етапът на преглед и одобрение показва времето от Ñъздаването на заÑвката за Ñливане до прилагането Ñ. Данните ще бъдат добавени автоматично Ñлед като приложите първата Ñи заÑвка за Ñливане."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "Етапът на подготовка за издаване показва времето между прилагането на заÑвката за Ñливане и внедрÑването на кода в Ñредата на работещата крайна верÑиÑ. Данните ще бъдат добавени автоматично Ñлед като направите първото Ñи внедрÑване в крайната верÑиÑ."
@@ -3167,6 +3502,9 @@ msgstr "Това означава, че нÑма да можете да изпр
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3336,9 +3674,15 @@ msgstr[1] "мин"
msgid "Time|s"
msgstr "Ñек"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3354,19 +3698,16 @@ msgstr ""
msgid "Total Time"
msgstr "Общо време"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "Общо време за теÑтване на вÑички подаваниÑ/ÑливаниÑ"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3378,9 +3719,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3396,6 +3734,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "Без звезда"
@@ -3441,6 +3782,9 @@ msgstr "Използване на глобалната Ви наÑтройка Ð
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3477,6 +3821,9 @@ msgstr "ÐÑма доÑтатъчно данни за този етап."
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3597,6 +3944,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "ОттеглÑне на заÑвката за доÑтъп"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Ðа път Ñте да премахнете „%{group_name}“. Ðко Ñ Ð¿Ñ€ÐµÐ¼Ð°Ñ…Ð½ÐµÑ‚Ðµ, групата ÐЕ може да бъде възÑтановена! ÐÐИСТИÐРли иÑкате това?"
@@ -3609,10 +3959,13 @@ msgstr "Ðа път Ñте да премахнете връзката на раÐ
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Ðа път Ñте да прехвърлите „%{project_name_with_namespace}“ към друг ÑобÑтвеник. ÐÐИСТИÐРли иÑкате това?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3630,12 +3983,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "Ðе можете да Ñъздавате повече проекти"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "ТрÑбва да Ñе впишете, за да отбележите проект ÑÑŠÑ Ð·Ð²ÐµÐ·Ð´Ð°"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "Ðуждаете Ñе от разрешение."
@@ -3669,6 +4034,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3696,7 +4064,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3708,7 +4076,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3723,6 +4091,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3735,6 +4112,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3752,11 +4135,41 @@ msgstr[1] "дни"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3790,6 +4203,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3823,6 +4239,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3877,6 +4296,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3924,3 +4346,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index 4a0ca1e7efb..76982ff61b1 100644
--- a/locale/de/gitlab.po
+++ b/locale/de/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 04:00-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:21-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: German\n"
"Language: de_DE\n"
@@ -49,6 +49,9 @@ msgid_plural "%s additional commits have been omitted to prevent performance iss
msgstr[0] "%s zusätzlicher Commit wurde ausgelassen um Leistungsprobleme zu verhindern."
msgstr[1] "%s zusätzliche Commits wurden ausgelassen um Leistungsprobleme zu verhindern."
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -57,6 +60,9 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -66,6 +72,9 @@ msgstr "%{number_of_failures} von %{maximum_failures} Fehlschlägen. GitLab wird
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "%{number_of_failures} von %{maximum_failures} Fehlschlägen. GitLab wird es nicht weiter versuchen. Setze die Speicherinformation nach Behebung des Problems zurück."
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}: fehlgeschlagener Speicherzugriff auf Host:"
@@ -130,9 +139,15 @@ msgstr "Mitarbeitsanleitung hinzufügen"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "Lizenz hinzufügen"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "Erstelle eine neues Verzeichnis"
@@ -151,12 +166,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -181,6 +229,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -190,12 +244,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -208,6 +286,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -232,15 +316,15 @@ msgstr "Archiviertes Projekt! Repository ist nicht änderbar."
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Bist Du sicher, dass Du diesen Pipeline-Zeitplan löschen möchtest?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "Bist Du sicher, dass Du alle Änderungen zurücksetzen willst?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "Bist Du sicher, dass Du den Registrierungstoken zurücksetzen willst?"
msgid "Are you sure you want to reset the health check token?"
msgstr "Bist Du sicher, dass Du den Systemüberwachungstoken zurücksetzen willst?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "Bist Du sicher?"
@@ -280,6 +364,9 @@ msgstr ""
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -304,7 +391,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -316,6 +409,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -370,13 +466,10 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "Zweig"
-msgstr[1] "Zweige"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "Branch <strong>%{branch_name}</strong> wurde erstellt. Um die automatische Bereitstellung einzurichten, wähle eine GitLab CI Yaml Vorlage und committe Deine Änderungen. %{link_to_autodeploy_doc}"
@@ -669,6 +762,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -723,6 +819,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -771,6 +870,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -822,9 +924,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -960,6 +1059,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "Kommentare"
@@ -968,6 +1073,11 @@ msgid_plural "Commits"
msgstr[0] "Commit"
msgstr[1] "Commits"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Commit Message"
msgstr ""
@@ -980,6 +1090,9 @@ msgstr "Commit Nachricht"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "Commit"
@@ -1121,6 +1234,9 @@ msgstr "Kopiere URL in die Zwischenablage"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "Kopiere Commit SHA in die Zwischenablage"
@@ -1133,9 +1249,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "Erstelle neues Verzeichnis"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Erstelle einen persönlichen Zugriffstoken in Deinem Konto um mittels %{protocol} zu übertragen (push) oder abzurufen (pull)."
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "Erstelle Verzeichnis"
@@ -1154,6 +1279,9 @@ msgstr ""
msgid "Create merge request"
msgstr "Erstelle Merge Request"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr ""
@@ -1178,6 +1306,12 @@ msgstr "Tag "
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Erstelle einen persönlichen Zugriffstoken"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1232,6 +1366,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Erstelle ein individuelles Muster mittels Cron Syntax"
@@ -1264,8 +1401,8 @@ msgstr "Verzeichnisname"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
-msgstr "Änderungen verwerfen"
+msgid "Discard draft"
+msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
@@ -1324,6 +1461,9 @@ msgstr "E-Mails"
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1378,9 +1518,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1447,12 +1596,36 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Wechsel des Besitzers fehlgeschlagen"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "Entfernung der Pipelineplanung fehlgeschlagen"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1468,6 +1641,9 @@ msgstr ""
msgid "Files"
msgstr "Dateien"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "Filter nach Commit Nachricht"
@@ -1503,6 +1679,9 @@ msgstr "Von der Ticketbeschreibung bis zur Bereitstellung"
msgid "From merge request merge until deploy to production"
msgstr "Vom Umsetzen des Merge Request bis zur Bereitstellung auf dem Produktivsystem"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr ""
@@ -1650,6 +1829,24 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -1748,6 +1945,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr "Aufräumen erfolgreich gestartet"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "Repository importieren"
@@ -1760,6 +1960,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "Installiere einen Runner der mit GitLab CI kompatibel ist"
@@ -1810,6 +2013,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1840,6 +2046,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1887,6 +2096,12 @@ msgstr "am"
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "Erfahre mehr in den"
@@ -1905,6 +2120,9 @@ msgstr "Verlasse das Projekt"
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1914,6 +2132,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1923,6 +2144,9 @@ msgstr ""
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr ""
@@ -1953,9 +2177,6 @@ msgstr "Median"
msgid "Members"
msgstr "Mitglieder"
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr ""
@@ -1968,6 +2189,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1992,9 +2216,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "einen SSH Schlüssel hinzufügst"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr "Ãœberwachung"
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr "hier"
@@ -2090,9 +2323,6 @@ msgstr "Kein Repository"
msgid "No schedules"
msgstr "Keine Zeitpläne"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr ""
@@ -2108,6 +2338,9 @@ msgstr ""
msgid "Not enough data"
msgstr "Nicht genügend Daten"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "Benachrichtigungsereignisse"
@@ -2210,6 +2443,9 @@ msgstr ""
msgid "Options"
msgstr "Optionen"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr "Ãœbersicht"
@@ -2315,6 +2551,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "Alle"
@@ -2348,6 +2602,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr "Profil"
@@ -2510,12 +2767,30 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2537,9 +2812,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2558,6 +2842,12 @@ msgstr ""
msgid "Push events"
msgstr "Ãœbertragungsereignisse"
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2621,6 +2911,9 @@ msgstr ""
msgid "Repository"
msgstr ""
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "Anfrage auf Zugriff"
@@ -2633,6 +2926,9 @@ msgstr "Zugriffstoken für Systemzustand zurücksetzen"
msgid "Reset runners registration token"
msgstr "Registrierungstoken für Runner zurücksetzen"
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2644,6 +2940,9 @@ msgstr "Commit zurücksetzen"
msgid "Revert this merge request"
msgstr "Merge Request zurücksetzen"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr "SSH-Schlüssel"
@@ -2689,12 +2988,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "Archivierungsformat auswählen"
msgid "Select a timezone"
msgstr "Zeitzone auswählen"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2707,6 +3012,9 @@ msgstr "Zielbranch auswählen"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2719,6 +3027,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Lege ein Passwort für dein Konto fest, um mittels %{protocol} zu übertragen (push) oder abzurufen (pull)."
@@ -2728,15 +3039,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "Koding einrichten"
-msgid "Set up auto deploy"
-msgstr "Automatische Bereitstellung einrichten"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "ein Passwort festlegst"
msgid "Settings"
msgstr "Einstellungen"
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2746,6 +3057,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2787,12 +3101,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2898,6 +3224,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "Quellcode"
@@ -2937,8 +3266,8 @@ msgstr "Zu Branch/Tag wechseln"
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
msgstr[0] ""
msgstr[1] ""
@@ -3071,9 +3400,15 @@ msgstr "Auf das Projekt kann ohne Authentifizierung zugegriffen werden."
msgid "The repository for this project does not exist."
msgstr "Das Repository für das Projekt existiert nicht."
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "Die Überprüfungsphase stellt die Zeit vom Anlegen eines Merge Requests bis dessen Umsetzung dar. Sobald Du Deinen ersten Merge Request abschließt, werden dessen Daten hier automatisch angezeigt."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "Die Staging-Phase stellt die Zeit zwischen der Umsetzung eines Merge Requests und der Bereitstellung des Codes auf dem Produktivsystem dar. Sobald Du das erste Mal auf das Produktivsystem ausgeliefert hast, werden dessen Daten hier automatisch angezeigt."
@@ -3167,6 +3502,9 @@ msgstr "Dies bedeutet, dass Du keinen Code übertragen kannst, bevor Du kein lee
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3336,9 +3674,15 @@ msgstr[1] "Min."
msgid "Time|s"
msgstr "Sek."
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3354,19 +3698,16 @@ msgstr ""
msgid "Total Time"
msgstr "Gesamtzeit"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "Gesamte Testzeit für alle Commits/Merges"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3378,9 +3719,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3396,6 +3734,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "Entfavorisieren"
@@ -3441,6 +3782,9 @@ msgstr "Benutze Deine globalen Benachrichtigungseinstellungen"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3477,6 +3821,9 @@ msgstr "Es liegen nicht genügend Daten vor, um diese Phase anzuzeigen."
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3597,6 +3944,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "Zugriffsanfrage widerrufen"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Du bist dabei %{group_name} zu entfernen. Entfernte Gruppen können NICHT wiederhergestellt werden! Bist Du dir WIRKLICH sicher?"
@@ -3609,10 +3959,13 @@ msgstr "Du bist dabei, die Beziehung des Ablegers zum Ursprungsprojekt %{forked_
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Du bist dabei %{project_name_with_namespace} einem andere Besitzer zu übergeben. Bist Du dir WIRKLICH sicher?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3630,12 +3983,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "Du hast die Projektbegrenzung erreicht."
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "Du musst angemeldet sein, um ein Projekt zu favorisieren."
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "Du brauchst eine Genehmigung."
@@ -3669,6 +4034,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3696,7 +4064,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3708,7 +4076,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3723,6 +4091,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3735,6 +4112,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3752,11 +4135,41 @@ msgstr[1] "Tage"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3790,6 +4203,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3823,6 +4239,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3877,6 +4296,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3924,3 +4346,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index 7d4648c55f1..2613d719882 100644
--- a/locale/eo/gitlab.po
+++ b/locale/eo/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 03:59-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:22-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Esperanto\n"
"Language: eo_UY\n"
@@ -49,6 +49,9 @@ msgid_plural "%s additional commits have been omitted to prevent performance iss
msgstr[0] "%s enmetado estis transsaltita, por ne troÅarÄi la sistemon."
msgstr[1] "%s enmetadoj estis transsaltitaj, por ne troÅarÄi la sistemon."
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -57,6 +60,9 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -66,6 +72,9 @@ msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr ""
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] ""
@@ -130,9 +139,15 @@ msgstr "Aldoni gvidliniojn por kontribuado"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "Aldoni rajtigilon"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "Aldoni novan dosierujon"
@@ -151,12 +166,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -181,6 +229,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -190,12 +244,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -208,6 +286,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -232,15 +316,15 @@ msgstr "Arkivita projekto! La deponejo permesas nur legadon"
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Ĉu vi certe volas forigi ĉi tiun ĉenstablan planon?"
-msgid "Are you sure you want to discard your changes?"
-msgstr ""
-
msgid "Are you sure you want to reset registration token?"
msgstr ""
msgid "Are you sure you want to reset the health check token?"
msgstr ""
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr ""
@@ -280,6 +364,9 @@ msgstr ""
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -304,7 +391,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -316,6 +409,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -370,13 +466,10 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "Branĉo"
-msgstr[1] "Branĉoj"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "La branĉo <strong>%{branch_name}</strong> estis kreita. Por agordi aÅ­tomatan disponigadon, bonvolu elekti Yaml-Åablonon por GitLab CI kaj enmeti viajn ÅanÄojn. %{link_to_autodeploy_doc}"
@@ -669,6 +762,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -723,6 +819,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -771,6 +870,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -822,9 +924,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -960,6 +1059,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr ""
@@ -968,6 +1073,11 @@ msgid_plural "Commits"
msgstr[0] "Enmetado"
msgstr[1] "Enmetadoj"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Commit Message"
msgstr ""
@@ -980,6 +1090,9 @@ msgstr "MesaÄo pri la enmetado"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "Enmeti"
@@ -1121,6 +1234,9 @@ msgstr "Kopii la adreson en la kopibufron"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "Kopii la identigilon de la enmetado"
@@ -1133,9 +1249,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "Krei novan dosierujon"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Kreu propran atingoĵetonon en via konto por ebligi al vi eltiri kaj alpuÅi per %{protocol}."
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "Krei dosierujon"
@@ -1154,6 +1279,9 @@ msgstr ""
msgid "Create merge request"
msgstr "Krei peton pri kunfando"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr ""
@@ -1178,6 +1306,12 @@ msgstr "Etikedo"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "kreos propran atingoĵetonon"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1232,6 +1366,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Difini propran Åablonon, uzante la sintakson de Cron"
@@ -1264,7 +1401,7 @@ msgstr "Nomo de dosierujo"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
+msgid "Discard draft"
msgstr ""
msgid "Discover GitLab Geo."
@@ -1324,6 +1461,9 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1378,9 +1518,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1447,12 +1596,36 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Ne eblas ÅanÄi la posedanton"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "Ne eblas forigi la ĉenstablan planon"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1468,6 +1641,9 @@ msgstr ""
msgid "Files"
msgstr "Dosieroj"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "Filtri per mesaÄo"
@@ -1503,6 +1679,9 @@ msgstr "De la kreado de la problemo Äis la disponigado en la publika versio"
msgid "From merge request merge until deploy to production"
msgstr "De la kunfandado de la peto pri kunfando Äis la disponigado en la publika versio"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr ""
@@ -1650,6 +1829,24 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -1748,6 +1945,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr "La refreÅigo komenciÄis sukcese"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "Enporti deponejon"
@@ -1760,6 +1960,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr ""
@@ -1810,6 +2013,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1840,6 +2046,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1887,6 +2096,12 @@ msgstr ""
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "Lernu pli en la"
@@ -1905,6 +2120,9 @@ msgstr "Forlasi la projekton"
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1914,6 +2132,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1923,6 +2144,9 @@ msgstr ""
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr ""
@@ -1953,9 +2177,6 @@ msgstr "Mediano"
msgid "Members"
msgstr ""
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr ""
@@ -1968,6 +2189,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1992,9 +2216,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "aldonos SSH-Ålosilon"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -2090,9 +2323,6 @@ msgstr "Ne estas deponejo"
msgid "No schedules"
msgstr "Ne estas planoj"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr ""
@@ -2108,6 +2338,9 @@ msgstr ""
msgid "Not enough data"
msgstr "Ne estas sufiĉe da datenoj"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "Sciigaj eventoj"
@@ -2210,6 +2443,9 @@ msgstr ""
msgid "Options"
msgstr "Opcioj"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr ""
@@ -2315,6 +2551,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "ĉiuj"
@@ -2348,6 +2602,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr ""
@@ -2510,12 +2767,30 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2537,9 +2812,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2558,6 +2842,12 @@ msgstr ""
msgid "Push events"
msgstr ""
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2621,6 +2911,9 @@ msgstr ""
msgid "Repository"
msgstr ""
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "Peti atingeblon"
@@ -2633,6 +2926,9 @@ msgstr ""
msgid "Reset runners registration token"
msgstr ""
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2644,6 +2940,9 @@ msgstr "Malfari ĉi tiun enmetadon"
msgid "Revert this merge request"
msgstr "Malfari ĉi tiun peton pri kunfando"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2689,12 +2988,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "Elektu formaton de arkivo"
msgid "Select a timezone"
msgstr "Elektu horzonon"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2707,6 +3012,9 @@ msgstr "Elektu celan branĉon"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2719,6 +3027,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Kreu pasvorton por via konto por ebligi al vi eltiri kaj alpuÅi per %{protocol}."
@@ -2728,15 +3039,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "Agordi „Koding“"
-msgid "Set up auto deploy"
-msgstr "Agordi aÅ­tomatan disponigadon"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "kreos pasvorton"
msgid "Settings"
msgstr ""
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2746,6 +3057,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2787,12 +3101,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2898,6 +3224,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "Kodo"
@@ -2937,10 +3266,10 @@ msgstr "Iri al branĉo/etikedo"
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "Etikedo"
-msgstr[1] "Etikedoj"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Tags"
msgstr "Etikedoj"
@@ -3071,9 +3400,15 @@ msgstr "Ĉiu povas havi atingon al la projekto, sen ensaluti"
msgid "The repository for this project does not exist."
msgstr "La deponejo por ĉi tiu projekto ne ekzistas."
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "La etapo de la kontrolo montras la tempon de la kreado de la peto pri kunfando Äis Äia aplikado. La datenoj aldoniÄos aÅ­tomate post kiam vi aplikos la unuan peton pri kunfando."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "La etapo de preparo por eldono montras la tempon inter la aplikado de la peto pri kunfando kaj la disponigado de la kodo en la publika versio. La datenoj aldoniÄos aÅ­tomate post kiam vi faros la unuan disponigadon en la publika versio."
@@ -3167,6 +3502,9 @@ msgstr "Ĉi tiu signifas, ke vi ne povos alpuÅi kodon, antaÅ­ ol vi kreos malpl
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3336,9 +3674,15 @@ msgstr[1] "min"
msgid "Time|s"
msgstr "s"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3354,19 +3698,16 @@ msgstr ""
msgid "Total Time"
msgstr "Totala tempo"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "Totala tempo por la testado de ĉiuj enmetadoj/kunfandoj"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3378,9 +3719,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3396,6 +3734,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "Malsteligi"
@@ -3441,6 +3782,9 @@ msgstr "Uzi vian Äeneralan agordon pri la sciigoj"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3477,6 +3821,9 @@ msgstr "Ne estas sufiĉe da datenoj por montri ĉi tiun etapon."
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3597,6 +3944,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "Nuligi la peton pri atingeblo"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Vi forigos „%{group_name}“. Oni NE POVAS malfari la forigon de grupo! Ĉu vi estas ABSOLUTE certa?"
@@ -3609,10 +3959,13 @@ msgstr "Vi forigos la rilaton de la disbranĉigo al la originala projekto, „%{
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Vi estas transigonta „%{project_name_with_namespace}“ al alia posedanto. Ĉu vi estas ABSOLUTE certa?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3630,12 +3983,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "Vi ne povas krei pliajn projektojn"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "Oni devas ensaluti por steligi projekton"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "VI bezonas permeson."
@@ -3669,6 +4034,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3696,7 +4064,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3708,7 +4076,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3723,6 +4091,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3735,6 +4112,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3752,11 +4135,41 @@ msgstr[1] "tagoj"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3790,6 +4203,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3823,6 +4239,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3877,6 +4296,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3924,3 +4346,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index 7d28a7064d3..76926fd5c64 100644
--- a/locale/es/gitlab.po
+++ b/locale/es/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 04:01-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:20-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Spanish\n"
"Language: es_ES\n"
@@ -49,6 +49,9 @@ msgid_plural "%s additional commits have been omitted to prevent performance iss
msgstr[0] "%s cambio adicional ha sido omitido para evitar problemas de rendimiento."
msgstr[1] "%s cambios adicionales han sido omitidos para evitar problemas de rendimiento."
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -57,6 +60,9 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participante"
msgstr[1] "%{count} participantes"
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr "%{number_commits_behind} commits detrás de %{default_branch}, %{number_commits_ahead} commits por delante"
@@ -66,6 +72,9 @@ msgstr "%{number_of_failures} de %{maximum_failures} intentos fallidos. GitLab p
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "%{number_of_failures} de %{maximum_failures} intentos fallidos. GitLab no reintentará automáticamente. Debe reinicializar la información de almacenamiento cuando el problema sea solventado."
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}: intento de acceso fallido al almacenamiento en host:"
@@ -130,9 +139,15 @@ msgstr "Agregar guía de contribución"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr "Añadir Webhooks Grupales y Gitlab Enterprise Edition."
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "Agregar Licencia"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "Agregar nuevo directorio"
@@ -140,31 +155,64 @@ msgid "Add todo"
msgstr ""
msgid "AdminArea|Stop all jobs"
-msgstr ""
+msgstr "Detener todos los trabajos"
msgid "AdminArea|Stop all jobs?"
-msgstr ""
+msgstr "Detener todos los trabajos?"
msgid "AdminArea|Stop jobs"
-msgstr ""
+msgstr "Detener trabajos"
msgid "AdminArea|Stopping jobs failed"
-msgstr ""
+msgstr "Error al detener trabajos"
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr "Página de estado"
-msgid "Advanced"
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
msgstr ""
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
+msgid "Advanced"
+msgstr "Avanzado"
+
msgid "Advanced settings"
msgstr "Configuración avanzada"
msgid "All"
-msgstr ""
+msgstr "Todos"
msgid "All changes are committed"
msgstr ""
@@ -173,7 +221,7 @@ msgid "Allows you to add and manage Kubernetes clusters."
msgstr ""
msgid "An error occurred previewing the blob"
-msgstr ""
+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"
@@ -181,6 +229,12 @@ msgstr "Se produjo un error al activar/desactivar la suscripción de notificaciÃ
msgid "An error occurred when updating the issue weight"
msgstr "Se produjo un error al actualizar el peso de la incidencia"
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -190,12 +244,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr "Se produjo un error al obtener datos de la barra lateral"
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -208,6 +286,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -232,15 +316,15 @@ msgstr "¡Proyecto archivado! El repositorio es de solo lectura"
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "¿Estás seguro que deseas eliminar esta programación del pipeline?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "¿Está seguro que desea descartar sus cambios?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "¿Está seguro que desea reinicializar el token de registro?"
msgid "Are you sure you want to reset the health check token?"
msgstr "¿Está seguro que desea reinicializar el token de Verificación de Estado?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "¿Estás seguro?"
@@ -251,16 +335,16 @@ msgid "Assign custom color like #FF0000"
msgstr ""
msgid "Assign labels"
-msgstr ""
+msgstr "Asignar etiquetas"
msgid "Assign milestone"
-msgstr ""
+msgstr "Asignar milestone"
msgid "Assign to"
-msgstr ""
+msgstr "Asignar a"
msgid "Assignee"
-msgstr ""
+msgstr "Asignado a"
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Adjunte un archivo arrastrando &amp; soltando o %{upload_link}"
@@ -275,9 +359,12 @@ msgid "Authentication Log"
msgstr "Registro de Autenticación"
msgid "Author"
-msgstr "Autor"
+msgstr ""
msgid "Authors: %{authors}"
+msgstr "Autores: %{authors}"
+
+msgid "Auto DevOps enabled"
msgstr ""
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
@@ -287,24 +374,30 @@ msgid "Auto Review Apps and Auto Deploy need a domain name and a %{kubernetes} t
msgstr ""
msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
-msgstr ""
+msgstr "Tanto las Auto Review Apps como Auto Deploy necesitan un dominio para funcionar correctamente."
msgid "AutoDevOps|Auto DevOps (Beta)"
-msgstr ""
+msgstr "Auto DevOps (Beta)"
msgid "AutoDevOps|Auto DevOps documentation"
-msgstr ""
+msgstr "Documentación de Auto DevOps"
msgid "AutoDevOps|Enable in settings"
-msgstr ""
+msgstr "Habilitar en la configuración"
msgid "AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
-msgstr ""
+msgstr "Automáticamente construirán, probarán y desplegarán su aplicación con base en la configuración predefinida de CI/CD."
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
+msgstr "Más información en %{link_to_documentation}"
+
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -314,81 +407,81 @@ msgid "Avatar will be removed. Are you sure?"
msgstr ""
msgid "Average per day: %{average}"
-msgstr ""
+msgstr "Promedio por día: %{average}"
+
+msgid "Begin with the selected commit"
+msgstr "Iniciar con el commit seleccionado"
msgid "Billing"
msgstr "Facturación"
msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
-msgstr ""
+msgstr "%{group_name} está actualmente en el plan %{plan_link}."
msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
-msgstr ""
+msgstr "Aumentar o disminuir automáticamente las características de algunos Planes no está disponible actualmente."
msgid "BillingPlans|Current plan"
-msgstr ""
+msgstr "Plan actual"
msgid "BillingPlans|Customer Support"
-msgstr ""
+msgstr "Atención al cliente"
msgid "BillingPlans|Downgrade"
msgstr ""
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
-msgstr ""
+msgstr "Obtenga más información sobre cada plan al leer nuestro %{faq_link}."
msgid "BillingPlans|Manage plan"
-msgstr ""
+msgstr "Gestionar plan"
msgid "BillingPlans|Please contact %{customer_support_link} in that case."
-msgstr ""
+msgstr "Por favor contacte a %{customer_support_link} en ese caso."
msgid "BillingPlans|See all %{plan_name} features"
-msgstr ""
+msgstr "Ver todas la funcionalidades del plan %{plan_name}"
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 "Para gestionar el plan para este grupo, visite la sección de facturación de %{parent_billing_page_link}."
msgid "BillingPlans|Upgrade"
msgstr ""
msgid "BillingPlans|You are currently on the %{plan_link} plan."
-msgstr ""
+msgstr "Actualmente estás en el plan %{plan_link}."
msgid "BillingPlans|frequently asked questions"
-msgstr ""
+msgstr "preguntas frecuentes"
msgid "BillingPlans|monthly"
-msgstr ""
+msgstr "mensual"
msgid "BillingPlans|paid annually at %{price_per_year}"
-msgstr ""
+msgstr "%{price_per_year} pagados anualmente"
msgid "BillingPlans|per user"
-msgstr ""
-
-msgid "Begin with the selected commit"
-msgstr ""
+msgstr "por usuario"
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "Rama"
-msgstr[1] "Ramas"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "La rama <strong>%{branch_name}</strong> fue creada. Para configurar el auto despliegue, escoge una plantilla Yaml para GitLab CI y envía tus cambios. %{link_to_autodeploy_doc}"
msgid "Branch has changed"
-msgstr ""
+msgstr "La rama ha cambiado"
msgid "Branch is already taken"
-msgstr ""
+msgstr "La rama ya existe"
msgid "Branch name"
-msgstr ""
+msgstr "Nombre de la rama"
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Buscar ramas"
@@ -400,34 +493,34 @@ msgid "Branches"
msgstr "Ramas"
msgid "Branches|Cant find HEAD commit for this branch"
-msgstr ""
+msgstr "No puedo encontrar el commit HEAD para esta rama"
msgid "Branches|Compare"
-msgstr ""
+msgstr "Comparar"
msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
-msgstr ""
+msgstr "Borrar todas las ramas que se fusionen con '%{default_branch}'"
msgid "Branches|Delete branch"
-msgstr ""
+msgstr "Eliminar la rama"
msgid "Branches|Delete merged branches"
-msgstr ""
+msgstr "Borrar ramas fusionadas"
msgid "Branches|Delete protected branch"
-msgstr ""
+msgstr "Borrar rama protegida"
msgid "Branches|Delete protected branch '%{branch_name}'?"
-msgstr ""
+msgstr "¿Borrar rama protegida '%{branch_name}'?"
msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?"
-msgstr ""
+msgstr "El borrado de la rama '%{branch_name}' no podrá deshacerse. ¿Está seguro?"
msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
-msgstr ""
+msgstr "El borrado de las ramas fusionadas no podrá deshacerse. ¿Está usted seguro?"
msgid "Branches|Filter by branch name"
-msgstr ""
+msgstr "Filtrar por nombre de rama"
msgid "Branches|Merged into %{default_branch}"
msgstr ""
@@ -499,10 +592,10 @@ msgid "ByAuthor|by"
msgstr "por"
msgid "CI / CD"
-msgstr ""
+msgstr "CI / CD"
msgid "CI/CD configuration"
-msgstr ""
+msgstr "Configuración de CI/CD"
msgid "CICD|Jobs"
msgstr ""
@@ -511,13 +604,13 @@ msgid "Cancel"
msgstr "Cancelar"
msgid "Cancel edit"
-msgstr ""
+msgstr "Cancelar edición"
msgid "Cannot modify managed Kubernetes cluster"
msgstr ""
msgid "Change Weight"
-msgstr ""
+msgstr "Cambiar peso"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Escoger en la rama"
@@ -550,10 +643,10 @@ msgid "Check interval"
msgstr ""
msgid "Checking %{text} availability…"
-msgstr ""
+msgstr "Comprobando disponibilidad de %{text}..."
msgid "Checking branch availability..."
-msgstr ""
+msgstr "Verificando disponibilidad de la rama..."
msgid "Cherry-pick this commit"
msgstr "Escoger este cambio"
@@ -568,13 +661,13 @@ msgid "Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to s
msgstr ""
msgid "Choose file..."
-msgstr ""
+msgstr "Elegir archivo..."
msgid "Choose which groups you wish to synchronize to this secondary node."
-msgstr ""
+msgstr "Elija qué grupos desea sincronizar a este nodo secundario."
msgid "Choose which shards you wish to synchronize to this secondary node."
-msgstr ""
+msgstr "Elija qué fragmentos desea sincronizar a este nodo secundario."
msgid "CiStatusLabel|canceled"
msgstr "cancelado"
@@ -669,17 +762,20 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
-msgid "Click to expand text"
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
msgstr ""
+msgid "Click to expand text"
+msgstr "Haga clic para expandir el texto"
+
msgid "Clone repository"
msgstr ""
msgid "Close"
-msgstr ""
+msgstr "Cerrar"
msgid "Closed"
-msgstr ""
+msgstr "Cerrado"
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr ""
@@ -721,16 +817,19 @@ msgid "ClusterIntegration|Copy API URL"
msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
+msgstr "Copiar Certificado CA"
+
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
msgstr ""
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
msgid "ClusterIntegration|Copy Token"
-msgstr ""
+msgstr "Copiar Token"
msgid "ClusterIntegration|Create Kubernetes cluster"
-msgstr ""
+msgstr "Crear cluster de Kubernetes"
msgid "ClusterIntegration|Create Kubernetes cluster on Google Kubernetes Engine"
msgstr ""
@@ -739,10 +838,10 @@ msgid "ClusterIntegration|Create a new Kubernetes cluster on Google Kubernetes E
msgstr ""
msgid "ClusterIntegration|Create on GKE"
-msgstr ""
+msgstr "Crear en GKE"
msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
-msgstr ""
+msgstr "Ingrese los detalles para un cluster Kubernetes existente"
msgid "ClusterIntegration|Enter the details for your Kubernetes cluster"
msgstr ""
@@ -751,49 +850,52 @@ msgid "ClusterIntegration|Environment scope"
msgstr ""
msgid "ClusterIntegration|GitLab Integration"
-msgstr ""
+msgstr "Integración GitLab"
msgid "ClusterIntegration|GitLab Runner"
-msgstr ""
+msgstr "GitLab Runner"
msgid "ClusterIntegration|Google Cloud Platform project ID"
-msgstr ""
+msgstr "ID del proyecto de Google Cloud Platform"
msgid "ClusterIntegration|Google Kubernetes Engine"
-msgstr ""
+msgstr "Google Kubernetes Engine"
msgid "ClusterIntegration|Google Kubernetes Engine project"
-msgstr ""
+msgstr "Proyecto Google Kubernetes Engine"
msgid "ClusterIntegration|Helm Tiller"
-msgstr ""
+msgstr "Helm Tiller"
msgid "ClusterIntegration|Ingress"
msgstr ""
-msgid "ClusterIntegration|Install"
+msgid "ClusterIntegration|Ingress IP Address"
msgstr ""
+msgid "ClusterIntegration|Install"
+msgstr "Instalar"
+
msgid "ClusterIntegration|Installed"
-msgstr ""
+msgstr "Instalado"
msgid "ClusterIntegration|Installing"
-msgstr ""
+msgstr "Instalando"
msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
msgstr ""
msgid "ClusterIntegration|Integration status"
-msgstr ""
+msgstr "Estado de integración"
msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
+msgstr "cluster de Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster details"
-msgstr ""
+msgstr "Detalles del cluster de Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster integration"
-msgstr ""
+msgstr "Integración de cluster de Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster integration is disabled for this project."
msgstr ""
@@ -808,7 +910,7 @@ msgid "ClusterIntegration|Kubernetes cluster is being created on Google Kubernet
msgstr ""
msgid "ClusterIntegration|Kubernetes cluster name"
-msgstr ""
+msgstr "Nombre de cluster de Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine. Refresh the page to see Kubernetes cluster's details"
msgstr ""
@@ -820,25 +922,22 @@ msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications
msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
-msgstr ""
-
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
+msgstr "Conozca más sobre %{link_to_documentation}"
msgid "ClusterIntegration|Learn more about environments"
-msgstr ""
+msgstr "Conozca más sobre los entornos"
msgid "ClusterIntegration|Machine type"
-msgstr ""
+msgstr "Tipo de máquina"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage"
-msgstr ""
+msgstr "Administrar"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
-msgstr ""
+msgstr "Administre su cluster de Kubernetes visitando %{link_gke}"
msgid "ClusterIntegration|More information"
msgstr ""
@@ -847,19 +946,19 @@ msgid "ClusterIntegration|Multiple Kubernetes clusters are available in GitLab E
msgstr ""
msgid "ClusterIntegration|Note:"
-msgstr ""
+msgstr "Nota:"
msgid "ClusterIntegration|Number of nodes"
-msgstr ""
+msgstr "Número de nodos"
msgid "ClusterIntegration|Please enter access information for your Kubernetes cluster. If you need help, you can read our %{link_to_help_page} on Kubernetes"
msgstr ""
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
-msgstr ""
+msgstr "Asegúrese de que su cuenta de Google cumpla con los siguientes requisitos:"
msgid "ClusterIntegration|Project ID"
-msgstr ""
+msgstr "ID de Proyecto"
msgid "ClusterIntegration|Project namespace"
msgstr ""
@@ -877,43 +976,43 @@ msgid "ClusterIntegration|Remove Kubernetes cluster integration"
msgstr ""
msgid "ClusterIntegration|Remove integration"
-msgstr ""
+msgstr "Eliminar integración"
msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
msgstr ""
msgid "ClusterIntegration|Request to begin installing failed"
-msgstr ""
+msgstr "Falló la solicitud para iniciar la instalación"
msgid "ClusterIntegration|Save changes"
-msgstr ""
+msgstr "Guardar cambios"
msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
msgstr ""
msgid "ClusterIntegration|See machine types"
-msgstr ""
+msgstr "Ver tipos de máquina"
msgid "ClusterIntegration|See your projects"
-msgstr ""
+msgstr "Ver tus proyectos"
msgid "ClusterIntegration|See zones"
-msgstr ""
+msgstr "Ver zonas"
msgid "ClusterIntegration|Service token"
msgstr ""
msgid "ClusterIntegration|Show"
-msgstr ""
+msgstr "Mostrar"
msgid "ClusterIntegration|Something went wrong on our end."
-msgstr ""
+msgstr "Algo salió mal de nuestro lado."
msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster on Google Kubernetes Engine"
msgstr ""
msgid "ClusterIntegration|Something went wrong while installing %{title}"
-msgstr ""
+msgstr "Algo salió mal durante la instalación de %{title}"
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
@@ -925,51 +1024,62 @@ msgid "ClusterIntegration|Toggle Kubernetes cluster"
msgstr ""
msgid "ClusterIntegration|Token"
-msgstr ""
+msgstr "Token"
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 ""
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
-msgstr ""
+msgstr "Su cuenta debe tener %{link_to_kubernetes_engine}"
msgid "ClusterIntegration|Zone"
-msgstr ""
+msgstr "Zona"
msgid "ClusterIntegration|access to Google Kubernetes Engine"
-msgstr ""
+msgstr "acceso a Google Kubernetes Engine"
msgid "ClusterIntegration|check the pricing here"
msgstr ""
msgid "ClusterIntegration|documentation"
-msgstr ""
+msgstr "documentación"
msgid "ClusterIntegration|help page"
-msgstr ""
+msgstr "página de ayuda"
msgid "ClusterIntegration|installing applications"
-msgstr ""
+msgstr "Instalando aplicaciones"
msgid "ClusterIntegration|meets the requirements"
-msgstr ""
+msgstr "cumple con los requisitos"
msgid "ClusterIntegration|properly configured"
msgstr ""
msgid "Collapse"
+msgstr "Contraer"
+
+msgid "Comment and resolve discussion"
msgstr ""
-msgid "Comments"
+msgid "Comment and unresolve discussion"
msgstr ""
+msgid "Comments"
+msgstr "Comentarios"
+
msgid "Commit"
msgid_plural "Commits"
msgstr[0] "Cambio"
msgstr[1] "Cambios"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Commit Message"
-msgstr ""
+msgstr "Mensaje del commit"
msgid "Commit duration in minutes for last 30 commits"
msgstr "Duración de los cambios en minutos para los últimos 30"
@@ -980,6 +1090,9 @@ msgstr "Mensaje del cambio"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "Cambio"
@@ -1041,49 +1154,49 @@ msgid "CompareBranches|There isn't anything to compare."
msgstr ""
msgid "Confidentiality"
-msgstr ""
+msgstr "Confidencialidad"
msgid "Container Registry"
msgstr ""
msgid "ContainerRegistry|Created"
-msgstr ""
+msgstr "Creado"
msgid "ContainerRegistry|First log in to GitLab&rsquo;s Container Registry using your GitLab username and password. If you have %{link_2fa} you need to use a %{link_token}:"
msgstr ""
msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
-msgstr ""
+msgstr "Gitlab soporta hasta 3 niveles para nombres de imágenes. Los siguientes ejemplos de imágenes son válidos para tu proyecto:"
msgid "ContainerRegistry|How to use the Container Registry"
msgstr ""
msgid "ContainerRegistry|Learn more about"
-msgstr ""
+msgstr "Conozca más sobre"
msgid "ContainerRegistry|No tags in Container Registry for this container image."
-msgstr ""
+msgstr "No hay etiquetas en el Container Registry para esta imagen de contenedor."
msgid "ContainerRegistry|Once you log in, you&rsquo;re free to create and upload a container image using the common %{build} and %{push} commands"
-msgstr ""
+msgstr "Una vez que inicies sesión, eres libre de crear y cargar una imagen de contenedor utilizando los comandos comunes %{build} y %{push}"
msgid "ContainerRegistry|Remove repository"
-msgstr ""
+msgstr "Borrar repositorio"
msgid "ContainerRegistry|Remove tag"
-msgstr ""
+msgstr "Borrar etiqueta"
msgid "ContainerRegistry|Size"
-msgstr ""
+msgstr "Tamaño"
msgid "ContainerRegistry|Tag"
-msgstr ""
+msgstr "Etiqueta"
msgid "ContainerRegistry|Tag ID"
-msgstr ""
+msgstr "Etiqueta ID"
msgid "ContainerRegistry|Use different image names"
-msgstr ""
+msgstr "Usar nombres de imagen diferentes"
msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
msgstr ""
@@ -1113,7 +1226,7 @@ msgid "Control the maximum concurrency of repository backfill for this secondary
msgstr ""
msgid "Copy SSH public key to clipboard"
-msgstr ""
+msgstr "Copiar la clave pública SSH al portapapeles"
msgid "Copy URL to clipboard"
msgstr "Copiar URL al portapapeles"
@@ -1121,6 +1234,9 @@ msgstr "Copiar URL al portapapeles"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "Copiar SHA del cambio al portapapeles"
@@ -1128,14 +1244,23 @@ msgid "Copy reference to clipboard"
msgstr ""
msgid "Create"
-msgstr ""
+msgstr "Crear"
msgid "Create New Directory"
msgstr "Crear Nuevo Directorio"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Crear un token de acceso personal en tu cuenta para actualizar o enviar a través de %{protocol}."
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "Crear directorio"
@@ -1143,10 +1268,10 @@ msgid "Create empty bare repository"
msgstr "Crear repositorio vacío"
msgid "Create epic"
-msgstr ""
+msgstr "Crear epic"
msgid "Create file"
-msgstr ""
+msgstr "Crear archivo"
msgid "Create lists from labels. Issues with that label appear in that list."
msgstr ""
@@ -1154,17 +1279,20 @@ msgstr ""
msgid "Create merge request"
msgstr "Crear solicitud de fusión"
-msgid "Create new branch"
+msgid "Create merge request and branch"
msgstr ""
+msgid "Create new branch"
+msgstr "Crear una nueva rama"
+
msgid "Create new directory"
-msgstr ""
+msgstr "Crear nuevo directorio"
msgid "Create new file"
-msgstr ""
+msgstr "Crear nuevo archivo"
msgid "Create new label"
-msgstr ""
+msgstr "Crear nueva etiqueta"
msgid "Create new..."
msgstr "Crear nuevo..."
@@ -1178,9 +1306,15 @@ msgstr "Etiqueta"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "crear un token de acceso personal"
-msgid "Creating epic"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
msgstr ""
+msgid "Creating epic"
+msgstr "Creando epic"
+
msgid "Cron Timezone"
msgstr "Zona horaria del Cron"
@@ -1188,7 +1322,7 @@ msgid "Cron syntax"
msgstr "Sintaxis de Cron"
msgid "Current node"
-msgstr ""
+msgstr "Nodo actual"
msgid "Custom notification events"
msgstr "Eventos de notificaciones personalizadas"
@@ -1221,15 +1355,18 @@ msgid "CycleAnalyticsStage|Test"
msgstr "Pruebas"
msgid "DashboardProjects|All"
-msgstr ""
+msgstr "Todos"
msgid "DashboardProjects|Personal"
-msgstr ""
+msgstr "Personales"
msgid "Dec"
-msgstr ""
+msgstr "Dic"
msgid "December"
+msgstr "Diciembre"
+
+msgid "Default classification label"
msgstr ""
msgid "Define a custom pattern with cron syntax"
@@ -1253,7 +1390,7 @@ msgid "Description templates allow you to define context-specific templates for
msgstr ""
msgid "Details"
-msgstr ""
+msgstr "Detalles"
msgid "Diffs|No file name available"
msgstr ""
@@ -1262,9 +1399,9 @@ msgid "Directory name"
msgstr "Nombre del directorio"
msgid "Disable"
-msgstr ""
+msgstr "Deshabilitar"
-msgid "Discard changes"
+msgid "Discard draft"
msgstr ""
msgid "Discover GitLab Geo."
@@ -1322,6 +1459,9 @@ msgid "Emails"
msgstr ""
msgid "Enable"
+msgstr "Habilitar"
+
+msgid "Enable Auto DevOps"
msgstr ""
msgid "Environments|An error occurred while fetching the environments."
@@ -1367,23 +1507,32 @@ msgid "Environments|Show all"
msgstr ""
msgid "Environments|Updated"
-msgstr ""
+msgstr "Actualizado"
msgid "Environments|You don't have any environments right now."
-msgstr ""
+msgstr "No tiene ningún entorno en este momento."
msgid "Epic will be removed! Are you sure?"
msgstr ""
msgid "Epics"
+msgstr "Epics"
+
+msgid "Epics Roadmap"
msgstr ""
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
-msgid "Error creating epic"
+msgid "Error checking branch data. Please try again."
msgstr ""
+msgid "Error committing changes. Please try again."
+msgstr ""
+
+msgid "Error creating epic"
+msgstr "Error creando epic"
+
msgid "Error fetching contributors data."
msgstr ""
@@ -1400,7 +1549,7 @@ msgid "Error fetching usage ping data."
msgstr ""
msgid "Error occurred when toggling the notification subscription"
-msgstr ""
+msgstr "Se produjo un error al activar/desactivar la suscripción de notificación"
msgid "Error saving label update."
msgstr ""
@@ -1415,7 +1564,7 @@ msgid "EventFilterBy|Filter by all"
msgstr ""
msgid "EventFilterBy|Filter by comments"
-msgstr ""
+msgstr "Filtrar por comentarios"
msgid "EventFilterBy|Filter by issue events"
msgstr ""
@@ -1427,7 +1576,7 @@ msgid "EventFilterBy|Filter by push events"
msgstr ""
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "Filtrar por equipo"
msgid "Every day (at 4:00am)"
msgstr "Todos los días (a las 4:00 am)"
@@ -1439,35 +1588,62 @@ msgid "Every week (Sundays at 4:00am)"
msgstr "Todas las semanas (domingos a las 4:00 am)"
msgid "Expand"
-msgstr ""
+msgstr "Expandir"
msgid "Explore projects"
-msgstr ""
+msgstr "Explorar proyectos"
msgid "Explore public groups"
+msgstr "Explorar grupos públicos"
+
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
msgstr ""
msgid "Failed to change the owner"
msgstr "Error al cambiar el propietario"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "Error al eliminar la programación del pipeline"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
msgid "February"
-msgstr ""
+msgstr "Febrero"
msgid "Fields on this page are now uneditable, you can configure"
msgstr ""
msgid "File name"
-msgstr ""
+msgstr "Nombre de archivo"
msgid "Files"
msgstr "Archivos"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "Filtrar por mensaje del cambio"
@@ -1495,7 +1671,7 @@ msgid "ForkedFromProjectPath|Forked from %{project_name} (deleted)"
msgstr ""
msgid "Format"
-msgstr ""
+msgstr "Formato"
msgid "From issue creation until deploy to production"
msgstr "Desde la creación de la incidencia hasta el despliegue a producción"
@@ -1503,9 +1679,12 @@ msgstr "Desde la creación de la incidencia hasta el despliegue a producción"
msgid "From merge request merge until deploy to production"
msgstr "Desde la integración de la solicitud de fusión hasta el despliegue a producción"
-msgid "GPG Keys"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
msgstr ""
+msgid "GPG Keys"
+msgstr "Llaves GPG"
+
msgid "Generate a default set of labels"
msgstr ""
@@ -1513,10 +1692,10 @@ msgid "Geo Nodes"
msgstr ""
msgid "GeoNodeSyncStatus|Node is failing or broken."
-msgstr ""
+msgstr "El nodo está fallando o dañado."
msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
-msgstr ""
+msgstr "El nodo está lento, sobrecargado o se esta recuperando de una interrupción."
msgid "GeoNodes|Database replication lag:"
msgstr ""
@@ -1603,7 +1782,7 @@ msgid "Geo|All projects"
msgstr ""
msgid "Geo|File sync capacity"
-msgstr ""
+msgstr "Capacidad de sincronización de archivos"
msgid "Geo|Groups to synchronize"
msgstr ""
@@ -1615,10 +1794,10 @@ msgid "Geo|Projects in certain storage shards"
msgstr ""
msgid "Geo|Repository sync capacity"
-msgstr ""
+msgstr "Capacidad de sincronización del Repositorio"
msgid "Geo|Select groups to replicate."
-msgstr ""
+msgstr "Seleccionar grupos a replicar."
msgid "Geo|Shards to synchronize"
msgstr ""
@@ -1633,7 +1812,7 @@ msgid "Git version"
msgstr ""
msgid "GitLab Runner section"
-msgstr ""
+msgstr "Sección GitLab Runner"
msgid "Gitaly Servers"
msgstr ""
@@ -1645,14 +1824,32 @@ msgid "GoToYourFork|Fork"
msgstr "Bifurcación"
msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
-msgstr ""
+msgstr "La autenticación de Google no se encuentra %{link_to_documentation}. Pregúntale a tu administrador de GitLab si quieres usar este servicio."
msgid "Got it!"
msgstr ""
-msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
msgstr ""
+msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
+msgstr "Prevenir que se comparta un proyecto de %{group} con otros grupos"
+
msgid "GroupSettings|Share with group lock"
msgstr ""
@@ -1681,7 +1878,7 @@ msgid "GroupsEmptyState|If you organize your projects under a group, it works li
msgstr ""
msgid "GroupsEmptyState|No groups found"
-msgstr ""
+msgstr "No se encuentran grupos"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
@@ -1690,31 +1887,31 @@ msgid "GroupsTree|Are you sure you want to leave the \"${group.fullName}\" group
msgstr ""
msgid "GroupsTree|Create a project in this group."
-msgstr ""
+msgstr "Crear un proyecto en este grupo."
msgid "GroupsTree|Create a subgroup in this group."
-msgstr ""
+msgstr "Crear un sub-grupo en este grupo."
msgid "GroupsTree|Edit group"
-msgstr ""
+msgstr "Editar grupo"
msgid "GroupsTree|Failed to leave the group. Please make sure you are not the only owner."
-msgstr ""
+msgstr "No pudiste dejar el grupo. Por favor, asegúrate que no seas el único propietario."
msgid "GroupsTree|Filter by name..."
-msgstr ""
+msgstr "Filtrar por nombre..."
msgid "GroupsTree|Leave this group"
-msgstr ""
+msgstr "Dejar este grupo"
msgid "GroupsTree|Loading groups"
-msgstr ""
+msgstr "Cargando grupos"
msgid "GroupsTree|Sorry, no groups matched your search"
-msgstr ""
+msgstr "Lo sentimos, no existen grupos que coincidan con su búsqueda"
msgid "GroupsTree|Sorry, no groups or projects matched your search"
-msgstr ""
+msgstr "Lo sentimos, no existen grupos ni proyectos que coincidan con su búsqueda"
msgid "Have your users email"
msgstr ""
@@ -1726,16 +1923,16 @@ msgid "Health information can be retrieved from the following endpoints. More in
msgstr ""
msgid "HealthCheck|Access token is"
-msgstr ""
+msgstr "Token de Acceso es"
msgid "HealthCheck|Healthy"
-msgstr ""
+msgstr "Saludable"
msgid "HealthCheck|No Health Problems Detected"
msgstr ""
msgid "HealthCheck|Unhealthy"
-msgstr ""
+msgstr "Poco Saludable"
msgid "Hide value"
msgid_plural "Hide values"
@@ -1743,30 +1940,36 @@ msgstr[0] ""
msgstr[1] ""
msgid "History"
-msgstr ""
+msgstr "Historial"
msgid "Housekeeping successfully started"
msgstr "Servicio de limpieza iniciado con éxito"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "Importar repositorio"
msgid "Improve Issue boards with GitLab Enterprise Edition."
-msgstr ""
+msgstr "Mejore los tableros de Incidencias con GitLab Enterprise Edition."
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
-msgstr ""
+msgstr "Mejore la gestión de incidencias con Peso de Incidencias y GitLab Enterprise Edition."
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
-msgid "Install a Runner compatible with GitLab CI"
+msgid "Install Runner on Kubernetes"
msgstr ""
+msgid "Install a Runner compatible with GitLab CI"
+msgstr "Instala un Runner compatible con GitLab CI"
+
msgid "Instance"
msgid_plural "Instances"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Instancia"
+msgstr[1] "Instancias"
msgid "Instance does not support multiple Kubernetes clusters"
msgstr ""
@@ -1775,10 +1978,10 @@ msgid "Interested parties can even contribute by pushing commits if they want to
msgstr ""
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
-msgstr ""
+msgstr "Interno - cualquier usuario que haya iniciado sesión puede ver el grupo y cualquier proyecto interno."
msgid "Internal - The project can be accessed by any logged in user."
-msgstr ""
+msgstr "Interno - cualquier usuario haya iniciado sesión puede acceder a este proyecto."
msgid "Interval Pattern"
msgstr "Patrón de intervalo"
@@ -1787,16 +1990,16 @@ msgid "Introducing Cycle Analytics"
msgstr "Introducción a Cycle Analytics"
msgid "Issue board focus mode"
-msgstr ""
+msgstr "Modo enfocado del Tablero de Incidencias"
msgid "Issue events"
-msgstr ""
+msgstr "Eventos de incidencia"
msgid "IssueBoards|Board"
-msgstr ""
+msgstr "Tablero"
msgid "IssueBoards|Boards"
-msgstr ""
+msgstr "Tableros"
msgid "Issues"
msgstr ""
@@ -1808,6 +2011,9 @@ msgid "Jan"
msgstr ""
msgid "January"
+msgstr "Enero"
+
+msgid "Jobs"
msgstr ""
msgid "Jul"
@@ -1820,7 +2026,7 @@ msgid "Jun"
msgstr ""
msgid "June"
-msgstr ""
+msgstr "Junio"
msgid "Kubernetes"
msgstr ""
@@ -1840,6 +2046,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1870,13 +2079,13 @@ msgid "Last edited %{date}"
msgstr ""
msgid "Last edited by %{name}"
-msgstr ""
+msgstr "Última edición por %{name}"
msgid "Last update"
-msgstr ""
+msgstr "Última actualización"
msgid "Last updated"
-msgstr ""
+msgstr "Última actualización"
msgid "LastPushEvent|You pushed to"
msgstr ""
@@ -1885,6 +2094,12 @@ msgid "LastPushEvent|at"
msgstr ""
msgid "Learn more"
+msgstr "Conozca más"
+
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
msgstr ""
msgid "Learn more in the"
@@ -1903,28 +2118,37 @@ msgid "Leave project"
msgstr "Abandonar proyecto"
msgid "License"
+msgstr "Licencia"
+
+msgid "List"
msgstr ""
msgid "Loading the GitLab IDE..."
msgstr ""
msgid "Lock"
-msgstr ""
+msgstr "Bloquear"
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
msgid "Locked"
-msgstr ""
+msgstr "Bloqueado"
msgid "Locked Files"
+msgstr "Archivos Bloqueados"
+
+msgid "Locks give the ability to lock specific file or folder."
msgstr ""
msgid "Login"
-msgstr ""
+msgstr "Iniciar sesión"
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 ""
@@ -1936,7 +2160,7 @@ msgid "Mar"
msgstr ""
msgid "March"
-msgstr ""
+msgstr "Marzo"
msgid "Mark done"
msgstr ""
@@ -1951,10 +2175,7 @@ msgid "Median"
msgstr "Mediana"
msgid "Members"
-msgstr ""
-
-msgid "Merge Request"
-msgstr ""
+msgstr "Miembros"
msgid "Merge Requests"
msgstr ""
@@ -1968,11 +2189,14 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
msgid "Messages"
-msgstr ""
+msgstr "Mensajes"
msgid "Milestone"
msgstr ""
@@ -1992,9 +2216,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "agregar una clave SSH"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -2028,19 +2261,19 @@ msgid "New branch"
msgstr "Nueva rama"
msgid "New branch unavailable"
-msgstr ""
+msgstr "Nueva rama no disponible"
msgid "New directory"
msgstr "Nuevo directorio"
msgid "New epic"
-msgstr ""
+msgstr "Nuevo epic"
msgid "New file"
msgstr "Nuevo archivo"
msgid "New group"
-msgstr ""
+msgstr "Nuevo grupo"
msgid "New issue"
msgstr "Nueva incidencia"
@@ -2052,7 +2285,7 @@ msgid "New merge request"
msgstr "Nueva solicitud de fusión"
msgid "New project"
-msgstr ""
+msgstr "Nuevo proyecto"
msgid "New schedule"
msgstr "Nueva programación"
@@ -2061,7 +2294,7 @@ msgid "New snippet"
msgstr "Nuevo fragmento de código"
msgid "New subgroup"
-msgstr ""
+msgstr "Nuevo sub-grupo"
msgid "New tag"
msgstr "Nueva etiqueta"
@@ -2090,11 +2323,8 @@ msgstr "No hay repositorio"
msgid "No schedules"
msgstr "No hay programaciones"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
-msgstr ""
+msgstr "Ninguno"
msgid "Not allowed to merge"
msgstr ""
@@ -2108,6 +2338,9 @@ msgstr ""
msgid "Not enough data"
msgstr "No hay suficientes datos"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "Eventos de notificación"
@@ -2163,7 +2396,7 @@ msgid "NotificationLevel|Watch"
msgstr "Vigilancia"
msgid "Notifications"
-msgstr ""
+msgstr "Notificaciones"
msgid "Notifications off"
msgstr ""
@@ -2175,7 +2408,7 @@ msgid "Nov"
msgstr ""
msgid "November"
-msgstr ""
+msgstr "Noviembre"
msgid "Number of access attempts"
msgstr ""
@@ -2187,32 +2420,35 @@ msgid "Oct"
msgstr ""
msgid "October"
-msgstr ""
+msgstr "Octubre"
msgid "OfSearchInADropdown|Filter"
msgstr "Filtrar"
msgid "Only project members can comment."
-msgstr ""
+msgstr "Sólo los miembros de proyecto pueden comentar."
msgid "Open"
msgstr ""
msgid "Opened"
-msgstr ""
+msgstr "Abierto"
msgid "OpenedNDaysAgo|Opened"
msgstr "Abierto"
msgid "Opens in a new window"
-msgstr ""
+msgstr "Abre en una nueva ventana"
msgid "Options"
msgstr "Opciones"
-msgid "Overview"
+msgid "Otherwise it is recommended you start with one of the options below."
msgstr ""
+msgid "Overview"
+msgstr "Resumen"
+
msgid "Owner"
msgstr "Propietario"
@@ -2229,10 +2465,10 @@ msgid "Pagination|« First"
msgstr ""
msgid "Password"
-msgstr ""
+msgstr "Contraseña"
msgid "Pipeline"
-msgstr ""
+msgstr "Pipeline"
msgid "Pipeline Health"
msgstr "Estado del Pipeline"
@@ -2295,7 +2531,7 @@ msgid "PipelineSheduleIntervalPattern|Custom"
msgstr "Personalizado"
msgid "Pipelines"
-msgstr ""
+msgstr "Pipelines"
msgid "Pipelines charts"
msgstr "Gráficos de los pipelines"
@@ -2315,6 +2551,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "todos"
@@ -2337,19 +2591,22 @@ msgid "Please solve the reCAPTCHA"
msgstr ""
msgid "Preferences"
-msgstr ""
+msgstr "Preferencias"
msgid "Primary"
msgstr ""
msgid "Private - Project access must be granted explicitly to each user."
-msgstr ""
+msgstr "Privado - El acceso al proyecto debe ser concedido explícitamente para cada usuario."
msgid "Private - The group and its projects can only be viewed by members."
+msgstr "Privado - El grupo y sus proyectos sólo pueden ser vistos por sus miembros."
+
+msgid "Private projects can be created in your personal namespace with:"
msgstr ""
msgid "Profile"
-msgstr ""
+msgstr "Perfil"
msgid "Profiles|Account scheduled for removal."
msgstr ""
@@ -2367,31 +2624,31 @@ msgid "Profiles|Deleting an account has the following effects:"
msgstr ""
msgid "Profiles|Invalid password"
-msgstr ""
+msgstr "Contraseña inválida"
msgid "Profiles|Invalid username"
-msgstr ""
+msgstr "Nombre de usuario inválido"
msgid "Profiles|Type your %{confirmationValue} to confirm:"
-msgstr ""
+msgstr "Escribe tu %{confirmationValue} para confirmar:"
msgid "Profiles|You don't have access to delete this user."
-msgstr ""
+msgstr "No tienes acceso para eliminar este usuario."
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
-msgstr ""
+msgstr "Debes transferir o eliminar estos grupos antes de que puedas eliminar tu cuenta."
msgid "Profiles|Your account is currently an owner in these groups:"
-msgstr ""
+msgstr "Actualmente su cuenta es propietaria de estos grupos:"
msgid "Profiles|your account"
-msgstr ""
+msgstr "tu cuenta"
msgid "Programming languages used in this repository"
msgstr ""
msgid "Project '%{project_name}' is in the process of being deleted."
-msgstr ""
+msgstr "Proyecto '%{project_name}' está en proceso de ser eliminado."
msgid "Project '%{project_name}' queued for deletion."
msgstr "Proyecto ‘%{project_name}’ en cola para eliminación."
@@ -2415,7 +2672,7 @@ msgid "Project cache successfully reset."
msgstr ""
msgid "Project details"
-msgstr ""
+msgstr "Detalles del Proyecto"
msgid "Project export could not be deleted."
msgstr "No se pudo eliminar la exportación del proyecto."
@@ -2430,7 +2687,7 @@ msgid "Project export started. A download link will be sent by email."
msgstr "Se inició la exportación del proyecto. Se enviará un enlace de descarga por correo electrónico."
msgid "ProjectActivityRSS|Subscribe"
-msgstr ""
+msgstr "Suscribirse"
msgid "ProjectCreationLevel|Allowed to create projects"
msgstr ""
@@ -2469,98 +2726,131 @@ msgid "ProjectNetworkGraph|Graph"
msgstr "Historial gráfico"
msgid "ProjectSettings|Contact an admin to change this setting."
-msgstr ""
+msgstr "Póngase en contacto con un administrador para cambiar esta opción."
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
-msgstr ""
+msgstr "Solo se pueden enviar commits firmados a este repositorio."
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
-msgstr ""
+msgstr "Esta configuración se aplica a nivel del servidor y puede ser redefinida por un administrador."
msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
-msgstr ""
+msgstr "Esta configuración se aplica a nivel del servidor pero se ha redefinido para este proyecto."
msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
-msgstr ""
+msgstr "Esta configuración se aplicará a todos los proyectos a menos que sea redefinida por un administrador."
msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
msgstr ""
msgid "Projects"
-msgstr ""
+msgstr "Proyectos"
msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
-msgstr ""
+msgstr "Cargando proyectos"
msgid "ProjectsDropdown|Projects you visit often will appear here"
msgstr ""
msgid "ProjectsDropdown|Search your projects"
-msgstr ""
+msgstr "Busca en tus proyectos"
msgid "ProjectsDropdown|Something went wrong on our end."
-msgstr ""
+msgstr "Algo salió mal por nuestra parte."
msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr ""
+msgstr "Lo sentimos, no hay proyectos que coincidan con su búsqueda"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
+msgstr "Esta función requiere que el navegador soporte localStorage"
+
+msgid "PrometheusService|Active"
msgstr ""
-msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr "De manera predeterminada, Prometheus escucha en 'http://localhost:9090'. No se recomienda cambiar la dirección y el puerto predeterminados, ya que esto podría afectar o entrar en conflicto con otros servicios que se ejecutan en el servidor de GitLab."
+
msgid "PrometheusService|Finding and configuring metrics..."
+msgstr "Encontrar y configurar métricas..."
+
+msgid "PrometheusService|Install Prometheus on clusters"
msgstr ""
-msgid "PrometheusService|Metrics"
+msgid "PrometheusService|Manage clusters"
msgstr ""
-msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgid "PrometheusService|Manual configuration"
msgstr ""
+msgid "PrometheusService|Metrics"
+msgstr "Métricas"
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr "Las métricas se configuran y supervisan automáticamente en función de una biblioteca de métricas de exportadores populares."
+
msgid "PrometheusService|Missing environment variable"
-msgstr ""
+msgstr "Falta la variable de entorno"
msgid "PrometheusService|Monitored"
-msgstr ""
+msgstr "Monitoreado"
msgid "PrometheusService|More information"
-msgstr ""
+msgstr "Más información"
msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
-msgstr ""
+msgstr "No se están supervisando las métricas. Para comenzar a monitorear, despliega en un entorno."
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr "URL Base de Prometheus, como http://prometheus.example.com/"
+
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
msgstr ""
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
-msgid "PrometheusService|View environments"
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
msgstr ""
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr "Ver entornos"
+
msgid "Protip:"
msgstr ""
msgid "Public - The group and any public projects can be viewed without any authentication."
-msgstr ""
+msgstr "Público - El grupo y cualquier proyecto público puede ser visto sin autenticación."
msgid "Public - The project can be accessed without any authentication."
-msgstr ""
+msgstr "Público - El proyecto puede ser accedido sin ninguna autenticación."
msgid "Push Rules"
-msgstr ""
+msgstr "Reglas Push"
msgid "Push events"
+msgstr "Eventos Push"
+
+msgid "Push project from command line"
msgstr ""
-msgid "PushRule|Committer restriction"
+msgid "Push to create a project"
msgstr ""
+msgid "PushRule|Committer restriction"
+msgstr "Restricción de Committer"
+
msgid "Quick actions can be used in the issues description and comment boxes."
msgstr ""
@@ -2583,7 +2873,7 @@ msgid "Register / Sign In"
msgstr ""
msgid "Registry"
-msgstr ""
+msgstr "Registro"
msgid "Related Commits"
msgstr "Cambios Relacionados"
@@ -2619,6 +2909,9 @@ msgid "Repair authentication"
msgstr ""
msgid "Repository"
+msgstr "Repositorio"
+
+msgid "Repository has no locks."
msgstr ""
msgid "Request Access"
@@ -2631,6 +2924,9 @@ msgid "Reset health check access token"
msgstr ""
msgid "Reset runners registration token"
+msgstr "Reinicializar el token de registro del runner"
+
+msgid "Resolve discussion"
msgstr ""
msgid "Reveal value"
@@ -2644,11 +2940,14 @@ msgstr "Revertir este cambio"
msgid "Revert this merge request"
msgstr "Revertir esta solicitud de fusión"
-msgid "SSH Keys"
+msgid "Roadmap"
msgstr ""
+msgid "SSH Keys"
+msgstr "Llaves SSH"
+
msgid "Save changes"
-msgstr ""
+msgstr "Guardar los cambios"
msgid "Save pipeline schedule"
msgstr "Guardar programación del pipeline"
@@ -2681,20 +2980,26 @@ msgid "Search users"
msgstr ""
msgid "Seconds before reseting failure information"
-msgstr ""
+msgstr "Segundos antes de reinicializar información de fallas"
msgid "Seconds to wait for a storage access attempt"
-msgstr ""
+msgstr "Segundos a esperar para intentar acceder al almacenamiento"
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "Seleccionar formato de archivo"
msgid "Select a timezone"
msgstr "Selecciona una zona horaria"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2707,16 +3012,22 @@ msgstr "Selecciona una rama de destino"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
msgid "September"
-msgstr ""
+msgstr "Septiembre"
msgid "Server version"
msgstr ""
msgid "Service Templates"
+msgstr "Plantillas de Servicio"
+
+msgid "Service URL"
msgstr ""
msgid "Set a password on your account to pull or push via %{protocol}."
@@ -2728,13 +3039,13 @@ msgstr ""
msgid "Set up Koding"
msgstr "Configurar Koding"
-msgid "Set up auto deploy"
-msgstr "Configurar auto despliegue"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "establecer una contraseña"
msgid "Settings"
+msgstr "Configuración"
+
+msgid "Setup a specific Runner automatically"
msgstr ""
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
@@ -2746,9 +3057,12 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
-msgid "Show parent pages"
+msgid "Show command"
msgstr ""
+msgid "Show parent pages"
+msgstr "Mostrar páginas padre"
+
msgid "Show parent subgroups"
msgstr ""
@@ -2787,17 +3101,29 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
msgid "Sort by"
-msgstr ""
+msgstr "Ordenar por"
msgid "SortOptions|Access level, ascending"
msgstr ""
@@ -2896,6 +3222,9 @@ msgid "SortOptions|Weight"
msgstr ""
msgid "Source"
+msgstr "Fuente"
+
+msgid "Source (branch or tag)"
msgstr ""
msgid "Source code"
@@ -2914,7 +3243,7 @@ msgid "StarProject|Star"
msgstr "Destacar"
msgid "Starred projects"
-msgstr ""
+msgstr "Proyectos favoritos"
msgid "Start a %{new_merge_request} with these changes"
msgstr "Iniciar una %{new_merge_request} con estos cambios"
@@ -2923,24 +3252,24 @@ msgid "Start the Runner!"
msgstr ""
msgid "Stopped"
-msgstr ""
+msgstr "Detenido"
msgid "Storage"
msgstr ""
msgid "Subgroups"
-msgstr ""
+msgstr "Sub-grupos"
msgid "Switch branch/tag"
msgstr "Cambiar rama/etiqueta"
msgid "System Hooks"
-msgstr ""
+msgstr "Hooks de sistema"
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "Etiqueta"
-msgstr[1] "Etiquetas"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Tags"
msgstr "Etiquetas"
@@ -3018,10 +3347,10 @@ msgid "Target Branch"
msgstr "Rama de destino"
msgid "Team"
-msgstr ""
+msgstr "Equipo"
msgid "Thanks! Don't show me this again"
-msgstr ""
+msgstr "Gracias! No mostrar esto nuevamente"
msgid "The Advanced Global 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 ""
@@ -3071,9 +3400,15 @@ msgstr "El proyecto puede accederse sin ninguna autenticación."
msgid "The repository for this project does not exist."
msgstr "El repositorio para este proyecto no existe."
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "La etapa de revisión muestra el tiempo desde la creación de la solicitud de fusión hasta que los cambios se fusionaron. Los datos se añadirán automáticamente después de fusionar su primera solicitud de fusión."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "La etapa de puesta en escena muestra el tiempo entre la fusión y el despliegue de código en el entorno de producción. Los datos se añadirán automáticamente una vez que se despliega a producción por primera vez."
@@ -3167,6 +3502,9 @@ msgstr "Esto significa que no puede enviar código hasta que cree un repositorio
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3336,7 +3674,13 @@ msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
+msgstr "Título"
+
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
msgstr ""
msgid "Todo"
@@ -3354,19 +3698,16 @@ msgstr ""
msgid "Total Time"
msgstr "Tiempo Total"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "Tiempo total de pruebas para todos los cambios o integraciones"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3378,9 +3719,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3388,12 +3726,15 @@ msgid "Unknown"
msgstr ""
msgid "Unlock"
-msgstr ""
+msgstr "Desbloquear"
msgid "Unlock this %{issuableDisplayName}? <strong>Everyone</strong> will be able to comment."
msgstr ""
msgid "Unlocked"
+msgstr "Desbloqueado"
+
+msgid "Unresolve discussion"
msgstr ""
msgid "Unstar"
@@ -3441,9 +3782,12 @@ msgstr "Utiliza tu configuración de notificación global"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
-msgid "View file @ "
+msgid "View epics list"
msgstr ""
+msgid "View file @ "
+msgstr "Ver archivo @ "
+
msgid "View labels"
msgstr ""
@@ -3451,7 +3795,7 @@ msgid "View open merge request"
msgstr "Ver solicitud de fusión abierta"
msgid "View replaced file @ "
-msgstr ""
+msgstr "Ver archivo reemplazado @ "
msgid "VisibilityLevel|Internal"
msgstr "Interno"
@@ -3477,14 +3821,17 @@ msgstr "No hay suficientes datos para mostrar en esta etapa."
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
msgid "Weight"
-msgstr ""
+msgstr "Peso"
msgid "Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "WikiClone|Clone your wiki"
msgstr ""
@@ -3597,6 +3944,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "Retirar Solicitud de Acceso"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Va a eliminar %{group_name}. ¡El grupo eliminado NO puede ser restaurado! ¿Estás TOTALMENTE seguro?"
@@ -3609,10 +3959,13 @@ msgstr "Vas a eliminar el enlace de la bifurcación con el proyecto original %{f
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Vas a transferir %{project_name_with_namespace} a otro propietario. ¿Estás TOTALMENTE seguro?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3630,12 +3983,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "Has alcanzado el límite de tu proyecto"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "Debes iniciar sesión para destacar un proyecto"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "Necesitas permisos."
@@ -3667,28 +4032,31 @@ msgid "You'll need to use different branch names to get a valid comparison."
msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
+msgstr "La información del cluster de Kubernetes en esta página aún se puede editar, pero se recomienda desactivarla y modificar"
+
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
msgstr ""
msgid "Your comment will not be visible to the public."
-msgstr ""
+msgstr "Tus comentarios no serán visibles al público."
msgid "Your groups"
-msgstr ""
+msgstr "Tus grupos"
msgid "Your name"
msgstr "Tu nombre"
msgid "Your projects"
-msgstr ""
+msgstr "Tus proyectos"
msgid "assign yourself"
msgstr ""
msgid "branch name"
-msgstr ""
+msgstr "nombre de la rama"
msgid "by"
-msgstr ""
+msgstr "por"
msgid "ciReport|Code quality"
msgstr ""
@@ -3696,7 +4064,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3708,7 +4076,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3723,6 +4091,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3735,9 +4112,15 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
-msgid "commit"
+msgid "ciReport|no security vulnerabilities"
msgstr ""
+msgid "command line instructions"
+msgstr ""
+
+msgid "commit"
+msgstr "commit"
+
msgid "confidentiality|You are going to turn off the confidentiality. This means <strong>everyone</strong> will be able to see and leave a comment on this issue."
msgstr ""
@@ -3752,11 +4135,41 @@ msgstr[1] "días"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3790,6 +4203,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3823,6 +4239,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3877,6 +4296,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3901,10 +4323,10 @@ msgstr[0] "padre"
msgstr[1] "padres"
msgid "password"
-msgstr ""
+msgstr "contraseña"
msgid "personal access token"
-msgstr ""
+msgstr "token de acceso personal"
msgid "remove due date"
msgstr ""
@@ -3916,11 +4338,14 @@ msgid "spendCommand|%{slash_command} will update the sum of the time spent."
msgstr ""
msgid "to help your contributors communicate effectively!"
-msgstr ""
+msgstr "para ayudar a sus colaboradores a comunicarse de manera efectiva!"
msgid "username"
-msgstr ""
+msgstr "usuario"
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po
new file mode 100644
index 00000000000..1037ec675e9
--- /dev/null
+++ b/locale/fil_PH/gitlab.po
@@ -0,0 +1,4351 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: gitlab-ee\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:19-0500\n"
+"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
+"Language-Team: Filipino\n"
+"Language: fil_PH\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: crowdin.com\n"
+"X-Crowdin-Project: gitlab-ee\n"
+"X-Crowdin-Language: fil\n"
+"X-Crowdin-File: /master/locale/gitlab.pot\n"
+
+msgid " and"
+msgstr ""
+
+msgid "%d commit"
+msgid_plural "%d commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d commit behind"
+msgid_plural "%d commits behind"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d issue"
+msgid_plural "%d issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d layer"
+msgid_plural "%d layers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d merge request"
+msgid_plural "%d merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%s additional commit has been omitted to prevent performance issues."
+msgid_plural "%s additional commits have been omitted to prevent performance issues."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
+msgid "%{commit_author_link} authored %{commit_timeago}"
+msgstr ""
+
+msgid "%{count} participant"
+msgid_plural "%{count} participants"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
+msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
+msgstr ""
+
+msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
+msgstr ""
+
+msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
+msgstr ""
+
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
+msgid "%{storage_name}: failed storage access attempt on host:"
+msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{text} is available"
+msgstr ""
+
+msgid "(checkout the %{link} for information on how to install it)."
+msgstr ""
+
+msgid "+ %{moreCount} more"
+msgstr ""
+
+msgid "- show less"
+msgstr ""
+
+msgid "1 pipeline"
+msgid_plural "%d pipelines"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1st contribution!"
+msgstr ""
+
+msgid "2FA enabled"
+msgstr ""
+
+msgid "A collection of graphs regarding Continuous Integration"
+msgstr ""
+
+msgid "About auto deploy"
+msgstr ""
+
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
+msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
+msgstr ""
+
+msgid "Account"
+msgstr ""
+
+msgid "Active"
+msgstr ""
+
+msgid "Activity"
+msgstr ""
+
+msgid "Add"
+msgstr ""
+
+msgid "Add Changelog"
+msgstr ""
+
+msgid "Add Contribution guide"
+msgstr ""
+
+msgid "Add Group Webhooks and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Add Kubernetes cluster"
+msgstr ""
+
+msgid "Add License"
+msgstr ""
+
+msgid "Add Readme"
+msgstr ""
+
+msgid "Add new directory"
+msgstr ""
+
+msgid "Add todo"
+msgstr ""
+
+msgid "AdminArea|Stop all jobs"
+msgstr ""
+
+msgid "AdminArea|Stop all jobs?"
+msgstr ""
+
+msgid "AdminArea|Stop jobs"
+msgstr ""
+
+msgid "AdminArea|Stopping jobs failed"
+msgstr ""
+
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
+msgstr ""
+
+msgid "AdminHealthPageLink|health page"
+msgstr ""
+
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
+msgid "Advanced"
+msgstr ""
+
+msgid "Advanced settings"
+msgstr ""
+
+msgid "All"
+msgstr ""
+
+msgid "All changes are committed"
+msgstr ""
+
+msgid "Allows you to add and manage Kubernetes clusters."
+msgstr ""
+
+msgid "An error occurred previewing the blob"
+msgstr ""
+
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
+msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
+msgstr ""
+
+msgid "An error occurred while fetching markdown preview"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
+msgid "An error occurred while getting projects"
+msgstr ""
+
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
+msgid "An error occurred while loading filenames"
+msgstr ""
+
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
+msgid "An error occurred while rendering KaTeX"
+msgstr ""
+
+msgid "An error occurred while rendering preview broadcast message"
+msgstr ""
+
+msgid "An error occurred while retrieving calendar activity"
+msgstr ""
+
+msgid "An error occurred while retrieving diff"
+msgstr ""
+
+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 validating username"
+msgstr ""
+
+msgid "An error occurred. Please try again."
+msgstr ""
+
+msgid "Appearance"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
+msgid "Archived project! Repository is read-only"
+msgstr ""
+
+msgid "Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
+msgid "Are you sure you want to reset registration token?"
+msgstr ""
+
+msgid "Are you sure you want to reset the health check token?"
+msgstr ""
+
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
+msgid "Are you sure?"
+msgstr ""
+
+msgid "Artifacts"
+msgstr ""
+
+msgid "Assign custom color like #FF0000"
+msgstr ""
+
+msgid "Assign labels"
+msgstr ""
+
+msgid "Assign milestone"
+msgstr ""
+
+msgid "Assign to"
+msgstr ""
+
+msgid "Assignee"
+msgstr ""
+
+msgid "Attach a file by drag &amp; drop or %{upload_link}"
+msgstr ""
+
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Author"
+msgstr ""
+
+msgid "Authors: %{authors}"
+msgstr ""
+
+msgid "Auto DevOps enabled"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and a %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Auto DevOps (Beta)"
+msgstr ""
+
+msgid "AutoDevOps|Auto DevOps documentation"
+msgstr ""
+
+msgid "AutoDevOps|Enable in settings"
+msgstr ""
+
+msgid "AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
+msgstr ""
+
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Available"
+msgstr ""
+
+msgid "Avatar will be removed. Are you sure?"
+msgstr ""
+
+msgid "Average per day: %{average}"
+msgstr ""
+
+msgid "Begin with the selected commit"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Downgrade"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Branch <strong>%{branch_name}</strong> 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 is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
+msgid "BranchSwitcherPlaceholder|Search branches"
+msgstr ""
+
+msgid "BranchSwitcherTitle|Switch branch"
+msgstr ""
+
+msgid "Branches"
+msgstr ""
+
+msgid "Branches|Cant find HEAD commit for this branch"
+msgstr ""
+
+msgid "Branches|Compare"
+msgstr ""
+
+msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
+msgstr ""
+
+msgid "Branches|Delete branch"
+msgstr ""
+
+msgid "Branches|Delete merged branches"
+msgstr ""
+
+msgid "Branches|Delete protected branch"
+msgstr ""
+
+msgid "Branches|Delete protected branch '%{branch_name}'?"
+msgstr ""
+
+msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "Branches|Filter by branch name"
+msgstr ""
+
+msgid "Branches|Merged into %{default_branch}"
+msgstr ""
+
+msgid "Branches|New branch"
+msgstr ""
+
+msgid "Branches|No branches to show"
+msgstr ""
+
+msgid "Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered."
+msgstr ""
+
+msgid "Branches|Only a project master or owner can delete a protected branch"
+msgstr ""
+
+msgid "Branches|Protected branches can be managed in %{project_settings_link}"
+msgstr ""
+
+msgid "Branches|Sort by"
+msgstr ""
+
+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 ""
+
+msgid "Branches|This branch hasn’t been merged into %{default_branch}."
+msgstr ""
+
+msgid "Branches|To avoid data loss, consider merging this branch before deleting it."
+msgstr ""
+
+msgid "Branches|To confirm, type %{branch_name_confirmation}:"
+msgstr ""
+
+msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
+msgstr ""
+
+msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
+msgstr ""
+
+msgid "Branches|diverged from upstream"
+msgstr ""
+
+msgid "Branches|merged"
+msgstr ""
+
+msgid "Branches|project settings"
+msgstr ""
+
+msgid "Branches|protected"
+msgstr ""
+
+msgid "Browse Directory"
+msgstr ""
+
+msgid "Browse File"
+msgstr ""
+
+msgid "Browse Files"
+msgstr ""
+
+msgid "Browse files"
+msgstr ""
+
+msgid "ByAuthor|by"
+msgstr ""
+
+msgid "CI / CD"
+msgstr ""
+
+msgid "CI/CD configuration"
+msgstr ""
+
+msgid "CICD|Jobs"
+msgstr ""
+
+msgid "Cancel"
+msgstr ""
+
+msgid "Cancel edit"
+msgstr ""
+
+msgid "Cannot modify managed Kubernetes cluster"
+msgstr ""
+
+msgid "Change Weight"
+msgstr ""
+
+msgid "ChangeTypeActionLabel|Pick into branch"
+msgstr ""
+
+msgid "ChangeTypeActionLabel|Revert in branch"
+msgstr ""
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr ""
+
+msgid "ChangeTypeAction|Revert"
+msgstr ""
+
+msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
+msgstr ""
+
+msgid "Changelog"
+msgstr ""
+
+msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision."
+msgstr ""
+
+msgid "Charts"
+msgstr ""
+
+msgid "Chat"
+msgstr ""
+
+msgid "Check interval"
+msgstr ""
+
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
+msgid "Cherry-pick this commit"
+msgstr ""
+
+msgid "Cherry-pick this merge request"
+msgstr ""
+
+msgid "Choose File ..."
+msgstr ""
+
+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 ""
+
+msgid "Choose file..."
+msgstr ""
+
+msgid "Choose which groups you wish to synchronize to this secondary node."
+msgstr ""
+
+msgid "Choose which shards you wish to synchronize to this secondary node."
+msgstr ""
+
+msgid "CiStatusLabel|canceled"
+msgstr ""
+
+msgid "CiStatusLabel|created"
+msgstr ""
+
+msgid "CiStatusLabel|failed"
+msgstr ""
+
+msgid "CiStatusLabel|manual action"
+msgstr ""
+
+msgid "CiStatusLabel|passed"
+msgstr ""
+
+msgid "CiStatusLabel|passed with warnings"
+msgstr ""
+
+msgid "CiStatusLabel|pending"
+msgstr ""
+
+msgid "CiStatusLabel|skipped"
+msgstr ""
+
+msgid "CiStatusLabel|waiting for manual action"
+msgstr ""
+
+msgid "CiStatusText|blocked"
+msgstr ""
+
+msgid "CiStatusText|canceled"
+msgstr ""
+
+msgid "CiStatusText|created"
+msgstr ""
+
+msgid "CiStatusText|failed"
+msgstr ""
+
+msgid "CiStatusText|manual"
+msgstr ""
+
+msgid "CiStatusText|passed"
+msgstr ""
+
+msgid "CiStatusText|pending"
+msgstr ""
+
+msgid "CiStatusText|skipped"
+msgstr ""
+
+msgid "CiStatus|running"
+msgstr ""
+
+msgid "CiVariables|Input variable key"
+msgstr ""
+
+msgid "CiVariables|Input variable value"
+msgstr ""
+
+msgid "CiVariables|Remove variable row"
+msgstr ""
+
+msgid "CiVariable|* (All environments)"
+msgstr ""
+
+msgid "CiVariable|All environments"
+msgstr ""
+
+msgid "CiVariable|Create wildcard"
+msgstr ""
+
+msgid "CiVariable|Error occured while saving variables"
+msgstr ""
+
+msgid "CiVariable|New environment"
+msgstr ""
+
+msgid "CiVariable|Protected"
+msgstr ""
+
+msgid "CiVariable|Search environments"
+msgstr ""
+
+msgid "CiVariable|Toggle protected"
+msgstr ""
+
+msgid "CiVariable|Validation failed"
+msgstr ""
+
+msgid "CircuitBreakerApiLink|circuitbreaker api"
+msgstr ""
+
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
+msgid "Click to expand text"
+msgstr ""
+
+msgid "Clone repository"
+msgstr ""
+
+msgid "Close"
+msgstr ""
+
+msgid "Closed"
+msgstr ""
+
+msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Add Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|Are you sure you want to remove this Kubernetes cluster's integration? This will not delete your actual Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Choose which of your project's environments will use this Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Control how your Kubernetes cluster integrates with GitLab"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Kubernetes cluster name"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
+msgstr ""
+
+msgid "ClusterIntegration|Create Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Create Kubernetes cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create a new Kubernetes cluster on Google Kubernetes Engine right from GitLab"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment scope"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Integration"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
+msgid "ClusterIntegration|Google Cloud Platform project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Google Kubernetes Engine project"
+msgstr ""
+
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgstr ""
+
+msgid "ClusterIntegration|Integration status"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster details"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is disabled for this project."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project. Disabling this integration will not affect your Kubernetes cluster, it will only temporarily turn off GitLab's connection to it."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster is being created on Google Kubernetes Engine..."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster name"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine. Refresh the page to see Kubernetes cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about environments"
+msgstr ""
+
+msgid "ClusterIntegration|Machine type"
+msgstr ""
+
+msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
+msgstr ""
+
+msgid "ClusterIntegration|Manage"
+msgstr ""
+
+msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
+msgstr ""
+
+msgid "ClusterIntegration|More information"
+msgstr ""
+
+msgid "ClusterIntegration|Multiple Kubernetes clusters are available in GitLab Enterprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
+msgid "ClusterIntegration|Number of nodes"
+msgstr ""
+
+msgid "ClusterIntegration|Please enter access information for your Kubernetes cluster. If you need help, you can read our %{link_to_help_page} on Kubernetes"
+msgstr ""
+
+msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace (optional, unique)"
+msgstr ""
+
+msgid "ClusterIntegration|Prometheus"
+msgstr ""
+
+msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration."
+msgstr ""
+
+msgid "ClusterIntegration|Remove Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Remove integration"
+msgstr ""
+
+msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
+msgstr ""
+
+msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|See machine types"
+msgstr ""
+
+msgid "ClusterIntegration|See your projects"
+msgstr ""
+
+msgid "ClusterIntegration|See zones"
+msgstr ""
+
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong on our end."
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
+msgid "ClusterIntegration|Toggle Kubernetes Cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Toggle Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Token"
+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 ""
+
+msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
+msgstr ""
+
+msgid "ClusterIntegration|Zone"
+msgstr ""
+
+msgid "ClusterIntegration|access to Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|check the pricing here"
+msgstr ""
+
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
+msgid "ClusterIntegration|help page"
+msgstr ""
+
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
+msgid "ClusterIntegration|meets the requirements"
+msgstr ""
+
+msgid "ClusterIntegration|properly configured"
+msgstr ""
+
+msgid "Collapse"
+msgstr ""
+
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
+msgid "Comments"
+msgstr ""
+
+msgid "Commit"
+msgid_plural "Commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Commit Message"
+msgstr ""
+
+msgid "Commit duration in minutes for last 30 commits"
+msgstr ""
+
+msgid "Commit message"
+msgstr ""
+
+msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
+msgstr ""
+
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
+msgid "CommitBoxTitle|Commit"
+msgstr ""
+
+msgid "CommitMessage|Add %{file_name}"
+msgstr ""
+
+msgid "Commits"
+msgstr ""
+
+msgid "Commits feed"
+msgstr ""
+
+msgid "Commits per day hour (UTC)"
+msgstr ""
+
+msgid "Commits per day of month"
+msgstr ""
+
+msgid "Commits per weekday"
+msgstr ""
+
+msgid "Commits|An error occurred while fetching merge requests data."
+msgstr ""
+
+msgid "Commits|Commit: %{commitText}"
+msgstr ""
+
+msgid "Commits|History"
+msgstr ""
+
+msgid "Commits|No related merge requests found"
+msgstr ""
+
+msgid "Committed by"
+msgstr ""
+
+msgid "Compare"
+msgstr ""
+
+msgid "Compare Git revisions"
+msgstr ""
+
+msgid "Compare Revisions"
+msgstr ""
+
+msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
+msgstr ""
+
+msgid "CompareBranches|Compare"
+msgstr ""
+
+msgid "CompareBranches|Source"
+msgstr ""
+
+msgid "CompareBranches|Target"
+msgstr ""
+
+msgid "CompareBranches|There isn't anything to compare."
+msgstr ""
+
+msgid "Confidentiality"
+msgstr ""
+
+msgid "Container Registry"
+msgstr ""
+
+msgid "ContainerRegistry|Created"
+msgstr ""
+
+msgid "ContainerRegistry|First log in to GitLab&rsquo;s Container Registry using your GitLab username and password. If you have %{link_2fa} you need to use a %{link_token}:"
+msgstr ""
+
+msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
+msgstr ""
+
+msgid "ContainerRegistry|How to use the Container Registry"
+msgstr ""
+
+msgid "ContainerRegistry|Learn more about"
+msgstr ""
+
+msgid "ContainerRegistry|No tags in Container Registry for this container image."
+msgstr ""
+
+msgid "ContainerRegistry|Once you log in, you&rsquo;re free to create and upload a container image using the common %{build} and %{push} commands"
+msgstr ""
+
+msgid "ContainerRegistry|Remove repository"
+msgstr ""
+
+msgid "ContainerRegistry|Remove tag"
+msgstr ""
+
+msgid "ContainerRegistry|Size"
+msgstr ""
+
+msgid "ContainerRegistry|Tag"
+msgstr ""
+
+msgid "ContainerRegistry|Tag ID"
+msgstr ""
+
+msgid "ContainerRegistry|Use different image names"
+msgstr ""
+
+msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
+msgstr ""
+
+msgid "Contribution guide"
+msgstr ""
+
+msgid "Contributors"
+msgstr ""
+
+msgid "ContributorsPage|%{startDate} – %{endDate}"
+msgstr ""
+
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
+msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
+msgstr ""
+
+msgid "Control the maximum concurrency of repository backfill for this secondary node"
+msgstr ""
+
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
+msgid "Copy URL to clipboard"
+msgstr ""
+
+msgid "Copy branch name to clipboard"
+msgstr ""
+
+msgid "Copy command to clipboard"
+msgstr ""
+
+msgid "Copy commit SHA to clipboard"
+msgstr ""
+
+msgid "Copy reference to clipboard"
+msgstr ""
+
+msgid "Create"
+msgstr ""
+
+msgid "Create New Directory"
+msgstr ""
+
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
+msgid "Create a personal access token on your account to pull or push via %{protocol}."
+msgstr ""
+
+msgid "Create branch"
+msgstr ""
+
+msgid "Create directory"
+msgstr ""
+
+msgid "Create empty bare repository"
+msgstr ""
+
+msgid "Create epic"
+msgstr ""
+
+msgid "Create file"
+msgstr ""
+
+msgid "Create lists from labels. Issues with that label appear in that list."
+msgstr ""
+
+msgid "Create merge request"
+msgstr ""
+
+msgid "Create merge request and branch"
+msgstr ""
+
+msgid "Create new branch"
+msgstr ""
+
+msgid "Create new directory"
+msgstr ""
+
+msgid "Create new file"
+msgstr ""
+
+msgid "Create new label"
+msgstr ""
+
+msgid "Create new..."
+msgstr ""
+
+msgid "CreateNewFork|Fork"
+msgstr ""
+
+msgid "CreateTag|Tag"
+msgstr ""
+
+msgid "CreateTokenToCloneLink|create a personal access token"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
+msgid "Creating epic"
+msgstr ""
+
+msgid "Cron Timezone"
+msgstr ""
+
+msgid "Cron syntax"
+msgstr ""
+
+msgid "Current node"
+msgstr ""
+
+msgid "Custom notification events"
+msgstr ""
+
+msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}."
+msgstr ""
+
+msgid "Cycle Analytics"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Code"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Issue"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Plan"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Production"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Review"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Staging"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Test"
+msgstr ""
+
+msgid "DashboardProjects|All"
+msgstr ""
+
+msgid "DashboardProjects|Personal"
+msgstr ""
+
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
+msgid "Default classification label"
+msgstr ""
+
+msgid "Define a custom pattern with cron syntax"
+msgstr ""
+
+msgid "Delete"
+msgstr ""
+
+msgid "Deploy"
+msgid_plural "Deploys"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Deploy Keys"
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
+msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
+msgstr ""
+
+msgid "Details"
+msgstr ""
+
+msgid "Diffs|No file name available"
+msgstr ""
+
+msgid "Directory name"
+msgstr ""
+
+msgid "Disable"
+msgstr ""
+
+msgid "Discard draft"
+msgstr ""
+
+msgid "Discover GitLab Geo."
+msgstr ""
+
+msgid "Dismiss Cycle Analytics introduction box"
+msgstr ""
+
+msgid "Dismiss Merge Request promotion"
+msgstr ""
+
+msgid "Don't show again"
+msgstr ""
+
+msgid "Download"
+msgstr ""
+
+msgid "Download tar"
+msgstr ""
+
+msgid "Download tar.bz2"
+msgstr ""
+
+msgid "Download tar.gz"
+msgstr ""
+
+msgid "Download zip"
+msgstr ""
+
+msgid "DownloadArtifacts|Download"
+msgstr ""
+
+msgid "DownloadCommit|Email Patches"
+msgstr ""
+
+msgid "DownloadCommit|Plain Diff"
+msgstr ""
+
+msgid "DownloadSource|Download"
+msgstr ""
+
+msgid "Due date"
+msgstr ""
+
+msgid "Edit"
+msgstr ""
+
+msgid "Edit Pipeline Schedule %{id}"
+msgstr ""
+
+msgid "Edit files in the editor and commit changes here"
+msgstr ""
+
+msgid "Emails"
+msgstr ""
+
+msgid "Enable"
+msgstr ""
+
+msgid "Enable Auto DevOps"
+msgstr ""
+
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics Roadmap"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error fetching contributors data."
+msgstr ""
+
+msgid "Error fetching labels."
+msgstr ""
+
+msgid "Error fetching network graph."
+msgstr ""
+
+msgid "Error fetching refs"
+msgstr ""
+
+msgid "Error fetching usage ping data."
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "Error saving label update."
+msgstr ""
+
+msgid "Error updating status for all todos."
+msgstr ""
+
+msgid "Error updating todo status."
+msgstr ""
+
+msgid "EventFilterBy|Filter by all"
+msgstr ""
+
+msgid "EventFilterBy|Filter by comments"
+msgstr ""
+
+msgid "EventFilterBy|Filter by issue events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by merge events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by push events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by team"
+msgstr ""
+
+msgid "Every day (at 4:00am)"
+msgstr ""
+
+msgid "Every month (on the 1st at 4:00am)"
+msgstr ""
+
+msgid "Every week (Sundays at 4:00am)"
+msgstr ""
+
+msgid "Expand"
+msgstr ""
+
+msgid "Explore projects"
+msgstr ""
+
+msgid "Explore public groups"
+msgstr ""
+
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
+msgid "Failed to change the owner"
+msgstr ""
+
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
+msgid "Failed to remove the pipeline schedule"
+msgstr ""
+
+msgid "Failed to update issues, please try again."
+msgstr ""
+
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
+msgid "Fields on this page are now uneditable, you can configure"
+msgstr ""
+
+msgid "File name"
+msgstr ""
+
+msgid "Files"
+msgstr ""
+
+msgid "Files (%{human_size})"
+msgstr ""
+
+msgid "Filter by commit message"
+msgstr ""
+
+msgid "Find by path"
+msgstr ""
+
+msgid "Find file"
+msgstr ""
+
+msgid "FirstPushedBy|First"
+msgstr ""
+
+msgid "FirstPushedBy|pushed by"
+msgstr ""
+
+msgid "Fork"
+msgid_plural "Forks"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ForkedFromProjectPath|Forked from"
+msgstr ""
+
+msgid "ForkedFromProjectPath|Forked from %{project_name} (deleted)"
+msgstr ""
+
+msgid "Format"
+msgstr ""
+
+msgid "From issue creation until deploy to production"
+msgstr ""
+
+msgid "From merge request merge until deploy to production"
+msgstr ""
+
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Generate a default set of labels"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodes|Database replication lag:"
+msgstr ""
+
+msgid "GeoNodes|Disabling a node stops the sync process. Are you sure?"
+msgstr ""
+
+msgid "GeoNodes|Does not match the primary storage configuration"
+msgstr ""
+
+msgid "GeoNodes|Failed"
+msgstr ""
+
+msgid "GeoNodes|Full"
+msgstr ""
+
+msgid "GeoNodes|GitLab version does not match the primary node version"
+msgstr ""
+
+msgid "GeoNodes|GitLab version:"
+msgstr ""
+
+msgid "GeoNodes|Health status:"
+msgstr ""
+
+msgid "GeoNodes|Last event ID processed by cursor:"
+msgstr ""
+
+msgid "GeoNodes|Last event ID seen from primary:"
+msgstr ""
+
+msgid "GeoNodes|Loading nodes"
+msgstr ""
+
+msgid "GeoNodes|Local Attachments:"
+msgstr ""
+
+msgid "GeoNodes|Local LFS objects:"
+msgstr ""
+
+msgid "GeoNodes|Local job artifacts:"
+msgstr ""
+
+msgid "GeoNodes|New node"
+msgstr ""
+
+msgid "GeoNodes|Out of sync"
+msgstr ""
+
+msgid "GeoNodes|Replication slot WAL:"
+msgstr ""
+
+msgid "GeoNodes|Replication slots:"
+msgstr ""
+
+msgid "GeoNodes|Repositories:"
+msgstr ""
+
+msgid "GeoNodes|Selective"
+msgstr ""
+
+msgid "GeoNodes|Storage config:"
+msgstr ""
+
+msgid "GeoNodes|Sync settings:"
+msgstr ""
+
+msgid "GeoNodes|Synced"
+msgstr ""
+
+msgid "GeoNodes|Unused slots"
+msgstr ""
+
+msgid "GeoNodes|Used slots"
+msgstr ""
+
+msgid "GeoNodes|Wikis:"
+msgstr ""
+
+msgid "GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS."
+msgstr ""
+
+msgid "Geo|All projects"
+msgstr ""
+
+msgid "Geo|File sync capacity"
+msgstr ""
+
+msgid "Geo|Groups to synchronize"
+msgstr ""
+
+msgid "Geo|Projects in certain groups"
+msgstr ""
+
+msgid "Geo|Projects in certain storage shards"
+msgstr ""
+
+msgid "Geo|Repository sync capacity"
+msgstr ""
+
+msgid "Geo|Select groups to replicate."
+msgstr ""
+
+msgid "Geo|Shards to synchronize"
+msgstr ""
+
+msgid "Git revision"
+msgstr ""
+
+msgid "Git storage health information has been reset"
+msgstr ""
+
+msgid "Git version"
+msgstr ""
+
+msgid "GitLab Runner section"
+msgstr ""
+
+msgid "Gitaly Servers"
+msgstr ""
+
+msgid "Go to your fork"
+msgstr ""
+
+msgid "GoToYourFork|Fork"
+msgstr ""
+
+msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
+msgstr ""
+
+msgid "Got it!"
+msgstr ""
+
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
+msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
+msgstr ""
+
+msgid "GroupSettings|Share with group lock"
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
+msgstr ""
+
+msgid "GroupSettings|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 ""
+
+msgid "GroupSettings|cannot be disabled when the parent group \"Share with group lock\" is enabled, except by the owner of the parent group"
+msgstr ""
+
+msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name}"
+msgstr ""
+
+msgid "GroupsEmptyState|A group is a collection of several projects."
+msgstr ""
+
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+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 ""
+
+msgid "GroupsTree|Are you sure you want to leave the \"${group.fullName}\" group?"
+msgstr ""
+
+msgid "GroupsTree|Create a project in this group."
+msgstr ""
+
+msgid "GroupsTree|Create a subgroup in this group."
+msgstr ""
+
+msgid "GroupsTree|Edit group"
+msgstr ""
+
+msgid "GroupsTree|Failed to leave the group. Please make sure you are not the only owner."
+msgstr ""
+
+msgid "GroupsTree|Filter by name..."
+msgstr ""
+
+msgid "GroupsTree|Leave this group"
+msgstr ""
+
+msgid "GroupsTree|Loading groups"
+msgstr ""
+
+msgid "GroupsTree|Sorry, no groups matched your search"
+msgstr ""
+
+msgid "GroupsTree|Sorry, no groups or projects matched your search"
+msgstr ""
+
+msgid "Have your users email"
+msgstr ""
+
+msgid "Health Check"
+msgstr ""
+
+msgid "Health information can be retrieved from the following endpoints. More information is available"
+msgstr ""
+
+msgid "HealthCheck|Access token is"
+msgstr ""
+
+msgid "HealthCheck|Healthy"
+msgstr ""
+
+msgid "HealthCheck|No Health Problems Detected"
+msgstr ""
+
+msgid "HealthCheck|Unhealthy"
+msgstr ""
+
+msgid "Hide value"
+msgid_plural "Hide values"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "History"
+msgstr ""
+
+msgid "Housekeeping successfully started"
+msgstr ""
+
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
+msgid "Import repository"
+msgstr ""
+
+msgid "Improve Issue boards with GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
+msgid "Install a Runner compatible with GitLab CI"
+msgstr ""
+
+msgid "Instance"
+msgid_plural "Instances"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Instance does not support multiple Kubernetes clusters"
+msgstr ""
+
+msgid "Interested parties can even contribute by pushing commits if they want to."
+msgstr ""
+
+msgid "Internal - The group and any internal projects can be viewed by any logged in user."
+msgstr ""
+
+msgid "Internal - The project can be accessed by any logged in user."
+msgstr ""
+
+msgid "Interval Pattern"
+msgstr ""
+
+msgid "Introducing Cycle Analytics"
+msgstr ""
+
+msgid "Issue board focus mode"
+msgstr ""
+
+msgid "Issue events"
+msgstr ""
+
+msgid "IssueBoards|Board"
+msgstr ""
+
+msgid "IssueBoards|Boards"
+msgstr ""
+
+msgid "Issues"
+msgstr ""
+
+msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
+msgstr ""
+
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jobs"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
+msgid "Kubernetes"
+msgstr ""
+
+msgid "Kubernetes Cluster"
+msgstr ""
+
+msgid "Kubernetes cluster creation time exceeds timeout; %{timeout}"
+msgstr ""
+
+msgid "Kubernetes cluster integration was not removed."
+msgstr ""
+
+msgid "Kubernetes cluster integration was successfully removed."
+msgstr ""
+
+msgid "Kubernetes cluster was successfully updated."
+msgstr ""
+
+msgid "Kubernetes configured"
+msgstr ""
+
+msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
+msgstr ""
+
+msgid "LFSStatus|Disabled"
+msgstr ""
+
+msgid "LFSStatus|Enabled"
+msgstr ""
+
+msgid "Labels"
+msgstr ""
+
+msgid "Labels can be applied to issues and merge requests to categorize them."
+msgstr ""
+
+msgid "Last %d day"
+msgid_plural "Last %d days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Last Pipeline"
+msgstr ""
+
+msgid "Last commit"
+msgstr ""
+
+msgid "Last edited %{date}"
+msgstr ""
+
+msgid "Last edited by %{name}"
+msgstr ""
+
+msgid "Last update"
+msgstr ""
+
+msgid "Last updated"
+msgstr ""
+
+msgid "LastPushEvent|You pushed to"
+msgstr ""
+
+msgid "LastPushEvent|at"
+msgstr ""
+
+msgid "Learn more"
+msgstr ""
+
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
+msgid "Learn more in the"
+msgstr ""
+
+msgid "Learn more in the|pipeline schedules documentation"
+msgstr ""
+
+msgid "Leave"
+msgstr ""
+
+msgid "Leave group"
+msgstr ""
+
+msgid "Leave project"
+msgstr ""
+
+msgid "License"
+msgstr ""
+
+msgid "List"
+msgstr ""
+
+msgid "Loading the GitLab IDE..."
+msgstr ""
+
+msgid "Lock"
+msgstr ""
+
+msgid "Lock %{issuableDisplayName}"
+msgstr ""
+
+msgid "Lock not found"
+msgstr ""
+
+msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
+msgstr ""
+
+msgid "Locked"
+msgstr ""
+
+msgid "Locked Files"
+msgstr ""
+
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
+msgid "Login"
+msgstr ""
+
+msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
+msgstr ""
+
+msgid "Manage labels"
+msgstr ""
+
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
+msgid "Mark done"
+msgstr ""
+
+msgid "Maximum git storage failures"
+msgstr ""
+
+msgid "May"
+msgstr ""
+
+msgid "Median"
+msgstr ""
+
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
+msgid "Merge events"
+msgstr ""
+
+msgid "Merge request"
+msgstr ""
+
+msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
+msgstr ""
+
+msgid "MergeRequest|Approved"
+msgstr ""
+
+msgid "Merged"
+msgstr ""
+
+msgid "Messages"
+msgstr ""
+
+msgid "Milestone"
+msgstr ""
+
+msgid "Milestones|Delete milestone"
+msgstr ""
+
+msgid "Milestones|Delete milestone %{milestoneTitle}?"
+msgstr ""
+
+msgid "Milestones|Failed to delete milestone %{milestoneTitle}"
+msgstr ""
+
+msgid "Milestones|Milestone %{milestoneTitle} was not found"
+msgstr ""
+
+msgid "MissingSSHKeyWarningLink|add an SSH key"
+msgstr ""
+
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
+msgid "Monitoring"
+msgstr ""
+
+msgid "More information"
+msgstr ""
+
+msgid "More information is available|here"
+msgstr ""
+
+msgid "Move"
+msgstr ""
+
+msgid "Move issue"
+msgstr ""
+
+msgid "Multiple issue boards"
+msgstr ""
+
+msgid "Name new label"
+msgstr ""
+
+msgid "New Issue"
+msgid_plural "New Issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "New Kubernetes Cluster"
+msgstr ""
+
+msgid "New Kubernetes cluster"
+msgstr ""
+
+msgid "New Pipeline Schedule"
+msgstr ""
+
+msgid "New branch"
+msgstr ""
+
+msgid "New branch unavailable"
+msgstr ""
+
+msgid "New directory"
+msgstr ""
+
+msgid "New epic"
+msgstr ""
+
+msgid "New file"
+msgstr ""
+
+msgid "New group"
+msgstr ""
+
+msgid "New issue"
+msgstr ""
+
+msgid "New label"
+msgstr ""
+
+msgid "New merge request"
+msgstr ""
+
+msgid "New project"
+msgstr ""
+
+msgid "New schedule"
+msgstr ""
+
+msgid "New snippet"
+msgstr ""
+
+msgid "New subgroup"
+msgstr ""
+
+msgid "New tag"
+msgstr ""
+
+msgid "No assignee"
+msgstr ""
+
+msgid "No changes"
+msgstr ""
+
+msgid "No connection could be made to a Gitaly Server, please check your logs!"
+msgstr ""
+
+msgid "No due date"
+msgstr ""
+
+msgid "No estimate or time spent"
+msgstr ""
+
+msgid "No file chosen"
+msgstr ""
+
+msgid "No repository"
+msgstr ""
+
+msgid "No schedules"
+msgstr ""
+
+msgid "None"
+msgstr ""
+
+msgid "Not allowed to merge"
+msgstr ""
+
+msgid "Not available"
+msgstr ""
+
+msgid "Not confidential"
+msgstr ""
+
+msgid "Not enough data"
+msgstr ""
+
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
+msgid "Notification events"
+msgstr ""
+
+msgid "NotificationEvent|Close issue"
+msgstr ""
+
+msgid "NotificationEvent|Close merge request"
+msgstr ""
+
+msgid "NotificationEvent|Failed pipeline"
+msgstr ""
+
+msgid "NotificationEvent|Merge merge request"
+msgstr ""
+
+msgid "NotificationEvent|New issue"
+msgstr ""
+
+msgid "NotificationEvent|New merge request"
+msgstr ""
+
+msgid "NotificationEvent|New note"
+msgstr ""
+
+msgid "NotificationEvent|Reassign issue"
+msgstr ""
+
+msgid "NotificationEvent|Reassign merge request"
+msgstr ""
+
+msgid "NotificationEvent|Reopen issue"
+msgstr ""
+
+msgid "NotificationEvent|Successful pipeline"
+msgstr ""
+
+msgid "NotificationLevel|Custom"
+msgstr ""
+
+msgid "NotificationLevel|Disabled"
+msgstr ""
+
+msgid "NotificationLevel|Global"
+msgstr ""
+
+msgid "NotificationLevel|On mention"
+msgstr ""
+
+msgid "NotificationLevel|Participate"
+msgstr ""
+
+msgid "NotificationLevel|Watch"
+msgstr ""
+
+msgid "Notifications"
+msgstr ""
+
+msgid "Notifications off"
+msgstr ""
+
+msgid "Notifications on"
+msgstr ""
+
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
+msgid "Number of access attempts"
+msgstr ""
+
+msgid "OK"
+msgstr ""
+
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
+msgid "OfSearchInADropdown|Filter"
+msgstr ""
+
+msgid "Only project members can comment."
+msgstr ""
+
+msgid "Open"
+msgstr ""
+
+msgid "Opened"
+msgstr ""
+
+msgid "OpenedNDaysAgo|Opened"
+msgstr ""
+
+msgid "Opens in a new window"
+msgstr ""
+
+msgid "Options"
+msgstr ""
+
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
+msgid "Overview"
+msgstr ""
+
+msgid "Owner"
+msgstr ""
+
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
+msgid "Password"
+msgstr ""
+
+msgid "Pipeline"
+msgstr ""
+
+msgid "Pipeline Health"
+msgstr ""
+
+msgid "Pipeline Schedule"
+msgstr ""
+
+msgid "Pipeline Schedules"
+msgstr ""
+
+msgid "Pipeline quota"
+msgstr ""
+
+msgid "PipelineCharts|Failed:"
+msgstr ""
+
+msgid "PipelineCharts|Overall statistics"
+msgstr ""
+
+msgid "PipelineCharts|Success ratio:"
+msgstr ""
+
+msgid "PipelineCharts|Successful:"
+msgstr ""
+
+msgid "PipelineCharts|Total:"
+msgstr ""
+
+msgid "PipelineSchedules|Activated"
+msgstr ""
+
+msgid "PipelineSchedules|Active"
+msgstr ""
+
+msgid "PipelineSchedules|All"
+msgstr ""
+
+msgid "PipelineSchedules|Inactive"
+msgstr ""
+
+msgid "PipelineSchedules|Next Run"
+msgstr ""
+
+msgid "PipelineSchedules|None"
+msgstr ""
+
+msgid "PipelineSchedules|Provide a short description for this pipeline"
+msgstr ""
+
+msgid "PipelineSchedules|Take ownership"
+msgstr ""
+
+msgid "PipelineSchedules|Target"
+msgstr ""
+
+msgid "PipelineSchedules|Variables"
+msgstr ""
+
+msgid "PipelineSheduleIntervalPattern|Custom"
+msgstr ""
+
+msgid "Pipelines"
+msgstr ""
+
+msgid "Pipelines charts"
+msgstr ""
+
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
+msgid "Pipelines|Build with confidence"
+msgstr ""
+
+msgid "Pipelines|Get started with Pipelines"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|all"
+msgstr ""
+
+msgid "Pipeline|success"
+msgstr ""
+
+msgid "Pipeline|with stage"
+msgstr ""
+
+msgid "Pipeline|with stages"
+msgstr ""
+
+msgid "Play"
+msgstr ""
+
+msgid "Please <a href=%{link_to_billing} target=\"_blank\" rel=\"noopener noreferrer\">enable billing for one of your projects to be able to create a Kubernetes cluster</a>, then try again."
+msgstr ""
+
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
+msgid "Preferences"
+msgstr ""
+
+msgid "Primary"
+msgstr ""
+
+msgid "Private - Project access must be granted explicitly to each user."
+msgstr ""
+
+msgid "Private - The group and its projects can only be viewed by members."
+msgstr ""
+
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
+msgid "Profile"
+msgstr ""
+
+msgid "Profiles|Account scheduled for removal."
+msgstr ""
+
+msgid "Profiles|Delete Account"
+msgstr ""
+
+msgid "Profiles|Delete account"
+msgstr ""
+
+msgid "Profiles|Delete your account?"
+msgstr ""
+
+msgid "Profiles|Deleting an account has the following effects:"
+msgstr ""
+
+msgid "Profiles|Invalid password"
+msgstr ""
+
+msgid "Profiles|Invalid username"
+msgstr ""
+
+msgid "Profiles|Type your %{confirmationValue} to confirm:"
+msgstr ""
+
+msgid "Profiles|You don't have access to delete this user."
+msgstr ""
+
+msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
+msgstr ""
+
+msgid "Profiles|Your account is currently an owner in these groups:"
+msgstr ""
+
+msgid "Profiles|your account"
+msgstr ""
+
+msgid "Programming languages used in this repository"
+msgstr ""
+
+msgid "Project '%{project_name}' is in the process of being deleted."
+msgstr ""
+
+msgid "Project '%{project_name}' queued for deletion."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully created."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully updated."
+msgstr ""
+
+msgid "Project access must be granted explicitly to each user."
+msgstr ""
+
+msgid "Project avatar"
+msgstr ""
+
+msgid "Project avatar in repository: %{link}"
+msgstr ""
+
+msgid "Project cache successfully reset."
+msgstr ""
+
+msgid "Project details"
+msgstr ""
+
+msgid "Project export could not be deleted."
+msgstr ""
+
+msgid "Project export has been deleted."
+msgstr ""
+
+msgid "Project export link has expired. Please generate a new export from your project settings."
+msgstr ""
+
+msgid "Project export started. A download link will be sent by email."
+msgstr ""
+
+msgid "ProjectActivityRSS|Subscribe"
+msgstr ""
+
+msgid "ProjectCreationLevel|Allowed to create projects"
+msgstr ""
+
+msgid "ProjectCreationLevel|Default project creation protection"
+msgstr ""
+
+msgid "ProjectCreationLevel|Developers + Masters"
+msgstr ""
+
+msgid "ProjectCreationLevel|Masters"
+msgstr ""
+
+msgid "ProjectCreationLevel|No one"
+msgstr ""
+
+msgid "ProjectFeature|Disabled"
+msgstr ""
+
+msgid "ProjectFeature|Everyone with access"
+msgstr ""
+
+msgid "ProjectFeature|Only team members"
+msgstr ""
+
+msgid "ProjectFileTree|Name"
+msgstr ""
+
+msgid "ProjectLastActivity|Never"
+msgstr ""
+
+msgid "ProjectLifecycle|Stage"
+msgstr ""
+
+msgid "ProjectNetworkGraph|Graph"
+msgstr ""
+
+msgid "ProjectSettings|Contact an admin to change this setting."
+msgstr ""
+
+msgid "ProjectSettings|Only signed commits can be pushed to this repository."
+msgstr ""
+
+msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
+msgstr ""
+
+msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
+msgstr ""
+
+msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
+msgstr ""
+
+msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
+msgstr ""
+
+msgid "Projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Frequently visited"
+msgstr ""
+
+msgid "ProjectsDropdown|Loading projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Projects you visit often will appear here"
+msgstr ""
+
+msgid "ProjectsDropdown|Search your projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Something went wrong on our end."
+msgstr ""
+
+msgid "ProjectsDropdown|Sorry, no projects matched your search"
+msgstr ""
+
+msgid "ProjectsDropdown|This feature requires browser localStorage support"
+msgstr ""
+
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
+msgid "PrometheusService|Time-series monitoring service"
+msgstr ""
+
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
+msgid "Protip:"
+msgstr ""
+
+msgid "Public - The group and any public projects can be viewed without any authentication."
+msgstr ""
+
+msgid "Public - The project can be accessed without any authentication."
+msgstr ""
+
+msgid "Push Rules"
+msgstr ""
+
+msgid "Push events"
+msgstr ""
+
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
+msgid "PushRule|Committer restriction"
+msgstr ""
+
+msgid "Quick actions can be used in the issues description and comment boxes."
+msgstr ""
+
+msgid "Read more"
+msgstr ""
+
+msgid "Readme"
+msgstr ""
+
+msgid "RefSwitcher|Branches"
+msgstr ""
+
+msgid "RefSwitcher|Tags"
+msgstr ""
+
+msgid "Reference:"
+msgstr ""
+
+msgid "Register / Sign In"
+msgstr ""
+
+msgid "Registry"
+msgstr ""
+
+msgid "Related Commits"
+msgstr ""
+
+msgid "Related Deployed Jobs"
+msgstr ""
+
+msgid "Related Issues"
+msgstr ""
+
+msgid "Related Jobs"
+msgstr ""
+
+msgid "Related Merge Requests"
+msgstr ""
+
+msgid "Related Merged Requests"
+msgstr ""
+
+msgid "Remind later"
+msgstr ""
+
+msgid "Remove"
+msgstr ""
+
+msgid "Remove avatar"
+msgstr ""
+
+msgid "Remove project"
+msgstr ""
+
+msgid "Repair authentication"
+msgstr ""
+
+msgid "Repository"
+msgstr ""
+
+msgid "Repository has no locks."
+msgstr ""
+
+msgid "Request Access"
+msgstr ""
+
+msgid "Reset git storage health information"
+msgstr ""
+
+msgid "Reset health check access token"
+msgstr ""
+
+msgid "Reset runners registration token"
+msgstr ""
+
+msgid "Resolve discussion"
+msgstr ""
+
+msgid "Reveal value"
+msgid_plural "Reveal values"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Revert this commit"
+msgstr ""
+
+msgid "Revert this merge request"
+msgstr ""
+
+msgid "Roadmap"
+msgstr ""
+
+msgid "SSH Keys"
+msgstr ""
+
+msgid "Save changes"
+msgstr ""
+
+msgid "Save pipeline schedule"
+msgstr ""
+
+msgid "Save variables"
+msgstr ""
+
+msgid "Schedule a new pipeline"
+msgstr ""
+
+msgid "Schedules"
+msgstr ""
+
+msgid "Scheduling Pipelines"
+msgstr ""
+
+msgid "Scoped issue boards"
+msgstr ""
+
+msgid "Search branches and tags"
+msgstr ""
+
+msgid "Search milestones"
+msgstr ""
+
+msgid "Search project"
+msgstr ""
+
+msgid "Search users"
+msgstr ""
+
+msgid "Seconds before reseting failure information"
+msgstr ""
+
+msgid "Seconds to wait for a storage access attempt"
+msgstr ""
+
+msgid "Secret variables"
+msgstr ""
+
+msgid "Security report"
+msgstr ""
+
+msgid "Select Archive Format"
+msgstr ""
+
+msgid "Select a timezone"
+msgstr ""
+
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
+msgid "Select assignee"
+msgstr ""
+
+msgid "Select branch/tag"
+msgstr ""
+
+msgid "Select target branch"
+msgstr ""
+
+msgid "Selective synchronization"
+msgstr ""
+
+msgid "Send email"
+msgstr ""
+
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
+msgid "Server version"
+msgstr ""
+
+msgid "Service Templates"
+msgstr ""
+
+msgid "Service URL"
+msgstr ""
+
+msgid "Set a password on your account to pull or push via %{protocol}."
+msgstr ""
+
+msgid "Set up CI/CD"
+msgstr ""
+
+msgid "Set up Koding"
+msgstr ""
+
+msgid "SetPasswordToCloneLink|set a password"
+msgstr ""
+
+msgid "Settings"
+msgstr ""
+
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
+msgstr ""
+
+msgid "Show command"
+msgstr ""
+
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
+msgid "Showing %d event"
+msgid_plural "Showing %d events"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
+msgid "Snippets"
+msgstr ""
+
+msgid "Something went wrong on our end"
+msgstr ""
+
+msgid "Something went wrong on our end."
+msgstr ""
+
+msgid "Something went wrong trying to change the confidentiality of this issue"
+msgstr ""
+
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr ""
+
+msgid "Something went wrong when toggling the button"
+msgstr ""
+
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
+msgid "Something went wrong while fetching the projects."
+msgstr ""
+
+msgid "Something went wrong while fetching the registry list."
+msgstr ""
+
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
+msgid "Something went wrong. Please try again."
+msgstr ""
+
+msgid "Sort by"
+msgstr ""
+
+msgid "SortOptions|Access level, ascending"
+msgstr ""
+
+msgid "SortOptions|Access level, descending"
+msgstr ""
+
+msgid "SortOptions|Created date"
+msgstr ""
+
+msgid "SortOptions|Due date"
+msgstr ""
+
+msgid "SortOptions|Due later"
+msgstr ""
+
+msgid "SortOptions|Due soon"
+msgstr ""
+
+msgid "SortOptions|Label priority"
+msgstr ""
+
+msgid "SortOptions|Largest group"
+msgstr ""
+
+msgid "SortOptions|Largest repository"
+msgstr ""
+
+msgid "SortOptions|Last created"
+msgstr ""
+
+msgid "SortOptions|Last joined"
+msgstr ""
+
+msgid "SortOptions|Last updated"
+msgstr ""
+
+msgid "SortOptions|Least popular"
+msgstr ""
+
+msgid "SortOptions|Less weight"
+msgstr ""
+
+msgid "SortOptions|Milestone"
+msgstr ""
+
+msgid "SortOptions|Milestone due later"
+msgstr ""
+
+msgid "SortOptions|Milestone due soon"
+msgstr ""
+
+msgid "SortOptions|More weight"
+msgstr ""
+
+msgid "SortOptions|Most popular"
+msgstr ""
+
+msgid "SortOptions|Name"
+msgstr ""
+
+msgid "SortOptions|Name, ascending"
+msgstr ""
+
+msgid "SortOptions|Name, descending"
+msgstr ""
+
+msgid "SortOptions|Oldest created"
+msgstr ""
+
+msgid "SortOptions|Oldest joined"
+msgstr ""
+
+msgid "SortOptions|Oldest sign in"
+msgstr ""
+
+msgid "SortOptions|Oldest updated"
+msgstr ""
+
+msgid "SortOptions|Popularity"
+msgstr ""
+
+msgid "SortOptions|Priority"
+msgstr ""
+
+msgid "SortOptions|Recent sign in"
+msgstr ""
+
+msgid "SortOptions|Start later"
+msgstr ""
+
+msgid "SortOptions|Start soon"
+msgstr ""
+
+msgid "SortOptions|Weight"
+msgstr ""
+
+msgid "Source"
+msgstr ""
+
+msgid "Source (branch or tag)"
+msgstr ""
+
+msgid "Source code"
+msgstr ""
+
+msgid "Source is not available"
+msgstr ""
+
+msgid "Spam Logs"
+msgstr ""
+
+msgid "Specify the following URL during the Runner setup:"
+msgstr ""
+
+msgid "StarProject|Star"
+msgstr ""
+
+msgid "Starred projects"
+msgstr ""
+
+msgid "Start a %{new_merge_request} with these changes"
+msgstr ""
+
+msgid "Start the Runner!"
+msgstr ""
+
+msgid "Stopped"
+msgstr ""
+
+msgid "Storage"
+msgstr ""
+
+msgid "Subgroups"
+msgstr ""
+
+msgid "Switch branch/tag"
+msgstr ""
+
+msgid "System Hooks"
+msgstr ""
+
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Tags"
+msgstr ""
+
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+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 ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
+msgid "Target Branch"
+msgstr ""
+
+msgid "Team"
+msgstr ""
+
+msgid "Thanks! Don't show me this again"
+msgstr ""
+
+msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
+msgstr ""
+
+msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
+msgstr ""
+
+msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project."
+msgstr ""
+
+msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
+msgstr ""
+
+msgid "The collection of events added to the data gathered for that stage."
+msgstr ""
+
+msgid "The fork relationship has been removed."
+msgstr ""
+
+msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
+msgstr ""
+
+msgid "The maximum file size allowed is 200KB."
+msgstr ""
+
+msgid "The number of attempts GitLab will make to access a storage."
+msgstr ""
+
+msgid "The number of failures of after which GitLab will completely prevent access to the storage. The number of failures can be reset in the admin interface: %{link_to_health_page} or using the %{api_documentation_link}."
+msgstr ""
+
+msgid "The phase of the development lifecycle."
+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 ""
+
+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 ""
+
+msgid "The project can be accessed without any authentication."
+msgstr ""
+
+msgid "The repository for this project does not exist."
+msgstr ""
+
+msgid "The repository for this project is empty"
+msgstr ""
+
+msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
+msgstr ""
+
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
+msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
+msgstr ""
+
+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 ""
+
+msgid "The time in seconds GitLab will keep failure information. When no failures occur during this time, information about the mount is reset."
+msgstr ""
+
+msgid "The time in seconds GitLab will try to access storage. After this time a timeout error will be raised."
+msgstr ""
+
+msgid "The time in seconds between storage checks. When a previous check did complete yet, GitLab will skip a check."
+msgstr ""
+
+msgid "The time taken by each data entry gathered by that stage."
+msgstr ""
+
+msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
+msgstr ""
+
+msgid "There are no issues to show"
+msgstr ""
+
+msgid "There are no merge requests to show"
+msgstr ""
+
+msgid "There are problems accessing Git storage: "
+msgstr ""
+
+msgid "There was an error loading users activity calendar."
+msgstr ""
+
+msgid "There was an error saving your notification settings."
+msgstr ""
+
+msgid "There was an error subscribing to this label."
+msgstr ""
+
+msgid "There was an error when reseting email token."
+msgstr ""
+
+msgid "There was an error when subscribing to this label."
+msgstr ""
+
+msgid "There was an error when unsubscribing from this label."
+msgstr ""
+
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
+msgid "This directory"
+msgstr ""
+
+msgid "This is a confidential issue."
+msgstr ""
+
+msgid "This is the author's first Merge Request to this project."
+msgstr ""
+
+msgid "This issue is confidential"
+msgstr ""
+
+msgid "This issue is confidential and locked."
+msgstr ""
+
+msgid "This issue is locked."
+msgstr ""
+
+msgid "This job depends on a user to trigger its process. Often they are used to deploy code to production environments"
+msgstr ""
+
+msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
+msgstr ""
+
+msgid "This job has not been triggered yet"
+msgstr ""
+
+msgid "This job has not started yet"
+msgstr ""
+
+msgid "This job is in pending state and is waiting to be picked by a runner"
+msgstr ""
+
+msgid "This job requires a manual action"
+msgstr ""
+
+msgid "This means you can not push code until you create an empty repository or import existing one."
+msgstr ""
+
+msgid "This merge request is locked."
+msgstr ""
+
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
+msgid "This project"
+msgstr ""
+
+msgid "This repository"
+msgstr ""
+
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
+msgid "Time before an issue gets scheduled"
+msgstr ""
+
+msgid "Time before an issue starts implementation"
+msgstr ""
+
+msgid "Time between merge request creation and merge/close"
+msgstr ""
+
+msgid "Time tracking"
+msgstr ""
+
+msgid "Time until first merge request"
+msgstr ""
+
+msgid "TimeTrackingEstimated|Est"
+msgstr ""
+
+msgid "TimeTracking|Estimated:"
+msgstr ""
+
+msgid "TimeTracking|Spent"
+msgstr ""
+
+msgid "Timeago|%s days ago"
+msgstr ""
+
+msgid "Timeago|%s days remaining"
+msgstr ""
+
+msgid "Timeago|%s hours remaining"
+msgstr ""
+
+msgid "Timeago|%s minutes ago"
+msgstr ""
+
+msgid "Timeago|%s minutes remaining"
+msgstr ""
+
+msgid "Timeago|%s months ago"
+msgstr ""
+
+msgid "Timeago|%s months remaining"
+msgstr ""
+
+msgid "Timeago|%s seconds remaining"
+msgstr ""
+
+msgid "Timeago|%s weeks ago"
+msgstr ""
+
+msgid "Timeago|%s weeks remaining"
+msgstr ""
+
+msgid "Timeago|%s years ago"
+msgstr ""
+
+msgid "Timeago|%s years remaining"
+msgstr ""
+
+msgid "Timeago|1 day remaining"
+msgstr ""
+
+msgid "Timeago|1 hour remaining"
+msgstr ""
+
+msgid "Timeago|1 minute remaining"
+msgstr ""
+
+msgid "Timeago|1 month remaining"
+msgstr ""
+
+msgid "Timeago|1 week remaining"
+msgstr ""
+
+msgid "Timeago|1 year remaining"
+msgstr ""
+
+msgid "Timeago|Past due"
+msgstr ""
+
+msgid "Timeago|a day ago"
+msgstr ""
+
+msgid "Timeago|a month ago"
+msgstr ""
+
+msgid "Timeago|a week ago"
+msgstr ""
+
+msgid "Timeago|a year ago"
+msgstr ""
+
+msgid "Timeago|about %s hours ago"
+msgstr ""
+
+msgid "Timeago|about a minute ago"
+msgstr ""
+
+msgid "Timeago|about an hour ago"
+msgstr ""
+
+msgid "Timeago|in %s days"
+msgstr ""
+
+msgid "Timeago|in %s hours"
+msgstr ""
+
+msgid "Timeago|in %s minutes"
+msgstr ""
+
+msgid "Timeago|in %s months"
+msgstr ""
+
+msgid "Timeago|in %s seconds"
+msgstr ""
+
+msgid "Timeago|in %s weeks"
+msgstr ""
+
+msgid "Timeago|in %s years"
+msgstr ""
+
+msgid "Timeago|in 1 day"
+msgstr ""
+
+msgid "Timeago|in 1 hour"
+msgstr ""
+
+msgid "Timeago|in 1 minute"
+msgstr ""
+
+msgid "Timeago|in 1 month"
+msgstr ""
+
+msgid "Timeago|in 1 week"
+msgstr ""
+
+msgid "Timeago|in 1 year"
+msgstr ""
+
+msgid "Timeago|in a while"
+msgstr ""
+
+msgid "Timeago|less than a minute ago"
+msgstr ""
+
+msgid "Time|hr"
+msgid_plural "Time|hrs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Time|min"
+msgid_plural "Time|mins"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Time|s"
+msgstr ""
+
+msgid "Tip:"
+msgstr ""
+
+msgid "Title"
+msgstr ""
+
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
+msgid "Todo"
+msgstr ""
+
+msgid "Toggle sidebar"
+msgstr ""
+
+msgid "ToggleButton|Toggle Status: OFF"
+msgstr ""
+
+msgid "ToggleButton|Toggle Status: ON"
+msgstr ""
+
+msgid "Total Time"
+msgstr ""
+
+msgid "Total test time for all commits/merges"
+msgstr ""
+
+msgid "Total: %{total}"
+msgstr ""
+
+msgid "Track activity with Contribution Analytics."
+msgstr ""
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Track time with quick actions"
+msgstr ""
+
+msgid "Trigger this manual action"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
+msgid "Unable to reset project cache."
+msgstr ""
+
+msgid "Unknown"
+msgstr ""
+
+msgid "Unlock"
+msgstr ""
+
+msgid "Unlock this %{issuableDisplayName}? <strong>Everyone</strong> will be able to comment."
+msgstr ""
+
+msgid "Unlocked"
+msgstr ""
+
+msgid "Unresolve discussion"
+msgstr ""
+
+msgid "Unstar"
+msgstr ""
+
+msgid "Up to date"
+msgstr ""
+
+msgid "Upgrade your plan to activate Advanced Global Search."
+msgstr ""
+
+msgid "Upgrade your plan to activate Contribution Analytics."
+msgstr ""
+
+msgid "Upgrade your plan to activate Group Webhooks."
+msgstr ""
+
+msgid "Upgrade your plan to activate Issue weight."
+msgstr ""
+
+msgid "Upgrade your plan to improve Issue boards."
+msgstr ""
+
+msgid "Upload New File"
+msgstr ""
+
+msgid "Upload file"
+msgstr ""
+
+msgid "Upload new avatar"
+msgstr ""
+
+msgid "UploadLink|click to upload"
+msgstr ""
+
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
+msgid "Use the following registration token during setup:"
+msgstr ""
+
+msgid "Use your global notification setting"
+msgstr ""
+
+msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
+msgstr ""
+
+msgid "View epics list"
+msgstr ""
+
+msgid "View file @ "
+msgstr ""
+
+msgid "View labels"
+msgstr ""
+
+msgid "View open merge request"
+msgstr ""
+
+msgid "View replaced file @ "
+msgstr ""
+
+msgid "VisibilityLevel|Internal"
+msgstr ""
+
+msgid "VisibilityLevel|Private"
+msgstr ""
+
+msgid "VisibilityLevel|Public"
+msgstr ""
+
+msgid "VisibilityLevel|Unknown"
+msgstr ""
+
+msgid "Want to see the data? Please ask an administrator for access."
+msgstr ""
+
+msgid "We could not verify that one of your projects on GCP has billing enabled. Please try again."
+msgstr ""
+
+msgid "We don't have enough data to show this stage."
+msgstr ""
+
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
+msgid "Web IDE"
+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 ""
+
+msgid "Weight"
+msgstr ""
+
+msgid "Wiki"
+msgstr ""
+
+msgid "WikiClone|Clone your wiki"
+msgstr ""
+
+msgid "WikiClone|Git Access"
+msgstr ""
+
+msgid "WikiClone|Install Gollum"
+msgstr ""
+
+msgid "WikiClone|It is recommended to install %{markdown} so that GFM features render locally:"
+msgstr ""
+
+msgid "WikiClone|Start Gollum and edit locally"
+msgstr ""
+
+msgid "WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title."
+msgstr ""
+
+msgid "WikiEdit|There is already a page with the same title in that path."
+msgstr ""
+
+msgid "WikiEmptyPageError|You are not allowed to create wiki pages"
+msgstr ""
+
+msgid "WikiHistoricalPage|This is an old version of this page."
+msgstr ""
+
+msgid "WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}."
+msgstr ""
+
+msgid "WikiHistoricalPage|history"
+msgstr ""
+
+msgid "WikiHistoricalPage|most recent version"
+msgstr ""
+
+msgid "WikiMarkdownDocs|More examples are in the %{docs_link}"
+msgstr ""
+
+msgid "WikiMarkdownDocs|documentation"
+msgstr ""
+
+msgid "WikiMarkdownTip|To link to a (new) page, simply type %{link_example}"
+msgstr ""
+
+msgid "WikiNewPagePlaceholder|how-to-setup"
+msgstr ""
+
+msgid "WikiNewPageTip|Tip: You can specify the full path for the new file. We will automatically create any missing directories."
+msgstr ""
+
+msgid "WikiNewPageTitle|New Wiki Page"
+msgstr ""
+
+msgid "WikiPageConfirmDelete|Are you sure you want to delete this page?"
+msgstr ""
+
+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 ""
+
+msgid "WikiPageCreate|Create %{page_title}"
+msgstr ""
+
+msgid "WikiPageEdit|Update %{page_title}"
+msgstr ""
+
+msgid "WikiPage|Page slug"
+msgstr ""
+
+msgid "WikiPage|Write your content or drag files here..."
+msgstr ""
+
+msgid "Wiki|Create Page"
+msgstr ""
+
+msgid "Wiki|Create page"
+msgstr ""
+
+msgid "Wiki|Edit Page"
+msgstr ""
+
+msgid "Wiki|Empty page"
+msgstr ""
+
+msgid "Wiki|More Pages"
+msgstr ""
+
+msgid "Wiki|New page"
+msgstr ""
+
+msgid "Wiki|Page history"
+msgstr ""
+
+msgid "Wiki|Page version"
+msgstr ""
+
+msgid "Wiki|Pages"
+msgstr ""
+
+msgid "Wiki|Wiki Pages"
+msgstr ""
+
+msgid "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 ""
+
+msgid "Withdraw Access Request"
+msgstr ""
+
+msgid "Write a commit message..."
+msgstr ""
+
+msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You can also create a project from the command line."
+msgstr ""
+
+msgid "You can also star a label to make it a priority label."
+msgstr ""
+
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
+msgstr ""
+
+msgid "You can move around the graph by using the arrow keys."
+msgstr ""
+
+msgid "You can only add files when you are on a branch"
+msgstr ""
+
+msgid "You can only edit files when you are on a branch"
+msgstr ""
+
+msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
+msgstr ""
+
+msgid "You cannot write to this read-only GitLab instance."
+msgstr ""
+
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
+msgid "You have reached your project limit"
+msgstr ""
+
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
+msgid "You must sign in to star a project"
+msgstr ""
+
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
+msgid "You need permission."
+msgstr ""
+
+msgid "You will not get any notifications via email"
+msgstr ""
+
+msgid "You will only receive notifications for the events you choose"
+msgstr ""
+
+msgid "You will only receive notifications for threads you have participated in"
+msgstr ""
+
+msgid "You will receive notifications for any activity"
+msgstr ""
+
+msgid "You will receive notifications only for comments in which you were @mentioned"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
+msgid "You'll need to use different branch names to get a valid comparison."
+msgstr ""
+
+msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
+msgstr ""
+
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
+msgid "Your comment will not be visible to the public."
+msgstr ""
+
+msgid "Your groups"
+msgstr ""
+
+msgid "Your name"
+msgstr ""
+
+msgid "Your projects"
+msgstr ""
+
+msgid "assign yourself"
+msgstr ""
+
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
+msgid "ciReport|Code quality"
+msgstr ""
+
+msgid "ciReport|DAST detected no alerts by analyzing the review app"
+msgstr ""
+
+msgid "ciReport|Failed to load %{reportName} report"
+msgstr ""
+
+msgid "ciReport|Fixed:"
+msgstr ""
+
+msgid "ciReport|Instances"
+msgstr ""
+
+msgid "ciReport|Learn more about whitelisting"
+msgstr ""
+
+msgid "ciReport|Loading %{reportName} report"
+msgstr ""
+
+msgid "ciReport|No changes to code quality"
+msgstr ""
+
+msgid "ciReport|No changes to performance metrics"
+msgstr ""
+
+msgid "ciReport|Performance metrics"
+msgstr ""
+
+msgid "ciReport|SAST"
+msgstr ""
+
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
+msgid "ciReport|SAST detected no security vulnerabilities"
+msgstr ""
+
+msgid "ciReport|SAST:container no vulnerabilities were found"
+msgstr ""
+
+msgid "ciReport|Show complete code vulnerabilities report"
+msgstr ""
+
+msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
+msgstr ""
+
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
+msgid "confidentiality|You are going to turn off the confidentiality. This means <strong>everyone</strong> will be able to see and leave a comment on this issue."
+msgstr ""
+
+msgid "confidentiality|You are going to turn on the confidentiality. This means that only team members with <strong>at least Reporter access</strong> are able to see and leave comments on the issue."
+msgstr ""
+
+msgid "day"
+msgid_plural "days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
+msgstr ""
+
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
+msgid "merge request"
+msgid_plural "merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
+msgid "mrWidget|Cancel automatic merge"
+msgstr ""
+
+msgid "mrWidget|Check out branch"
+msgstr ""
+
+msgid "mrWidget|Checking ability to merge automatically"
+msgstr ""
+
+msgid "mrWidget|Cherry-pick"
+msgstr ""
+
+msgid "mrWidget|Cherry-pick this merge request in a new merge request"
+msgstr ""
+
+msgid "mrWidget|Closed"
+msgstr ""
+
+msgid "mrWidget|Closed by"
+msgstr ""
+
+msgid "mrWidget|Closes"
+msgstr ""
+
+msgid "mrWidget|Did not close"
+msgstr ""
+
+msgid "mrWidget|Email patches"
+msgstr ""
+
+msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
+msgstr ""
+
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
+msgid "mrWidget|Mentions"
+msgstr ""
+
+msgid "mrWidget|Merge"
+msgstr ""
+
+msgid "mrWidget|Merge failed."
+msgstr ""
+
+msgid "mrWidget|Merge locally"
+msgstr ""
+
+msgid "mrWidget|Merged by"
+msgstr ""
+
+msgid "mrWidget|Plain diff"
+msgstr ""
+
+msgid "mrWidget|Refresh"
+msgstr ""
+
+msgid "mrWidget|Refresh now"
+msgstr ""
+
+msgid "mrWidget|Refreshing now"
+msgstr ""
+
+msgid "mrWidget|Remove Source Branch"
+msgstr ""
+
+msgid "mrWidget|Remove source branch"
+msgstr ""
+
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
+msgid "mrWidget|Request to merge"
+msgstr ""
+
+msgid "mrWidget|Resolve conflicts"
+msgstr ""
+
+msgid "mrWidget|Revert"
+msgstr ""
+
+msgid "mrWidget|Revert this merge request in a new merge request"
+msgstr ""
+
+msgid "mrWidget|Set by"
+msgstr ""
+
+msgid "mrWidget|The changes were merged into"
+msgstr ""
+
+msgid "mrWidget|The changes were not merged into"
+msgstr ""
+
+msgid "mrWidget|The changes will be merged into"
+msgstr ""
+
+msgid "mrWidget|The source branch has been removed"
+msgstr ""
+
+msgid "mrWidget|The source branch is being removed"
+msgstr ""
+
+msgid "mrWidget|The source branch will be removed"
+msgstr ""
+
+msgid "mrWidget|The source branch will not be removed"
+msgstr ""
+
+msgid "mrWidget|There are merge conflicts"
+msgstr ""
+
+msgid "mrWidget|This merge request failed to be merged automatically"
+msgstr ""
+
+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 ""
+
+msgid "mrWidget|You can merge this merge request manually using the"
+msgstr ""
+
+msgid "mrWidget|You can remove source branch now"
+msgstr ""
+
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
+msgid "mrWidget|command line"
+msgstr ""
+
+msgid "mrWidget|into"
+msgstr ""
+
+msgid "mrWidget|to be merged automatically when the pipeline succeeds"
+msgstr ""
+
+msgid "new merge request"
+msgstr ""
+
+msgid "notification emails"
+msgstr ""
+
+msgid "or"
+msgstr ""
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "password"
+msgstr ""
+
+msgid "personal access token"
+msgstr ""
+
+msgid "remove due date"
+msgstr ""
+
+msgid "source"
+msgstr ""
+
+msgid "spendCommand|%{slash_command} will update the sum of the time spent."
+msgstr ""
+
+msgid "to help your contributors communicate effectively!"
+msgstr ""
+
+msgid "username"
+msgstr ""
+
+msgid "uses Kubernetes clusters to deploy your code!"
+msgstr ""
+
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index d176e67937f..85fe26b83a7 100644
--- a/locale/fr/gitlab.po
+++ b/locale/fr/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 03:59-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 06:24-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: French\n"
"Language: fr_FR\n"
@@ -17,7 +17,7 @@ msgstr ""
"X-Crowdin-File: /master/locale/gitlab.pot\n"
msgid " and"
-msgstr ""
+msgstr " et"
msgid "%d commit"
msgid_plural "%d commits"
@@ -26,13 +26,13 @@ msgstr[1] "%d commits"
msgid "%d commit behind"
msgid_plural "%d commits behind"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d commit de retard"
+msgstr[1] "%d commits de retard"
msgid "%d issue"
msgid_plural "%d issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d ticket"
+msgstr[1] "%d tickets"
msgid "%d layer"
msgid_plural "%d layers"
@@ -41,24 +41,30 @@ msgstr[1] "%d couches"
msgid "%d merge request"
msgid_plural "%d merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d demande de fusion"
+msgstr[1] "%d demandes de fusion"
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 validation supplémentaire a été masquée afin d'éviter de créer de problèmes de performances."
-msgstr[1] "%s validations supplémentaires ont été masquées afin d'éviter de créer de problèmes de performances."
+msgstr[1] "%s commits supplémentaires ont été masqués afin d'éviter un problème de performance."
+
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr "%{actionText} et %{openOrClose} %{noteable}"
msgid "%{commit_author_link} authored %{commit_timeago}"
-msgstr ""
+msgstr "%{commit_author_link} a créé %{commit_timeago}"
msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} participant•e"
msgstr[1] "%{count} participant•e•s"
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr "%{lock_path} est verrouillé par l’utilisateur GitLab %{lock_user_id}"
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
-msgstr "%{number_commits_behind} validations de retard sur %{default_branch}, %{number_commits_ahead} validations d'avance"
+msgstr "%{number_commits_behind} commits de retard sur %{default_branch}, %{number_commits_ahead} commits d'avance"
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
msgstr "%{number_of_failures} sur %{maximum_failures} tentative(s). GitLab va vous permettre d'accéder à la prochaine tentative."
@@ -66,6 +72,9 @@ msgstr "%{number_of_failures} sur %{maximum_failures} tentative(s). GitLab va vo
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "%{number_of_failures} échecs sur %{maximum_failures}. GitLab ne va plus réessayer automatiquement. Réinitialisez les informations de stockage lorsque le problème est résolu."
+msgid "%{openOrClose} %{noteable}"
+msgstr "%{openOrClose} %{noteable}"
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name} : la tentative d’accès au stockage a échouée sur l’hôte :"
@@ -130,35 +139,74 @@ msgstr "Ajouter un guide de contribution"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr "Ajouter des Webhooks de groupe et GitLab Enterprise Edition."
+msgid "Add Kubernetes cluster"
+msgstr "Ajouter un cluster Kubernetes"
+
msgid "Add License"
msgstr "Ajouter une licence"
+msgid "Add Readme"
+msgstr "Ajouter un fichier Readme"
+
msgid "Add new directory"
msgstr "Ajouter un nouveau dossier"
msgid "Add todo"
-msgstr ""
+msgstr "Ajouter à la liste à faire"
msgid "AdminArea|Stop all jobs"
-msgstr ""
+msgstr "Arrêtez tous les travaux"
msgid "AdminArea|Stop all jobs?"
-msgstr ""
+msgstr "Arrêtez tous les travaux?"
msgid "AdminArea|Stop jobs"
-msgstr ""
+msgstr "Arrêtez les travaux"
msgid "AdminArea|Stopping jobs failed"
-msgstr ""
+msgstr "L’arrêt des travaux a échoué"
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
-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 tous les travaux. Tous les travaux en cours seront interrompus."
msgid "AdminHealthPageLink|health page"
msgstr "État des services"
+msgid "AdminProjects|Delete"
+msgstr "Supprimer"
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr "Supprimer le projet %{projectName} ?"
+
+msgid "AdminProjects|Delete project"
+msgstr "Supprimer le projet"
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr "Spécifiez un domaine à utiliser par défaut pour les étapes Auto Review Apps et Auto Deploy de chaque projet."
+
+msgid "AdminUsers|Block user"
+msgstr "Bloquer l’utilisateur•rice"
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr "Supprimer l’utilisateur•rice %{username} et ses contributions ?"
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr "Supprimer l’utilisateur•rice %{username} ?"
+
+msgid "AdminUsers|Delete user"
+msgstr "Supprimer un•e utilisateur•rice"
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr "Supprimer l’utilisateur•rice et ses contributions"
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr "Pour confirmer, veuillez saisir %{projectName}"
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr "Pour confirmer, veuillez saisir %{username}"
+
msgid "Advanced"
-msgstr ""
+msgstr "Avancé"
msgid "Advanced settings"
msgstr "Paramètres avancés"
@@ -167,13 +215,13 @@ msgid "All"
msgstr "Tous"
msgid "All changes are committed"
-msgstr ""
+msgstr "Toutes les modifications sont validées"
msgid "Allows you to add and manage Kubernetes clusters."
-msgstr ""
+msgstr "Vous permet d’ajouter et de gérer des clusters Kubernetes."
msgid "An error occurred previewing the blob"
-msgstr ""
+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/désactivation de l’abonnement aux notifications"
@@ -181,38 +229,74 @@ msgstr "Une erreur s’est produite lors de l’activation/désactivation de lâ€
msgid "An error occurred when updating the issue weight"
msgstr "Une erreur s'est produite lors de la mise à jour du poids du ticket"
+msgid "An error occurred while adding approver"
+msgstr "Une erreur s’est produite lors de l’ajout de l'approbateur•rice"
+
+msgid "An error occurred while detecting host keys"
+msgstr "Une erreur s’est produite lors de la détection des clés de l'hôte"
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
-msgstr ""
+msgstr "Une erreur s’est produite lors de la révocation de la mise en avant de la fonctionnalité. Actualisez la page et essayez de la révoquer à nouveau."
msgid "An error occurred while fetching markdown preview"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la prévisualisation markdown"
msgid "An error occurred while fetching sidebar data"
msgstr "Une erreur s'est produite lors de la récupération des données de la barre latérale"
+msgid "An error occurred while fetching the pipeline."
+msgstr "Une erreur est survenue pendant la récupération du pipeline."
+
msgid "An error occurred while getting projects"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la récupération des projets"
+
+msgid "An error occurred while importing project"
+msgstr "Une erreur s’est produite lors de l’importation du projet"
+
+msgid "An error occurred while initializing path locks"
+msgstr "Une erreur s’est produite lors de l’initialisation des verrous de chemin"
+
+msgid "An error occurred while loading commits"
+msgstr "Une erreur s’est produite lors du chargement des commits"
+
+msgid "An error occurred while loading diff"
+msgstr "Une erreur s’est produite lors du chargement du diff"
msgid "An error occurred while loading filenames"
-msgstr ""
+msgstr "Une erreur s’est produite lors du chargement des noms de fichiers"
+
+msgid "An error occurred while loading the file"
+msgstr "Une erreur s’est produite lors du chargement du fichier"
+
+msgid "An error occurred while making the request."
+msgstr "Une erreur s’est produite lors de la requête."
+
+msgid "An error occurred while removing approver"
+msgstr "Une erreur s’est produite lors de la suppression de l’approbateur•rice"
msgid "An error occurred while rendering KaTeX"
-msgstr ""
+msgstr "Une erreur s’est produite lors du rendu de KaTeX"
msgid "An error occurred while rendering preview broadcast message"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la prévisualisation de la bannière"
msgid "An error occurred while retrieving calendar activity"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la récupération de l’activité du calendrier"
msgid "An error occurred while retrieving diff"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la récupération du diff"
+
+msgid "An error occurred while saving LDAP override status. Please try again."
+msgstr "Une erreur s’est produite lors de l’enregistrement du statut de remplacement LDAP. Veuillez réessayer."
+
+msgid "An error occurred while saving assignees"
+msgstr "Une erreur s’est produite lors de l’enregistrement des destinataires"
msgid "An error occurred while validating username"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la validation du nom d’utilisateur•rice"
msgid "An error occurred. Please try again."
-msgstr "Une erreur est survenue. Merci de réessayer."
+msgstr "Une erreur s’est produite. Veuillez réessayer."
msgid "Appearance"
msgstr "Apparence"
@@ -232,15 +316,15 @@ msgstr "Projet archivé ! Le dépôt est en lecture seule"
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Êtes-vous sûr·e de vouloir supprimer ce pipeline programmé ?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "Êtes-vous sûr·e de vouloir annuler vos modifications ?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "Êtes-vous sûr·e de vouloir réinitialiser le jeton d’inscription ?"
msgid "Are you sure you want to reset the health check token?"
msgstr "Êtes-vous sûr de vouloir réinitialiser le jeton de bilan de santé ?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr "Êtes-vous sûr•e de vouloir déverrouiller %{path_lock_path} ?"
+
msgid "Are you sure?"
msgstr "Êtes-vous certain ?"
@@ -248,19 +332,19 @@ msgid "Artifacts"
msgstr "Artéfacts"
msgid "Assign custom color like #FF0000"
-msgstr ""
+msgstr "Attribuer une couleur personnalisée comme #FF0000"
msgid "Assign labels"
-msgstr ""
+msgstr "Attribuer des labels"
msgid "Assign milestone"
-msgstr ""
+msgstr "Attribuer un jalon"
msgid "Assign to"
-msgstr ""
+msgstr "Assigner à"
msgid "Assignee"
-msgstr ""
+msgstr "Assigné•e"
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Attachez un fichier par glisser &amp; déposer ou %{upload_link}"
@@ -278,13 +362,16 @@ msgid "Author"
msgstr "Auteur"
msgid "Authors: %{authors}"
-msgstr ""
+msgstr "Auteur•e•s : %{authors}"
+
+msgid "Auto DevOps enabled"
+msgstr "Auto DevOps activé"
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
-msgstr ""
+msgstr "Auto Review Apps et Auto Deploy ont besoin d’un %{kubernetes} qui fonctionne correctement."
msgid "Auto Review Apps and Auto Deploy need a domain name and a %{kubernetes} to work correctly."
-msgstr ""
+msgstr "Auto Review Apps et Auto Deploy ont besoin d’un nom de domaine et d’un %{kubernetes} qui fonctionne correctement."
msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
msgstr "Les applications de révision automatique et de déploiement automatique requièrent un nom de domaine pour fonctionner correctement."
@@ -304,17 +391,26 @@ msgstr "AutoDevOps vous permet de construire, tester et déployer automatiquemen
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "En savoir plus dans %{link_to_documentation}"
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
-msgstr "Vous pouvez activer %{link_to_settings} pour ce projet."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr "Vous pouvez automatiquement générer et tester votre application si vous %{link_to_auto_devops_settings} pour ce projet. Vous pouvez aussi la déployer automatiquement, si vous %{link_to_add_kubernetes_cluster}."
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr "ajouter un cluster Kubernetes"
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr "activer Auto DevOps (Bêta)"
msgid "Available"
msgstr "Disponible"
msgid "Avatar will be removed. Are you sure?"
-msgstr ""
+msgstr "L’avatar sera supprimé. Êtes-vous sûr•e ?"
msgid "Average per day: %{average}"
-msgstr ""
+msgstr "Moyenne par jour : %{average}"
+
+msgid "Begin with the selected commit"
+msgstr "Commencer avec le commit sélectionné"
msgid "Billing"
msgstr "Facturation"
@@ -370,13 +466,10 @@ msgstr "payé annuellement pour %{price_per_year}"
msgid "BillingPlans|per user"
msgstr "par utilisateur"
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "Branche"
-msgstr[1] "Branches"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] "Branche (%{branch_count})"
+msgstr[1] "Branches (%{branch_count})"
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "La branche <strong>%{branch_name}</strong> a été créée. Pour mettre en place le déploiement automatisé, sélectionnez un modèle de fichier Yaml pour l'intégration continue (CI) de GitLab, et validez les modifications. %{link_to_autodeploy_doc}"
@@ -400,7 +493,7 @@ msgid "Branches"
msgstr "Branches"
msgid "Branches|Cant find HEAD commit for this branch"
-msgstr "Impossible de trouver la validation HEAD pour cette branche"
+msgstr "Impossible de trouver le commit HEAD pour cette branche"
msgid "Branches|Compare"
msgstr "Comparer"
@@ -502,7 +595,7 @@ msgid "CI / CD"
msgstr "Intégration continu / Déploiement continu"
msgid "CI/CD configuration"
-msgstr ""
+msgstr "Configuration CI/CD"
msgid "CICD|Jobs"
msgstr "Tâches"
@@ -514,7 +607,7 @@ msgid "Cancel edit"
msgstr "Annuler modification"
msgid "Cannot modify managed Kubernetes cluster"
-msgstr ""
+msgstr "Impossible de modifier le cluster géré par Kubernetes"
msgid "Change Weight"
msgstr "Changer le poids"
@@ -532,13 +625,13 @@ msgid "ChangeTypeAction|Revert"
msgstr "Défaire"
msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
-msgstr ""
+msgstr "Cela va créer un nouveau commit afin de défaire les modifications existantes."
msgid "Changelog"
msgstr "Journal des modifications"
msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision."
-msgstr ""
+msgstr "Les modifications sont affichées comme si la révision <b>source</b> était fusionnée dans la révision<b>cible</b>."
msgid "Charts"
msgstr "Statistiques"
@@ -547,7 +640,7 @@ msgid "Chat"
msgstr "Chat"
msgid "Check interval"
-msgstr ""
+msgstr "Intervalle de vérification"
msgid "Checking %{text} availability…"
msgstr "Vérification de la disponibilité de %{text}…"
@@ -556,25 +649,25 @@ msgid "Checking branch availability..."
msgstr "Vérification de la disponibilité du nom de branche..."
msgid "Cherry-pick this commit"
-msgstr "Picorer cette validation"
+msgstr "Picorer ce commit"
msgid "Cherry-pick this merge request"
msgstr "Picorer cette demande de fusion"
msgid "Choose File ..."
-msgstr ""
+msgstr "Choisir le fichier…"
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 "Choisissez une branche / tag (par exemple %{master}) ou entrez un commit (par exemple %{sha}) pour voir ce qui a changé ou pour créer une demande de fusion."
msgid "Choose file..."
-msgstr ""
+msgstr "Choisir le fichier…"
msgid "Choose which groups you wish to synchronize to this secondary node."
-msgstr ""
+msgstr "Choisissez les groupes que vous souhaitez synchroniser avec ce nœud secondaire."
msgid "Choose which shards you wish to synchronize to this secondary node."
-msgstr ""
+msgstr "Choisissez les partitions que vous souhaitez synchroniser avec ce nœud secondaire."
msgid "CiStatusLabel|canceled"
msgstr "annulé"
@@ -631,46 +724,49 @@ msgid "CiStatus|running"
msgstr "en cours"
msgid "CiVariables|Input variable key"
-msgstr ""
+msgstr "Nom de la variable"
msgid "CiVariables|Input variable value"
-msgstr ""
+msgstr "Valeur de la variable"
msgid "CiVariables|Remove variable row"
-msgstr ""
+msgstr "Supprimer cette variable"
msgid "CiVariable|* (All environments)"
-msgstr ""
+msgstr "* (Tous les environnements)"
msgid "CiVariable|All environments"
-msgstr ""
+msgstr "Tous les environnements"
msgid "CiVariable|Create wildcard"
-msgstr ""
+msgstr "Créer un caractère générique"
msgid "CiVariable|Error occured while saving variables"
-msgstr ""
+msgstr "Une erreur s’est produite pendant la sauvegarde des variables"
msgid "CiVariable|New environment"
-msgstr ""
+msgstr "Nouvel environnement"
msgid "CiVariable|Protected"
-msgstr ""
+msgstr "Protégée"
msgid "CiVariable|Search environments"
-msgstr ""
+msgstr "Chercher dans les environnements"
msgid "CiVariable|Toggle protected"
-msgstr ""
+msgstr "Changer l’état de protection"
msgid "CiVariable|Validation failed"
-msgstr ""
+msgstr "La validation a échoué"
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr "CircuitBreaker API"
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr "Cliquez sur le bouton ci-dessous pour lancer le processus d’installation en accédant à la page Kubernetes"
+
msgid "Click to expand text"
-msgstr ""
+msgstr "Cliquez pour agrandir le texte"
msgid "Clone repository"
msgstr "Cloner le dépôt"
@@ -679,28 +775,28 @@ msgid "Close"
msgstr "Fermer"
msgid "Closed"
-msgstr ""
+msgstr "Fermée"
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
-msgstr ""
+msgstr "%{appList} a été installé avec succès sur votre cluster Kubernetes"
msgid "ClusterIntegration|API URL"
msgstr "URL de l'API"
msgid "ClusterIntegration|Add Kubernetes cluster"
-msgstr ""
+msgstr "Ajouter un cluster Kubernetes"
msgid "ClusterIntegration|Add an existing Kubernetes cluster"
-msgstr ""
+msgstr "Ajouter un cluster Kubernetes existant"
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration"
-msgstr ""
+msgstr "Options avancées sur l’intégration de ce cluster Kubernetes"
msgid "ClusterIntegration|Applications"
msgstr "Applications"
msgid "ClusterIntegration|Are you sure you want to remove this Kubernetes cluster's integration? This will not delete your actual Kubernetes cluster."
-msgstr ""
+msgstr "Êtes-vous sûr•e de vouloir supprimer l'intégration de ce cluster Kubernetes? Cela ne supprimera pas votre cluster Kubernetes."
msgid "ClusterIntegration|CA Certificate"
msgstr "Certificat d‘autorité de certification"
@@ -709,13 +805,13 @@ msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Paquet de l‘Autorité de certification (format PEM)"
msgid "ClusterIntegration|Choose how to set up Kubernetes cluster integration"
-msgstr ""
+msgstr "Choisissez comment configurer l’intégration de cluster Kubernetes"
msgid "ClusterIntegration|Choose which of your project's environments will use this Kubernetes cluster."
-msgstr ""
+msgstr "Choisissez les environnements de votre projet qui utiliseront ce cluster Kubernetes."
msgid "ClusterIntegration|Control how your Kubernetes cluster integrates with GitLab"
-msgstr ""
+msgstr "Contrôlez l’intégration de votre cluster Kubernetes avec GitLab"
msgid "ClusterIntegration|Copy API URL"
msgstr "Copier l’URL de l’API"
@@ -723,20 +819,23 @@ msgstr "Copier l’URL de l’API"
msgid "ClusterIntegration|Copy CA Certificate"
msgstr "Copier le certificat CA"
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr "Copier l’adresse IP entrante dans le presse-papiers"
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
-msgstr ""
+msgstr "Copier le nom du cluster Kubernetes"
msgid "ClusterIntegration|Copy Token"
msgstr "Copier le jeton"
msgid "ClusterIntegration|Create Kubernetes cluster"
-msgstr ""
+msgstr "Créer un cluster Kubernetes"
msgid "ClusterIntegration|Create Kubernetes cluster on Google Kubernetes Engine"
-msgstr ""
+msgstr "Créer un cluster Kubernetes sur Google Kubernetes Engine"
msgid "ClusterIntegration|Create a new Kubernetes cluster on Google Kubernetes Engine right from GitLab"
-msgstr ""
+msgstr "Créer un nouveau cluster Kubernetes sur Google Kubernetes Engine directement depuis GitLab"
msgid "ClusterIntegration|Create on GKE"
msgstr "Créer sur GKE"
@@ -745,13 +844,13 @@ msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
msgstr "Entrer les détails pour le cluster Kubernetes existant"
msgid "ClusterIntegration|Enter the details for your Kubernetes cluster"
-msgstr ""
+msgstr "Entrez les détails de votre cluster Kubernetes"
msgid "ClusterIntegration|Environment scope"
-msgstr ""
+msgstr "Portée de l’environnement"
msgid "ClusterIntegration|GitLab Integration"
-msgstr ""
+msgstr "Intégration GitLab"
msgid "ClusterIntegration|GitLab Runner"
msgstr "Éxécuteur GitLab"
@@ -771,6 +870,9 @@ msgstr "Helm Tiller"
msgid "ClusterIntegration|Ingress"
msgstr "Ingress"
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr "Adresse IP entrante"
+
msgid "ClusterIntegration|Install"
msgstr "Installer"
@@ -781,70 +883,67 @@ msgid "ClusterIntegration|Installing"
msgstr "En cours d’installation"
msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr ""
+msgstr "Intégrez l’automatisation du cluster Kubernetes"
msgid "ClusterIntegration|Integration status"
-msgstr ""
+msgstr "Statut d’intégration"
msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
+msgstr "Cluster Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster details"
-msgstr ""
+msgstr "Détails du cluster Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster integration"
-msgstr ""
+msgstr "Intégration d’un cluster Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster integration is disabled for this project."
-msgstr ""
+msgstr "L’intégration de cluster Kubernetes est désactivée pour ce projet."
msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project."
-msgstr ""
+msgstr "L’intégration de cluster Kubernetes est activée pour ce projet."
msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project. Disabling this integration will not affect your Kubernetes cluster, it will only temporarily turn off GitLab's connection to it."
-msgstr ""
+msgstr "L’intégration de cluster Kubernetes est activée pour ce projet. La désactivation de cette intégration n’affectera pas votre cluster Kubernetes, elle ne désactivera que temporairement la connexion de GitLab."
msgid "ClusterIntegration|Kubernetes cluster is being created on Google Kubernetes Engine..."
-msgstr ""
+msgstr "Le cluster Kubernetes est en cours de création sur Google Kubernetes Engine…"
msgid "ClusterIntegration|Kubernetes cluster name"
-msgstr ""
+msgstr "Nom du cluster Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine. Refresh the page to see Kubernetes cluster's details"
-msgstr ""
+msgstr "Le cluster Kubernetes a été créé avec succès sur Google Kubernetes Engine. Actualisez la page pour voir les détails du cluster Kubernetes"
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
-msgstr ""
+msgstr "Les clusters Kubernetes vous permettent d’utiliser des applications de révision, de déployer vos applications, d’exécuter vos pipelines et bien plus encore. %{link_to_help_page}"
msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
+msgstr "Les clusters Kubernetes peuvent être utilisés pour déployer des applications et fournir des applications de révision pour ce projet"
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "En savoir plus sur %{link_to_documentation}"
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
-msgstr ""
+msgstr "En savoir plus sur les environnements"
msgid "ClusterIntegration|Machine type"
msgstr "Type de machine"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
-msgstr ""
+msgstr "Assurez-vous que votre compte %{link_to_requirements} pour créer des clusters Kubernetes"
msgid "ClusterIntegration|Manage"
-msgstr ""
+msgstr "Gérer"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
-msgstr ""
+msgstr "Gérez votre cluster Kubernetes en visitant %{link_gke}"
msgid "ClusterIntegration|More information"
-msgstr ""
+msgstr "Plus d’informations"
msgid "ClusterIntegration|Multiple Kubernetes clusters are available in GitLab Enterprise Edition Premium and Ultimate"
-msgstr ""
+msgstr "Plusieurs clusters Kubernetes sont disponibles dans GitLab Enterprise Edition Premium et Ultimate"
msgid "ClusterIntegration|Note:"
msgstr "Remarque :"
@@ -853,7 +952,7 @@ msgid "ClusterIntegration|Number of nodes"
msgstr "Nombre de nœuds"
msgid "ClusterIntegration|Please enter access information for your Kubernetes cluster. If you need help, you can read our %{link_to_help_page} on Kubernetes"
-msgstr ""
+msgstr "Veuillez entrer les informations d’accès de votre cluster Kubernetes. Si vous avez besoin d'aide, vous pouvez lire notre %{link_to_help_page} sur Kubernetes"
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr "Veuillez vous assurer que votre compte Google répond aux exigences suivantes : "
@@ -868,19 +967,19 @@ msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr "Espace de noms du projet (facultatif, unique)"
msgid "ClusterIntegration|Prometheus"
-msgstr ""
+msgstr "Prometheus"
msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration."
-msgstr ""
+msgstr "Lisez notre %{link_to_help_page} sur l’intégration d’un cluster Kubernetes."
msgid "ClusterIntegration|Remove Kubernetes cluster integration"
-msgstr ""
+msgstr "Supprimer l’intégration du cluster Kubernetes"
msgid "ClusterIntegration|Remove integration"
msgstr "Retirer l’intégration"
msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
-msgstr ""
+msgstr "Supprimer la configuration de ce cluster Kubernetes de ce projet. Cela ne supprimera pas votre cluster Kubernetes actuel."
msgid "ClusterIntegration|Request to begin installing failed"
msgstr "La demande de lancement d'installation a échoué"
@@ -889,7 +988,7 @@ msgid "ClusterIntegration|Save changes"
msgstr "Enregistrer les modifications"
msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
-msgstr ""
+msgstr "Voir et modifier les détails de votre cluster Kubernetes"
msgid "ClusterIntegration|See machine types"
msgstr "Voir les types de machine"
@@ -910,25 +1009,25 @@ msgid "ClusterIntegration|Something went wrong on our end."
msgstr "Un problème est survenu de notre côté."
msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster on Google Kubernetes Engine"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la création de votre cluster Kubernetes sur Google Kubernetes Engine"
msgid "ClusterIntegration|Something went wrong while installing %{title}"
msgstr "Une erreur s’est produite lors de l'installation de %{title}"
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
-msgstr ""
+msgstr "Ce compte doit disposer des autorisations pour créer un cluster Kubernetes dans le %{link_to_container_project} spécifié ci-dessous"
msgid "ClusterIntegration|Toggle Kubernetes Cluster"
-msgstr ""
+msgstr "Activer le cluster Kubernetes"
msgid "ClusterIntegration|Toggle Kubernetes cluster"
-msgstr ""
+msgstr "Activer/désactiver le cluster Kubernetes"
msgid "ClusterIntegration|Token"
msgstr "Jeton"
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 ""
+msgstr "Avec un cluster Kubernetes associé à ce projet, vous pouvez utiliser des applications de révision, déployer vos applications, exécuter vos pipelines, et bien plus encore."
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
msgstr "Votre compte doit disposer de %{link_to_kubernetes_engine}"
@@ -940,7 +1039,7 @@ msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr "Accèder à Google Kubernetes Engine"
msgid "ClusterIntegration|check the pricing here"
-msgstr ""
+msgstr "vérifiez le prix ici"
msgid "ClusterIntegration|documentation"
msgstr "documentation"
@@ -958,6 +1057,12 @@ msgid "ClusterIntegration|properly configured"
msgstr "correctement configuré"
msgid "Collapse"
+msgstr "Réduire"
+
+msgid "Comment and resolve discussion"
+msgstr "Commenter et résoudre la discussion"
+
+msgid "Comment and unresolve discussion"
msgstr ""
msgid "Comments"
@@ -965,53 +1070,61 @@ msgstr "Commentaires"
msgid "Commit"
msgid_plural "Commits"
-msgstr[0] "Validation"
-msgstr[1] "Validations"
+msgstr[0] "Commit"
+msgstr[1] "Commits"
+
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] "Commit (%{commit_count})"
+msgstr[1] "Commits (%{commit_count})"
msgid "Commit Message"
-msgstr "Message de validation"
+msgstr "Message du commit"
msgid "Commit duration in minutes for last 30 commits"
msgstr "Durée des 30 derniers pipelines en minutes"
msgid "Commit message"
-msgstr "Message de validation"
+msgstr "Message de commit"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
+msgstr "Statistiques des commits pour %{ref} %{start_time} - %{end_time}"
+
+msgid "Commit to %{branchName} branch"
msgstr ""
msgid "CommitBoxTitle|Commit"
-msgstr "Validation"
+msgstr "Commit"
msgid "CommitMessage|Add %{file_name}"
msgstr "Ajout de %{file_name}"
msgid "Commits"
-msgstr "Validations"
+msgstr "Commits"
msgid "Commits feed"
-msgstr "Flux de validations"
+msgstr "Flux des commits"
msgid "Commits per day hour (UTC)"
-msgstr ""
+msgstr "Commits par heure du jour (UTC)"
msgid "Commits per day of month"
-msgstr ""
+msgstr "Commits par jour du mois"
msgid "Commits per weekday"
-msgstr ""
+msgstr "Commits par jour de la semaine"
msgid "Commits|An error occurred while fetching merge requests data."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des données de demandes de fusion."
msgid "Commits|Commit: %{commitText}"
-msgstr ""
+msgstr "Commit : %{commitText}"
msgid "Commits|History"
msgstr "Historique"
msgid "Commits|No related merge requests found"
-msgstr ""
+msgstr "Aucune demande de fusion associée trouvée"
msgid "Committed by"
msgstr "Validé par"
@@ -1020,28 +1133,28 @@ msgid "Compare"
msgstr "Comparer"
msgid "Compare Git revisions"
-msgstr ""
+msgstr "Comparer les révisions Git"
msgid "Compare Revisions"
-msgstr ""
+msgstr "Comparer les révisions"
msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
-msgstr ""
+msgstr "%{source_branch} et %{target_branch} sont identiques."
msgid "CompareBranches|Compare"
-msgstr ""
+msgstr "Comparer"
msgid "CompareBranches|Source"
-msgstr ""
+msgstr "Source"
msgid "CompareBranches|Target"
-msgstr ""
+msgstr "Cible"
msgid "CompareBranches|There isn't anything to compare."
-msgstr ""
+msgstr "Il n’y a rien à comparer."
msgid "Confidentiality"
-msgstr ""
+msgstr "Confidentialité"
msgid "Container Registry"
msgstr "Registre de conteneur"
@@ -1095,13 +1208,13 @@ msgid "Contributors"
msgstr "Contributeurs"
msgid "ContributorsPage|%{startDate} – %{endDate}"
-msgstr ""
+msgstr "%{startDate} - %{endDate}"
msgid "ContributorsPage|Building repository graph."
msgstr "Construction du graphique du dépôt."
msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
-msgstr "Validations sur %{branch_name}, à l’exclusion des validations de fusion. Limité à 6 000 validations."
+msgstr "Commit sur %{branch_name}, à l'exclusion des commits de fusion. Limité à 6 000 commits."
msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
msgstr "Veuillez patienter, cette page va être automatiquement actualisée."
@@ -1119,23 +1232,35 @@ msgid "Copy URL to clipboard"
msgstr "Copier l'URL dans le presse-papier"
msgid "Copy branch name to clipboard"
-msgstr ""
+msgstr "Copier le nom de la branche dans le presse-papiers"
+
+msgid "Copy command to clipboard"
+msgstr "Copier la commande dans le presse-papiers"
msgid "Copy commit SHA to clipboard"
-msgstr "Copier le SHA de la validation"
+msgstr "Copier le SHA du commit"
msgid "Copy reference to clipboard"
-msgstr ""
+msgstr "Copier la référence dans le presse-papiers"
msgid "Create"
-msgstr ""
+msgstr "Créer"
msgid "Create New Directory"
msgstr "Créer un nouveau dossier"
+msgid "Create a new branch"
+msgstr "Créer une nouvelle branche"
+
+msgid "Create a new branch and merge request"
+msgstr "Créer une nouvelle branche et demande de fusion"
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Créer un jeton d’accès personnel pour votre compte afin de récupérer ou pousser par %{protocol}."
+msgid "Create branch"
+msgstr "Créer une branche"
+
msgid "Create directory"
msgstr "Créer un dossier"
@@ -1149,11 +1274,14 @@ msgid "Create file"
msgstr "Créer un fichier"
msgid "Create lists from labels. Issues with that label appear in that list."
-msgstr ""
+msgstr "Créer des listes à partir de labels. Les tickets avec ce label apparaissent dans cette liste."
msgid "Create merge request"
msgstr "Créer une demande de fusion"
+msgid "Create merge request and branch"
+msgstr "Créer une demande de fusion et une branche"
+
msgid "Create new branch"
msgstr "Créer une nouvelle branche"
@@ -1164,7 +1292,7 @@ msgid "Create new file"
msgstr "Créer un nouveau fichier"
msgid "Create new label"
-msgstr ""
+msgstr "Créer un nouveau label"
msgid "Create new..."
msgstr "Créer nouveau..."
@@ -1178,6 +1306,12 @@ msgstr "Tag"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Créer un jeton d'accès personnel"
+msgid "Creates a new branch from %{branchName}"
+msgstr "Crée une nouvelle branche à partir de %{branchName}"
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr "Crée une nouvelle branche à partir de %{branchName} et redirige pour créer une nouvelle demande de fusion"
+
msgid "Creating epic"
msgstr "Création de l'épopée en cours"
@@ -1188,7 +1322,7 @@ msgid "Cron syntax"
msgstr "Syntaxe Cron"
msgid "Current node"
-msgstr ""
+msgstr "NÅ“ud actuel"
msgid "Custom notification events"
msgstr "Événements de notification personnalisés"
@@ -1232,6 +1366,9 @@ msgstr "Déc."
msgid "December"
msgstr "Décembre"
+msgid "Default classification label"
+msgstr "Label de classement par défaut"
+
msgid "Define a custom pattern with cron syntax"
msgstr "Définir un schéma personnalisé avec une syntaxe Cron"
@@ -1256,19 +1393,19 @@ msgid "Details"
msgstr "Détails"
msgid "Diffs|No file name available"
-msgstr ""
+msgstr "Aucun nom de fichier disponible"
msgid "Directory name"
msgstr "Nom du dossier"
msgid "Disable"
-msgstr ""
+msgstr "Désactiver"
-msgid "Discard changes"
-msgstr "Supprimer les modifications"
+msgid "Discard draft"
+msgstr "Supprimer le brouillon"
msgid "Discover GitLab Geo."
-msgstr ""
+msgstr "Découvrez GitLab Geo."
msgid "Dismiss Cycle Analytics introduction box"
msgstr "Passer l’introduction Cycle Analytics"
@@ -1307,7 +1444,7 @@ msgid "DownloadSource|Download"
msgstr "Télécharger"
msgid "Due date"
-msgstr ""
+msgstr "Date d’échéance"
msgid "Edit"
msgstr "Éditer"
@@ -1316,13 +1453,16 @@ msgid "Edit Pipeline Schedule %{id}"
msgstr "Éditer le pipeline programmé %{id}"
msgid "Edit files in the editor and commit changes here"
-msgstr ""
+msgstr "Modifier les fichiers dans l'éditeur et valider les modifications ici"
msgid "Emails"
msgstr "Courriels"
msgid "Enable"
-msgstr ""
+msgstr "Activer"
+
+msgid "Enable Auto DevOps"
+msgstr "Activer Auto DevOps"
msgid "Environments|An error occurred while fetching the environments."
msgstr "Une erreur s‘est produite lors de la récupération des environnements."
@@ -1331,7 +1471,7 @@ msgid "Environments|An error occurred while making the request."
msgstr "Une erreur s’est produite lors de la requête."
msgid "Environments|Commit"
-msgstr "Validation"
+msgstr "Commit"
msgid "Environments|Deployment"
msgstr "Déploiement"
@@ -1378,38 +1518,47 @@ msgstr "L’épopée sera supprimée ! Êtes-vous sûr•e ?"
msgid "Epics"
msgstr "Épopées"
+msgid "Epics Roadmap"
+msgstr "Feuille de route des épopées"
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr "Les épopées vous permettent de gérer votre portefeuille de projets plus efficacement et avec moins d'effort"
+msgid "Error checking branch data. Please try again."
+msgstr "Erreur lors de la vérification des données de branche. Veuillez réessayer."
+
+msgid "Error committing changes. Please try again."
+msgstr "Erreur lors de la validation des modifications. Veuillez réessayer."
+
msgid "Error creating epic"
msgstr "Erreur lors de la création de l’épopée"
msgid "Error fetching contributors data."
-msgstr ""
+msgstr "Erreur lors de l’extraction des données des contributeur•rice•s."
msgid "Error fetching labels."
-msgstr ""
+msgstr "Erreur lors de la récupération des labels."
msgid "Error fetching network graph."
-msgstr ""
+msgstr "Erreur lors de la récupération du graphique du réseau."
msgid "Error fetching refs"
-msgstr ""
+msgstr "Erreur lors de la récupération des refs"
msgid "Error fetching usage ping data."
-msgstr ""
+msgstr "Erreur lors de la récupération des données d’utilisation."
msgid "Error occurred when toggling the notification subscription"
msgstr "Une erreur s’est produite lors de l’activation/désactivation de l’abonnement aux notifications"
msgid "Error saving label update."
-msgstr ""
+msgstr "Erreur lors de la mise à jour du label."
msgid "Error updating status for all todos."
-msgstr ""
+msgstr "Erreur lors de la mise à jour de l’état de la liste de tâches à faire."
msgid "Error updating todo status."
-msgstr ""
+msgstr "Erreur lors de la mise à jour du statut de la tâche à faire."
msgid "EventFilterBy|Filter by all"
msgstr "Aucun filtre"
@@ -1439,7 +1588,7 @@ msgid "Every week (Sundays at 4:00am)"
msgstr "Chaque semaine (dimanche à 4h00 du matin)"
msgid "Expand"
-msgstr ""
+msgstr "Ouvrir"
msgid "Explore projects"
msgstr "Explorer les projets"
@@ -1447,12 +1596,36 @@ msgstr "Explorer les projets"
msgid "Explore public groups"
msgstr "Explorer les groupes publics"
+msgid "External Classification Policy Authorization"
+msgstr "Autorisation de politique de classification externe"
+
+msgid "External authorization denied access to this project"
+msgstr "L’autorisation externe a refusé l’accès à ce projet"
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr "Label de classification"
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr "Label de classification"
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr "Quand aucun label de classification n’est défini, le label par défaut `%{default_label}` sera utilisé."
+
+msgid "Failed Jobs"
+msgstr "Travaux ayant échoué"
+
msgid "Failed to change the owner"
msgstr "Échec du changement de propriétaire"
+msgid "Failed to remove issue from board, please try again."
+msgstr "Impossible de supprimer le ticket du tableau, veuillez réessayer."
+
msgid "Failed to remove the pipeline schedule"
msgstr "Échec de la suppression du pipeline programmé"
+msgid "Failed to update issues, please try again."
+msgstr "Échec de la mise à jour du ticket. Veuillez réessayer."
+
msgid "Feb"
msgstr "Févr."
@@ -1460,7 +1633,7 @@ msgid "February"
msgstr "Février"
msgid "Fields on this page are now uneditable, you can configure"
-msgstr ""
+msgstr "Les champs sur cette page sont désormais non modifiables, vous pouvez configurer"
msgid "File name"
msgstr "Nom du fichier"
@@ -1468,8 +1641,11 @@ msgstr "Nom du fichier"
msgid "Files"
msgstr "Fichiers"
+msgid "Files (%{human_size})"
+msgstr "Fichiers (%{human_size})"
+
msgid "Filter by commit message"
-msgstr "Filtrer par message de validation"
+msgstr "Filtrer par message de commit"
msgid "Find by path"
msgstr "Rechercher par chemin"
@@ -1503,11 +1679,14 @@ msgstr "Depuis la création du ticket jusqu'au déploiement en production"
msgid "From merge request merge until deploy to production"
msgstr "Depuis la fusion de la demande de fusion jusqu'au déploiement en production"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr "À partir de l’affichage des détails du cluster Kubernetes, installez un Exécuteur à partir de la liste des applications"
+
msgid "GPG Keys"
msgstr "Clés GPG"
msgid "Generate a default set of labels"
-msgstr ""
+msgstr "Générer un ensemble de labels par défaut"
msgid "Geo Nodes"
msgstr "NÅ“uds Geo"
@@ -1519,100 +1698,100 @@ msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an
msgstr "Le nœud est lent, surchargé, ou il vient juste de récupérer après un problème."
msgid "GeoNodes|Database replication lag:"
-msgstr ""
+msgstr "Retard de réplication de la base de données :"
msgid "GeoNodes|Disabling a node stops the sync process. Are you sure?"
-msgstr ""
+msgstr "La désactivation d’un nœud arrête le processus de synchronisation. Êtes-vous sûr•e?"
msgid "GeoNodes|Does not match the primary storage configuration"
-msgstr ""
+msgstr "Ne correspond pas à la configuration de stockage principale"
msgid "GeoNodes|Failed"
-msgstr ""
+msgstr "Échec"
msgid "GeoNodes|Full"
-msgstr ""
+msgstr "Complet"
msgid "GeoNodes|GitLab version does not match the primary node version"
-msgstr ""
+msgstr "La version de GitLab ne correspond pas à la version du nœud principal"
msgid "GeoNodes|GitLab version:"
-msgstr ""
+msgstr "Version de GitLab :"
msgid "GeoNodes|Health status:"
-msgstr ""
+msgstr "État :"
msgid "GeoNodes|Last event ID processed by cursor:"
-msgstr ""
+msgstr "Dernier ID d’événement traité par le curseur :"
msgid "GeoNodes|Last event ID seen from primary:"
-msgstr ""
+msgstr "Dernier événement vu du nœud primaire :"
msgid "GeoNodes|Loading nodes"
-msgstr ""
+msgstr "Chargement des nœuds"
msgid "GeoNodes|Local Attachments:"
-msgstr ""
+msgstr "Pièces jointes locales :"
msgid "GeoNodes|Local LFS objects:"
-msgstr ""
+msgstr "Objets LFS locaux :"
msgid "GeoNodes|Local job artifacts:"
-msgstr ""
+msgstr "Artefacts de tâches locaux :"
msgid "GeoNodes|New node"
-msgstr ""
+msgstr "Nouveau nœud"
msgid "GeoNodes|Out of sync"
-msgstr ""
+msgstr "Désynchronisé"
msgid "GeoNodes|Replication slot WAL:"
-msgstr ""
+msgstr "Emplacement de réplication WAL :"
msgid "GeoNodes|Replication slots:"
-msgstr ""
+msgstr "Emplacements de réplication :"
msgid "GeoNodes|Repositories:"
-msgstr ""
+msgstr "Dépôts :"
msgid "GeoNodes|Selective"
-msgstr ""
+msgstr "Sélectif"
msgid "GeoNodes|Storage config:"
-msgstr ""
+msgstr "Configuration de stockage :"
msgid "GeoNodes|Sync settings:"
-msgstr ""
+msgstr "Paramètres de synchronisation :"
msgid "GeoNodes|Synced"
-msgstr ""
+msgstr "Synchronisé"
msgid "GeoNodes|Unused slots"
-msgstr ""
+msgstr "Emplacements non utilisés"
msgid "GeoNodes|Used slots"
-msgstr ""
+msgstr "Emplacements utilisés"
msgid "GeoNodes|Wikis:"
-msgstr ""
+msgstr "Wikis :"
msgid "GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS."
-msgstr ""
+msgstr "Vous avez configuré des nœuds Geo en utilisant une connexion HTTP non sécurisée. Nous recommandons l’utilisation de HTTPS."
msgid "Geo|All projects"
-msgstr ""
+msgstr "Tous les projets"
msgid "Geo|File sync capacity"
msgstr "Capacité de synchronisation de fichier"
msgid "Geo|Groups to synchronize"
-msgstr ""
+msgstr "Groupes à synchroniser"
msgid "Geo|Projects in certain groups"
-msgstr ""
+msgstr "Projets dans certains groupes"
msgid "Geo|Projects in certain storage shards"
-msgstr ""
+msgstr "Projets dans certains fragments de stockage"
msgid "Geo|Repository sync capacity"
msgstr "Capacité de synchronisation du dépôt"
@@ -1621,22 +1800,22 @@ msgid "Geo|Select groups to replicate."
msgstr "Sélectionner les groupes à répliquer."
msgid "Geo|Shards to synchronize"
-msgstr ""
+msgstr "Fragments à synchroniser"
msgid "Git revision"
-msgstr ""
+msgstr "Révision de Git"
msgid "Git storage health information has been reset"
msgstr "Les informations de santé du stockage Git ont été réinitialisées"
msgid "Git version"
-msgstr ""
+msgstr "Version de Git"
msgid "GitLab Runner section"
msgstr "Section de l'Exécuteur GitLab"
msgid "Gitaly Servers"
-msgstr ""
+msgstr "Serveurs Gitaly"
msgid "Go to your fork"
msgstr "Aller à votre fourche"
@@ -1648,7 +1827,25 @@ msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab ad
msgstr "L’authentification Google n’est pas %{link_to_documentation}. Demandez à votre administrateur GitLab si vous souhaitez utiliser ce service."
msgid "Got it!"
-msgstr ""
+msgstr "Compris !"
+
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr "Les épopées vous permettent de gérer votre portefeuille de projets plus efficacement et avec moins d’effort"
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr "À partir de %{dateWord}"
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr "Chargement de la feuille de route"
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr "Une erreur s’est produite lors de la récupération des épopées"
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr "Pour afficher la feuille de route, ajoutez une date de début ou de fin planifiée à l'une de vos épopées dans ce groupe ou ses sous-groupes. Seules les épopées des 3 derniers mois et des 3 prochains mois sont affichées &ndash; de %{startDate} à %{endDate}."
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr "Jusqu’au %{dateWord}"
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr "Empêcher le partage d'un projet de %{group} avec d'autres groupes"
@@ -1687,7 +1884,7 @@ msgid "GroupsEmptyState|You can manage your group member’s permissions and acc
msgstr "Vous pouvez gérer les autorisations des membres de votre groupe et accéder à chacun de ses projets."
msgid "GroupsTree|Are you sure you want to leave the \"${group.fullName}\" group?"
-msgstr ""
+msgstr "Êtes-vous sûr•e de vouloir quitter le groupe \"${group.fullName}\" ?"
msgid "GroupsTree|Create a project in this group."
msgstr "Créez un projet dans ce groupe."
@@ -1739,8 +1936,8 @@ msgstr "En mauvaise santé"
msgid "Hide value"
msgid_plural "Hide values"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Masquer la valeur"
+msgstr[1] "Masquer les valeurs"
msgid "History"
msgstr "Historique"
@@ -1748,6 +1945,9 @@ msgstr "Historique"
msgid "Housekeeping successfully started"
msgstr "Maintenance démarrée avec succès"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr "Si vous avez déjà des fichiers, vous pouvez les pousser à l’aide de la %{link_to_cli} ci-dessous."
+
msgid "Import repository"
msgstr "Importer un dépôt"
@@ -1760,6 +1960,9 @@ msgstr "Améliorer la gestion des tickets avec les poids de ticket et GitLab Ent
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr "Améliorer la recherche avec la Recherche Globale Avancée et GitLab Enterprise Edition."
+msgid "Install Runner on Kubernetes"
+msgstr "Installez un Exécuteur sur Kubernetes"
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "Installez un Exécuteur compatible avec l'intégration continue de GitLab"
@@ -1769,10 +1972,10 @@ msgstr[0] "Instance"
msgstr[1] "Instances"
msgid "Instance does not support multiple Kubernetes clusters"
-msgstr ""
+msgstr "L’instance ne prend pas en charge plusieurs clusters Kubernetes"
msgid "Interested parties can even contribute by pushing commits if they want to."
-msgstr ""
+msgstr "Les parties intéressées peuvent même contribuer en poussant des commits si elles le souhaitent."
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
msgstr "Interne - Le groupe ainsi que tous les projets internes sont accessibles pour n’importe quel·le utilisa·teur·trice connecté·e."
@@ -1802,7 +2005,7 @@ msgid "Issues"
msgstr "Tickets"
msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
-msgstr ""
+msgstr "Les tickets peuvent être des bugs, des tâches ou des idées à discuter. De plus, les tickets sont consultables et filtrables."
msgid "Jan"
msgstr "Janv."
@@ -1810,6 +2013,9 @@ msgstr "Janv."
msgid "January"
msgstr "Janvier"
+msgid "Jobs"
+msgstr "Tâches"
+
msgid "Jul"
msgstr "Juill."
@@ -1823,25 +2029,28 @@ msgid "June"
msgstr "Juin"
msgid "Kubernetes"
-msgstr ""
+msgstr "Kubernetes"
msgid "Kubernetes Cluster"
-msgstr ""
+msgstr "Cluster Kubernetes"
msgid "Kubernetes cluster creation time exceeds timeout; %{timeout}"
-msgstr ""
+msgstr "Le temps de création du cluster Kubernetes dépasse le délai d’expiration ; %{timeout}"
msgid "Kubernetes cluster integration was not removed."
-msgstr ""
+msgstr "L’intégration du cluster Kubernetes n’a pas été supprimée."
msgid "Kubernetes cluster integration was successfully removed."
-msgstr ""
+msgstr "L’intégration du cluster Kubernetes a été supprimée avec succès."
msgid "Kubernetes cluster was successfully updated."
-msgstr ""
+msgstr "Le cluster Kubernetes a été mis à jour avec succès."
+
+msgid "Kubernetes configured"
+msgstr "Kubernetes configuré"
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
-msgstr ""
+msgstr "L’intégration du service Kubernetes est obsolète. %{deprecated_message_content} vos clusters Kubernetes en utilisant la nouvelle page <a href=\"%{url}\"/>Clusters Kubernetes</a>"
msgid "LFSStatus|Disabled"
msgstr "Désactivé"
@@ -1853,7 +2062,7 @@ msgid "Labels"
msgstr "Labels"
msgid "Labels can be applied to issues and merge requests to categorize them."
-msgstr ""
+msgstr "Les labels peuvent être appliqués aux tickets et aux demandes de fusion pour les classer."
msgid "Last %d day"
msgid_plural "Last %d days"
@@ -1864,7 +2073,7 @@ msgid "Last Pipeline"
msgstr "Dernier pipeline"
msgid "Last commit"
-msgstr "Dernière validation"
+msgstr "Dernier commit"
msgid "Last edited %{date}"
msgstr "Dernière modification le %{date}"
@@ -1885,7 +2094,13 @@ msgid "LastPushEvent|at"
msgstr "à"
msgid "Learn more"
-msgstr ""
+msgstr "En savoir plus"
+
+msgid "Learn more about Kubernetes"
+msgstr "En savoir plus sur Kubernetes"
+
+msgid "Learn more about protected branches"
+msgstr "En savoir plus sur les branches protégées"
msgid "Learn more in the"
msgstr "En apprendre plus dans le"
@@ -1905,17 +2120,23 @@ msgstr "Quitter le projet"
msgid "License"
msgstr "Licence"
+msgid "List"
+msgstr "Liste"
+
msgid "Loading the GitLab IDE..."
-msgstr ""
+msgstr "Chargement de l’IDE GitLab…"
msgid "Lock"
msgstr "Verrouiller"
msgid "Lock %{issuableDisplayName}"
-msgstr ""
+msgstr "Verrouiller %{issuableDisplayName}"
+
+msgid "Lock not found"
+msgstr "Verrou non trouvé"
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
-msgstr ""
+msgstr "Verrouiller ce•tte %{issuableDisplayName} ? Seul•e•s les <strong>membres du projet</strong> seront en mesure de commenter."
msgid "Locked"
msgstr "Verrouillé"
@@ -1923,14 +2144,17 @@ msgstr "Verrouillé"
msgid "Locked Files"
msgstr "Fichiers verrouillés"
+msgid "Locks give the ability to lock specific file or folder."
+msgstr "Les verrous donnent la possibilité de verrouiller un fichier ou un dossier spécifique."
+
msgid "Login"
msgstr "Se connecter"
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 "Rendez votre équipe plus productive quel que soit son emplacement. GitLab Geo crée des miroirs en lecture seule de votre instance GitLab afin que vous puissiez réduire le temps nécessaire pour cloner et récupérer de gros dépôts."
msgid "Manage labels"
-msgstr ""
+msgstr "Gérer les labels"
msgid "Mar"
msgstr "Mars"
@@ -1939,7 +2163,7 @@ msgid "March"
msgstr "Mars"
msgid "Mark done"
-msgstr ""
+msgstr "Marquer comme fait"
msgid "Maximum git storage failures"
msgstr "Nombre maximum d’échecs du stockage git"
@@ -1953,9 +2177,6 @@ msgstr "Médian"
msgid "Members"
msgstr "Membres"
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr "Demandes de fusion"
@@ -1966,49 +2187,61 @@ msgid "Merge request"
msgstr "Demande de fusion"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
-msgstr ""
+msgstr "Les demandes de fusion permettent de proposer les modifications que vous avez apportées à un projet et de discuter de ces modifications avec les autres"
+
+msgid "MergeRequest|Approved"
+msgstr "Approuvée"
msgid "Merged"
-msgstr ""
+msgstr "Fusionnée"
msgid "Messages"
msgstr "Messages"
msgid "Milestone"
-msgstr ""
+msgstr "Jalon"
msgid "Milestones|Delete milestone"
-msgstr ""
+msgstr "Supprimer le jalon"
msgid "Milestones|Delete milestone %{milestoneTitle}?"
-msgstr ""
+msgstr "Supprimer le jalon %{milestoneTitle} ?"
msgid "Milestones|Failed to delete milestone %{milestoneTitle}"
-msgstr ""
+msgstr "Impossible de supprimer le jalon %{milestoneTitle}"
msgid "Milestones|Milestone %{milestoneTitle} was not found"
-msgstr ""
+msgstr "Le jalon %{milestoneTitle} est introuvable"
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "ajouter une clé SSH"
+msgid "Modal|Cancel"
+msgstr "Annuler"
+
+msgid "Modal|Close"
+msgstr "Fermer"
+
msgid "Monitoring"
msgstr "Surveillance"
+msgid "More information"
+msgstr "Plus d’informations"
+
msgid "More information is available|here"
msgstr "ici"
msgid "Move"
-msgstr ""
+msgstr "Déplacer"
msgid "Move issue"
-msgstr ""
+msgstr "Déplacer le ticket"
msgid "Multiple issue boards"
msgstr "Multiple tableaux de tickets"
msgid "Name new label"
-msgstr ""
+msgstr "Nommez le nouveau label"
msgid "New Issue"
msgid_plural "New Issues"
@@ -2016,10 +2249,10 @@ msgstr[0] "Nouveau ticket"
msgstr[1] "Nouveaux tickets"
msgid "New Kubernetes Cluster"
-msgstr ""
+msgstr "Nouveau cluster Kubernetes"
msgid "New Kubernetes cluster"
-msgstr ""
+msgstr "Nouveau cluster Kubernetes"
msgid "New Pipeline Schedule"
msgstr "Nouveau pipeline programmé"
@@ -2046,7 +2279,7 @@ msgid "New issue"
msgstr "Nouveau ticket"
msgid "New label"
-msgstr ""
+msgstr "Nouveau label"
msgid "New merge request"
msgstr "Nouvelle demande de fusion"
@@ -2067,22 +2300,22 @@ msgid "New tag"
msgstr "Nouveau tag"
msgid "No assignee"
-msgstr ""
+msgstr "Aucune personne assignée"
msgid "No changes"
-msgstr ""
+msgstr "Aucun changement"
msgid "No connection could be made to a Gitaly Server, please check your logs!"
-msgstr ""
+msgstr "Aucune connexion n’a pu être établie avec un serveur Gitaly, veuillez vérifier vos logs !"
msgid "No due date"
-msgstr ""
+msgstr "Aucune date d’échéance"
msgid "No estimate or time spent"
-msgstr ""
+msgstr "Aucune estimation ou temps passé"
msgid "No file chosen"
-msgstr ""
+msgstr "Aucun fichier sélectionné"
msgid "No repository"
msgstr "Pas de dépôt"
@@ -2090,24 +2323,24 @@ msgstr "Pas de dépôt"
msgid "No schedules"
msgstr "Aucun programme"
-msgid "No time spent"
-msgstr "Pas de temps passé"
-
msgid "None"
msgstr "Aucun·e"
msgid "Not allowed to merge"
-msgstr ""
+msgstr "Non autorisé•e à fusionner"
msgid "Not available"
msgstr "Indisponible"
msgid "Not confidential"
-msgstr ""
+msgstr "Pas confidentiel•le"
msgid "Not enough data"
msgstr "Données insuffisantes"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr "Notez que la branche principale est automatiquement protégée. %{link_to_protected_branches}"
+
msgid "Notification events"
msgstr "Événement de notifications"
@@ -2166,10 +2399,10 @@ msgid "Notifications"
msgstr "Notifications"
msgid "Notifications off"
-msgstr ""
+msgstr "Notifications désactivées"
msgid "Notifications on"
-msgstr ""
+msgstr "Notifications activées"
msgid "Nov"
msgstr "Nov."
@@ -2181,7 +2414,7 @@ msgid "Number of access attempts"
msgstr "Nombre de tentatives d'accès"
msgid "OK"
-msgstr ""
+msgstr "OK"
msgid "Oct"
msgstr "Oct."
@@ -2196,7 +2429,7 @@ msgid "Only project members can comment."
msgstr "Seuls les membres du projet peuvent commenter."
msgid "Open"
-msgstr ""
+msgstr "Ouvrir"
msgid "Opened"
msgstr "Ouvert"
@@ -2210,6 +2443,9 @@ msgstr "Ouvrir dans une nouvelle fenêtre"
msgid "Options"
msgstr "Paramètres"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr "Sinon, il est recommandé de commencer avec l’une des options ci-dessous."
+
msgid "Overview"
msgstr "Vue d'ensemble"
@@ -2310,10 +2546,28 @@ msgid "Pipelines for last year"
msgstr "Pipelines de l’année dernière"
msgid "Pipelines|Build with confidence"
-msgstr ""
+msgstr "Construire en toute confiance"
msgid "Pipelines|Get started with Pipelines"
-msgstr ""
+msgstr "Premiers pas avec les Pipelines"
+
+msgid "Pipeline|Retry pipeline"
+msgstr "Relancer le pipeline"
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr "Relancer le pipeline #%{pipelineId} ?"
+
+msgid "Pipeline|Stop pipeline"
+msgstr "Arrêter le pipeline"
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr "Arrêter le pipeline #%{pipelineId} ?"
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr "Vous êtes sur le point de relancer le pipeline %{pipelineId}."
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr "Vous êtes sur le point d’arrêter le pipeline %{pipelineId}."
msgid "Pipeline|all"
msgstr "Tous"
@@ -2328,10 +2582,10 @@ msgid "Pipeline|with stages"
msgstr "avec les étapes"
msgid "Play"
-msgstr ""
+msgstr "Lancer"
msgid "Please <a href=%{link_to_billing} target=\"_blank\" rel=\"noopener noreferrer\">enable billing for one of your projects to be able to create a Kubernetes cluster</a>, then try again."
-msgstr ""
+msgstr "Merci d’<a href=%{link_to_billing} target=\"_blank\" rel=\"noopener noreferrer\">activer la facturation pour un de vos projets afin d’être en mesure de créer un cluster Kubernetes</a>, puis essayez à nouveau."
msgid "Please solve the reCAPTCHA"
msgstr "Veuillez résoudre le reCAPTCHA"
@@ -2340,7 +2594,7 @@ msgid "Preferences"
msgstr "Préférences"
msgid "Primary"
-msgstr ""
+msgstr "Principal"
msgid "Private - Project access must be granted explicitly to each user."
msgstr "Privé - L’accès au projet doit être autorisé explicitement pour chaque utilisa·teur·trice."
@@ -2348,6 +2602,9 @@ msgstr "Privé - L’accès au projet doit être autorisé explicitement pour ch
msgid "Private - The group and its projects can only be viewed by members."
msgstr "Privé - Le groupe ainsi que ses projets ne sont accessibles qu’à ses membres."
+msgid "Private projects can be created in your personal namespace with:"
+msgstr "Des projets privés peuvent être créés dans votre espace de noms personnel avec :"
+
msgid "Profile"
msgstr "Profil"
@@ -2388,7 +2645,7 @@ msgid "Profiles|your account"
msgstr "votre compte"
msgid "Programming languages used in this repository"
-msgstr ""
+msgstr "Langages de programmation utilisés dans ce dépôt"
msgid "Project '%{project_name}' is in the process of being deleted."
msgstr "Le projet “%{project_name}†est en train d’être supprimé."
@@ -2406,13 +2663,13 @@ msgid "Project access must be granted explicitly to each user."
msgstr "L’accès au projet doit être explicitement accordé à chaque utilisateur."
msgid "Project avatar"
-msgstr ""
+msgstr "Avatar du projet"
msgid "Project avatar in repository: %{link}"
-msgstr ""
+msgstr "Avatar du project dans le dépôt : %{link}"
msgid "Project cache successfully reset."
-msgstr ""
+msgstr "Le cache du projet a bien été réinitialisé."
msgid "Project details"
msgstr "Détails du projet"
@@ -2433,19 +2690,19 @@ msgid "ProjectActivityRSS|Subscribe"
msgstr "S’abonner"
msgid "ProjectCreationLevel|Allowed to create projects"
-msgstr ""
+msgstr "Autorisé•e à créer des projets"
msgid "ProjectCreationLevel|Default project creation protection"
-msgstr ""
+msgstr "Protection de création de projet par défaut"
msgid "ProjectCreationLevel|Developers + Masters"
-msgstr ""
+msgstr "Développeur•euse•s + Expert•e•s"
msgid "ProjectCreationLevel|Masters"
-msgstr ""
+msgstr "Expert•e•s"
msgid "ProjectCreationLevel|No one"
-msgstr ""
+msgstr "Personne"
msgid "ProjectFeature|Disabled"
msgstr "Désactivé"
@@ -2472,7 +2729,7 @@ msgid "ProjectSettings|Contact an admin to change this setting."
msgstr "Contactez un administrateur pour modifier ce paramètre."
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
-msgstr "Seules les validations signées peuvent être poussées sur ce dépôt."
+msgstr "Seules les commits signés peuvent être poussés sur ce dépôt."
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr "Ce paramètre est appliqué au niveau du serveur et peut être modifié par un administrateur."
@@ -2484,7 +2741,7 @@ msgid "ProjectSettings|This setting will be applied to all projects unless overr
msgstr "Ce paramètre s’appliquera à tous les projets à moins qu’un•e administrat•eur•rice ne le modifie."
msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
-msgstr "Les utilisateurs peuvent uniquement pousser sur ce dépôt des validations qui ont été validées avec une de leurs adresses courriels vérifiées."
+msgstr "Les utilisateurs peuvent uniquement pousser sur ce dépôt des commits qui ont été validés avec une de leurs adresses courriels vérifiées."
msgid "Projects"
msgstr "Projets"
@@ -2510,12 +2767,30 @@ msgstr "Désolé, aucun projet ne correspond à votre recherche"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Cette fonctionnalité requiert le support du localStorage par votre navigateur"
+msgid "PrometheusService|Active"
+msgstr "Actif"
+
+msgid "PrometheusService|Auto configuration"
+msgstr "Configuration automatique"
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr "Déployer et configurer automatiquement Prometheus sur vos clusters pour surveiller les environnements de vos projets"
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr "Par défaut, Prometheus écoute sur 'http://localhost:9090'. Il n’est pas recommandé de changer l’adresse et le port par défaut car cela pourrait affecter ou entrer en conflit avec d'autres services fonctionnant sur le serveur GitLab."
msgid "PrometheusService|Finding and configuring metrics..."
msgstr "Recherche et configuration des métriques en cours…"
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr "Installer Prometheus sur les clusters"
+
+msgid "PrometheusService|Manage clusters"
+msgstr "Gérer les clusters"
+
+msgid "PrometheusService|Manual configuration"
+msgstr "Configuration manuelle"
+
msgid "PrometheusService|Metrics"
msgstr "Métriques"
@@ -2537,14 +2812,23 @@ msgstr "Aucune métrique n’est surveillée. Pour démarrer la surveillance, dÃ
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr "URL de base de l’API Prometheus, comme http://prometheus.example.com/"
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr "Prometheus est géré automatiquement sur vos clusters"
+
msgid "PrometheusService|Time-series monitoring service"
-msgstr ""
+msgstr "Service de surveillance de séries temporelles"
+
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr "Pour activer la configuration manuelle, désinstallez Prometheus de vos clusters"
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr "Pour activer l’installation de Prometheus sur vos clusters, désactivez la configuration manuelle ci-dessous"
msgid "PrometheusService|View environments"
msgstr "Afficher les environnements"
msgid "Protip:"
-msgstr ""
+msgstr "Astuce :"
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr "Public - Le groupe ainsi que n’importe quel projet public est accessible sans authentification."
@@ -2558,11 +2842,17 @@ msgstr "Règles de poussée"
msgid "Push events"
msgstr "Évènements de poussée"
+msgid "Push project from command line"
+msgstr "Pousser le projet en ligne de commande"
+
+msgid "Push to create a project"
+msgstr "Pousser pour créer un projet"
+
msgid "PushRule|Committer restriction"
msgstr "Restriction du validateur"
msgid "Quick actions can be used in the issues description and comment boxes."
-msgstr ""
+msgstr "Les actions rapides peuvent être utilisées dans la description des tickets et dans les zones de commentaire."
msgid "Read more"
msgstr "Lire plus"
@@ -2577,16 +2867,16 @@ msgid "RefSwitcher|Tags"
msgstr "Tags"
msgid "Reference:"
-msgstr ""
+msgstr "Référence :"
msgid "Register / Sign In"
-msgstr ""
+msgstr "Inscription / Connexion"
msgid "Registry"
msgstr "Registre"
msgid "Related Commits"
-msgstr "Validations liées"
+msgstr "Commits liés"
msgid "Related Deployed Jobs"
msgstr "Tâches de déploiement liées"
@@ -2607,20 +2897,23 @@ msgid "Remind later"
msgstr "Me le rappeler ultérieurement"
msgid "Remove"
-msgstr ""
+msgstr "Supprimer"
msgid "Remove avatar"
-msgstr ""
+msgstr "Supprimer l’avatar"
msgid "Remove project"
msgstr "Supprimer le projet"
msgid "Repair authentication"
-msgstr ""
+msgstr "Réparer l’authentification"
msgid "Repository"
msgstr "Dépôt"
+msgid "Repository has no locks."
+msgstr "Le dépôt n’a pas de verrous."
+
msgid "Request Access"
msgstr "Demander l'accès"
@@ -2633,17 +2926,23 @@ msgstr "Réinitialiser le jeton d’accès au bilan de santé"
msgid "Reset runners registration token"
msgstr "Réinitialiser le jeton d’inscription des exécuteurs"
+msgid "Resolve discussion"
+msgstr "Résoudre la discussion"
+
msgid "Reveal value"
msgid_plural "Reveal values"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Révéler la valeur"
+msgstr[1] "Révéler les valeurs"
msgid "Revert this commit"
-msgstr "Défaire cette validation"
+msgstr "Défaire ce commit"
msgid "Revert this merge request"
msgstr "Défaire cette demande de fusion"
+msgid "Roadmap"
+msgstr "Feuille de route"
+
msgid "SSH Keys"
msgstr "Clés SSH"
@@ -2654,7 +2953,7 @@ msgid "Save pipeline schedule"
msgstr "Sauvegarder le pipeline programmé"
msgid "Save variables"
-msgstr ""
+msgstr "Enregistrer les variables"
msgid "Schedule a new pipeline"
msgstr "Programmer un nouveau pipeline"
@@ -2672,13 +2971,13 @@ msgid "Search branches and tags"
msgstr "Rechercher dans les branches et les étiquettes"
msgid "Search milestones"
-msgstr ""
+msgstr "Recherche de jalons"
msgid "Search project"
-msgstr ""
+msgstr "Recherche de projets"
msgid "Search users"
-msgstr ""
+msgstr "Recherche d’utilisateur•rice•s"
msgid "Seconds before reseting failure information"
msgstr "Nombre de secondes avant de réinitialiser les informations d’échec"
@@ -2687,7 +2986,10 @@ msgid "Seconds to wait for a storage access attempt"
msgstr "Nombre de secondes d’attente pour un essai d'accès au stockage"
msgid "Secret variables"
-msgstr ""
+msgstr "Variables secrètes"
+
+msgid "Security report"
+msgstr "Rapport de sécurité"
msgid "Select Archive Format"
msgstr "Sélectionnez le format de l'archive"
@@ -2695,17 +2997,23 @@ msgstr "Sélectionnez le format de l'archive"
msgid "Select a timezone"
msgstr "Sélectionnez un fuseau horaire"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr "Sélectionnez un cluster Kubernetes existant ou créez-en un nouveau"
+
msgid "Select assignee"
-msgstr ""
+msgstr "Sélectionner une personne assignée"
msgid "Select branch/tag"
-msgstr ""
+msgstr "Sélectionnez une branche / un tag"
msgid "Select target branch"
msgstr "Sélectionnez une branche cible"
msgid "Selective synchronization"
-msgstr ""
+msgstr "Synchronisation sélective"
+
+msgid "Send email"
+msgstr "Envoyer un courriel"
msgid "Sep"
msgstr "Sept."
@@ -2714,37 +3022,43 @@ msgid "September"
msgstr "Septembre"
msgid "Server version"
-msgstr ""
+msgstr "Version du serveur"
msgid "Service Templates"
msgstr "Modèles de service"
+msgid "Service URL"
+msgstr "URL du service"
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Définissez un mot de passe pour votre compte pour pouvoir tirer ou pousser par %{protocol}."
msgid "Set up CI/CD"
-msgstr ""
+msgstr "Configurer CI/CD"
msgid "Set up Koding"
msgstr "Mettre en place Koding"
-msgid "Set up auto deploy"
-msgstr "Mettre en place l’auto-déploiement"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "définir un mot de passe"
msgid "Settings"
msgstr "Paramètres"
+msgid "Setup a specific Runner automatically"
+msgstr "Configurer un Exécuteur spécifique automatiquement"
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
-msgstr ""
+msgstr "En réinitialisant les minutes du pipeline pour cet espace de noms, les minutes actuellement utilisées seront remises à zéro."
msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
-msgstr ""
+msgstr "Réinitialiser les minutes du pipeline"
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
-msgstr ""
+msgstr "Réinitialiser les minutes de pipeline utilisées"
+
+msgid "Show command"
+msgstr "Afficher la commande"
msgid "Show parent pages"
msgstr "Afficher les pages parentes"
@@ -2773,19 +3087,25 @@ msgid "Snippets"
msgstr "Extraits de code"
msgid "Something went wrong on our end"
-msgstr ""
+msgstr "Une erreur est survenue de notre côté"
msgid "Something went wrong on our end."
msgstr "Une erreur est survenue de notre côté."
msgid "Something went wrong trying to change the confidentiality of this issue"
-msgstr ""
+msgstr "Quelque chose s’est mal passé en essayant de changer la confidentialité de ce ticket"
msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr "Quelque chose ne s‘est pas bien passé en essayant de changer l’état de verrouillage de cette ${this.issuableDisplayName}"
msgid "Something went wrong when toggling the button"
-msgstr ""
+msgstr "Une erreur s’est produite lors du basculement du bouton"
+
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr "Une erreur s’est produite lors de la fermeture du/de la %{issuable}. Veuillez réessayer plus tard"
+
+msgid "Something went wrong while fetching SAST."
+msgstr "Une erreur s’est produite lors de la récupération de la SAST."
msgid "Something went wrong while fetching the projects."
msgstr "Une erreur s'est produite lors de la récupération des projets."
@@ -2793,9 +3113,15 @@ msgstr "Une erreur s'est produite lors de la récupération des projets."
msgid "Something went wrong while fetching the registry list."
msgstr "Une erreur s'est produite lors de la récupération de la liste du registre."
-msgid "Something went wrong. Please try again."
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr "Une erreur s’est produite lors de la réouverture du / de la %{issuable}. Veuillez réessayer plus tard"
+
+msgid "Something went wrong while resolving this discussion. Please try again."
msgstr ""
+msgid "Something went wrong. Please try again."
+msgstr "Quelque chose s’est mal passé. Veuillez réessayer."
+
msgid "Sort by"
msgstr "Trier par"
@@ -2898,6 +3224,9 @@ msgstr "Poids"
msgid "Source"
msgstr "Source"
+msgid "Source (branch or tag)"
+msgstr "Source (branche ou tag)"
+
msgid "Source code"
msgstr "Code source"
@@ -2926,7 +3255,7 @@ msgid "Stopped"
msgstr "Arrêté"
msgid "Storage"
-msgstr ""
+msgstr "Stockage"
msgid "Subgroups"
msgstr "Sous-groupes"
@@ -2937,22 +3266,22 @@ msgstr "Changer de branche / tag"
msgid "System Hooks"
msgstr "Crochets système"
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "Étiquette"
-msgstr[1] "Tags"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] "Tag (%{tag_count})"
+msgstr[1] "Tags (%{tag_count})"
msgid "Tags"
msgstr "Tags"
msgid "TagsPage|Browse commits"
-msgstr "Parcourir les validations"
+msgstr "Parcourir les commits"
msgid "TagsPage|Browse files"
msgstr "Parcourir les fichiers"
msgid "TagsPage|Can't find HEAD commit for this tag"
-msgstr "Impossible de trouver la validation HEAD pour ce tag"
+msgstr "Impossible de trouver le commit HEAD pour ce tag"
msgid "TagsPage|Cancel"
msgstr "Annuler"
@@ -2970,7 +3299,7 @@ msgid "TagsPage|Edit release notes"
msgstr "Modifier les notes de version"
msgid "TagsPage|Existing branch name, tag, or commit SHA"
-msgstr "Nom de branche, tag, ou SHA de validation existant"
+msgstr "Nom de branche, tag, ou SHA de commit existant"
msgid "TagsPage|Filter by tag name"
msgstr "Filtrer par nom de tag"
@@ -3027,13 +3356,13 @@ msgid "The Advanced Global Search in GitLab is a powerful search service that sa
msgstr "La Recherche Globale Avancée de Gitlab est un outils puissant qui vous fait gagner du temps. Au lieu de créer du code similaire et perdre du temps, vous pouvez maintenant chercher dans le code d'autres équipes pour vous aider sur votre projet."
msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
-msgstr ""
+msgstr "Le suivi des tickets est l’endroit où ajouter des éléments à améliorer ou à résoudre dans un projet"
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 "Le suivi des tickets est l’endroit où ajouter des éléments à améliorer ou à résoudre dans un projet. Vous pouvez vous inscrire ou vous connecter pour créer des tickets pour ce projet."
msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
-msgstr "L’étape de développement montre le temps entre la première validation et la création de la demande de fusion. Les données seront automatiquement ajoutées ici une fois que vous aurez créé votre première demande de fusion."
+msgstr "L’étape de développement montre le temps entre le premier commit et la création de la demande de fusion. Les données seront automatiquement ajoutées ici une fois que vous aurez créé votre première demande de fusion."
msgid "The collection of events added to the data gathered for that stage."
msgstr "L’ensemble d’évènements ajoutés aux données récupérées pour cette étape."
@@ -3045,7 +3374,7 @@ msgid "The issue stage shows the time it takes from creating an issue to assigni
msgstr "L'étape des tickets montre le temps nécessaire entre la création d'un ticket et son assignation à un jalon, ou son ajout à une liste d'un tableau de tickets. Commencez par créer des tickets pour voir des données pour cette étape."
msgid "The maximum file size allowed is 200KB."
-msgstr ""
+msgstr "La taille de fichier maximale autorisée est de 200 Ko."
msgid "The number of attempts GitLab will make to access a storage."
msgstr "Le nombre de tentatives que GitLab va effectuer pour accéder au stockage."
@@ -3057,7 +3386,7 @@ msgid "The phase of the development lifecycle."
msgstr "Les étapes du cycle de développement."
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 "L’étape de planification montre le temps entre l’étape précédente et l’envoi de votre première validation. Ce temps sera automatiquement ajouté quand vous pousserez votre première validation."
+msgstr "L’étape de planification montre le temps entre l’étape précédente et l’envoi de votre premier commit. Ce temps sera automatiquement ajouté quand vous pousserez votre premier commit."
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."
@@ -3071,9 +3400,15 @@ msgstr "Votre projet peut être accédé sans aucune authentification."
msgid "The repository for this project does not exist."
msgstr "Le dépôt pour ce projet n'existe pas."
+msgid "The repository for this project is empty"
+msgstr "Le dépôt de ce projet est vide"
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "L’étape d’évaluation montre le temps entre la création de la demande de fusion et la fusion effective de celle-ci. Ces données seront automatiquement ajoutées après que vous ayez fusionné votre première demande de fusion."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr "La feuille de route montre la progression de vos épopées dans le temps"
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "L’étape de pré-production indique le temps entre la fusion de la DF et le déploiement du code dans l’environnent de production. Les données seront automatiquement ajoutées une fois que vous déploierez en production pour la première fois."
@@ -3087,7 +3422,7 @@ msgid "The time in seconds GitLab will try to access storage. After this time a
msgstr "Temps en secondes pendant lequel GitLab essaiera d’accéder au stockage. Après ce délai, une erreur d’expiration d’attente sera déclenchée."
msgid "The time in seconds between storage checks. When a previous check did complete yet, GitLab will skip a check."
-msgstr ""
+msgstr "Le temps en secondes entre les vérifications de stockage. GitLab ne débute pas de nouvelle vérification si une vérification est déjà en cours."
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."
@@ -3096,37 +3431,37 @@ msgid "The value lying at the midpoint of a series of observed values. E.g., bet
msgstr "La valeur située au point médian d’une série de valeur observée. C.à.d., entre 3, 5, 9, le médian est 5. Entre 3, 5, 7, 8, le médian est (5+7)/2 = 6."
msgid "There are no issues to show"
-msgstr ""
+msgstr "Il n’y a aucun ticket à afficher"
msgid "There are no merge requests to show"
-msgstr ""
+msgstr "Il n’y a aucune demande de fusion à afficher"
msgid "There are problems accessing Git storage: "
msgstr "Il y a des difficultés à accéder aux données Git : "
msgid "There was an error loading users activity calendar."
-msgstr ""
+msgstr "Une erreur s’est produite lors du chargement du calendrier d’activité des utilisateurs."
msgid "There was an error saving your notification settings."
-msgstr ""
+msgstr "Une erreur s’est produite lors de l’enregistrement de vos paramètres de notification."
msgid "There was an error subscribing to this label."
-msgstr ""
+msgstr "Une erreur s’est produite lors de l’abonnement à ce label."
msgid "There was an error when reseting email token."
-msgstr ""
+msgstr "Une erreur s’est produite lors de la réinitialisation du jeton de courriel."
msgid "There was an error when subscribing to this label."
-msgstr ""
+msgstr "Une erreur s’est produite lors de l’abonnement à ce label."
msgid "There was an error when unsubscribing from this label."
-msgstr ""
+msgstr "Une erreur s’est produite lors de la désinscription à ce label."
msgid "This board\\'s scope is reduced"
msgstr "La portée de ce tableau est limitée"
msgid "This directory"
-msgstr ""
+msgstr "Ce répertoire"
msgid "This is a confidential issue."
msgstr "Ce ticket est confidentiel."
@@ -3135,7 +3470,7 @@ 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 issue is confidential"
-msgstr ""
+msgstr "Ce ticket est confidentiel"
msgid "This issue is confidential and locked."
msgstr "Ce ticket est confidentiel et verrouillé."
@@ -3144,22 +3479,22 @@ msgid "This issue is locked."
msgstr "Ce ticket est verrouillé."
msgid "This job depends on a user to trigger its process. Often they are used to deploy code to production environments"
-msgstr ""
+msgstr "Cette tâche dépend de l’utilisateur•rice pour déclencher son processus. Elles sont souvent utilisées pour déployer du code dans des environnements de production"
msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
-msgstr ""
+msgstr "Cette tâche dépend des tâches en amont qui doivent réussir pour que celle-ci soit déclenchée"
msgid "This job has not been triggered yet"
-msgstr ""
+msgstr "Cette tâche n’a pas encore été déclenchée"
msgid "This job has not started yet"
-msgstr ""
+msgstr "Cete tâche n’a pas encore commencée"
msgid "This job is in pending state and is waiting to be picked by a runner"
-msgstr ""
+msgstr "Cette tâche est en attente et attend d’être choisie par un exécuteur"
msgid "This job requires a manual action"
-msgstr ""
+msgstr "Cette tâche nécessite une action manuelle"
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "Cela signifie que vous ne pouvez pas pousser du code tant que vous n’avez pas créé un dépôt vide, ou que vous n’avez pas importé un dépôt existant."
@@ -3167,11 +3502,14 @@ msgstr "Cela signifie que vous ne pouvez pas pousser du code tant que vous n’a
msgid "This merge request is locked."
msgstr "Cette demande de fusion est verrouillée."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr "Cette page n’est pas disponible car vous n’êtes pas autorisé à lire des informations dans plusieurs projets."
+
msgid "This project"
-msgstr ""
+msgstr "Ce projet"
msgid "This repository"
-msgstr ""
+msgstr "Ce dépôt"
msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
msgstr "Ces emails deviennent automatiquement des tickets (les commentaires étant extrait de la conversation par email) répertoriés ici."
@@ -3186,19 +3524,19 @@ msgid "Time between merge request creation and merge/close"
msgstr "Temps entre la création d'une demande de fusion et sa fusion/clôture"
msgid "Time tracking"
-msgstr ""
+msgstr "Suivi du temps"
msgid "Time until first merge request"
msgstr "Temps jusqu’à la première demande de fusion"
msgid "TimeTrackingEstimated|Est"
-msgstr ""
+msgstr "Est"
msgid "TimeTracking|Estimated:"
-msgstr ""
+msgstr "Estimé :"
msgid "TimeTracking|Spent"
-msgstr ""
+msgstr "Passé"
msgid "Timeago|%s days ago"
msgstr "il y a %s jours"
@@ -3336,29 +3674,35 @@ msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
+msgid "Tip:"
+msgstr "Astuce :"
+
msgid "Title"
msgstr "Titre"
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr "Pour afficher la feuille de route, ajoutez une date de début ou de fin planifiée à l’une de vos épopées dans ce groupe ou ses sous-groupes. Seules les épopées des 3 derniers mois et des 3 prochains mois sont affichées."
+
msgid "Todo"
-msgstr ""
+msgstr "Tâche"
msgid "Toggle sidebar"
-msgstr ""
+msgstr "Afficher/masquer la barre latérale"
msgid "ToggleButton|Toggle Status: OFF"
-msgstr ""
+msgstr "État du commutateur : Inactif"
msgid "ToggleButton|Toggle Status: ON"
-msgstr ""
+msgstr "État du commutateur : Actif"
msgid "Total Time"
msgstr "Temps total"
-msgid "Total issue time spent"
-msgstr "Temps total passé sur les tickets"
-
msgid "Total test time for all commits/merges"
-msgstr "Temps total de test pour toutes les validations/fusions"
+msgstr "Temps total de test pour tous les commits/fusions"
+
+msgid "Total: %{total}"
+msgstr "Total : %{total}"
msgid "Track activity with Contribution Analytics."
msgstr "Suivre l’activité avec Contribution Analytics."
@@ -3366,41 +3710,38 @@ msgstr "Suivre l’activité avec Contribution Analytics."
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr "Suivez les groupes de tickets qui partagent un thème, entre projets et jalons"
-msgid "Total: %{total}"
-msgstr ""
-
msgid "Track time with quick actions"
-msgstr ""
+msgstr "Suivre le temps estimé/passé avec les actions rapides"
msgid "Trigger this manual action"
-msgstr ""
+msgstr "Déclencher cette action manuelle"
msgid "Turn on Service Desk"
msgstr "Activer le Service Desk"
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
-msgstr ""
+msgstr "Impossible de réinitialiser le cache du projet."
msgid "Unknown"
-msgstr ""
+msgstr "Inconnu"
msgid "Unlock"
msgstr "Déverrouiller"
msgid "Unlock this %{issuableDisplayName}? <strong>Everyone</strong> will be able to comment."
-msgstr ""
+msgstr "Débloquez le•a %{issuableDisplayName} ? <strong>Tout le monde</strong> sera en mesure de commenter."
msgid "Unlocked"
msgstr "Déverrouillé"
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "Supprimer des favoris"
msgid "Up to date"
-msgstr ""
+msgstr "À jour"
msgid "Upgrade your plan to activate Advanced Global Search."
msgstr "Mettez à jour votre abonnement pour activer la Recherche Globale Avancée."
@@ -3424,7 +3765,7 @@ msgid "Upload file"
msgstr "Téléverser un fichier"
msgid "Upload new avatar"
-msgstr ""
+msgstr "Importer un nouvel avatar"
msgid "UploadLink|click to upload"
msgstr "Cliquez pour envoyer"
@@ -3439,13 +3780,16 @@ msgid "Use your global notification setting"
msgstr "Utiliser vos paramètres de notification globaux"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
-msgstr ""
+msgstr "Les variables sont appliquées aux environnements via l’exécuteur. Elles peuvent être protégées en les exposant uniquement à des branches ou des tags protégées. Vous pouvez utiliser des variables pour les mots de passe, les clés secrètes ou tout ce que vous voulez."
+
+msgid "View epics list"
+msgstr "Afficher la liste des épopées"
msgid "View file @ "
msgstr "Voir le fichier @ "
msgid "View labels"
-msgstr ""
+msgstr "Afficher les labels"
msgid "View open merge request"
msgstr "Afficher la demande de fusion"
@@ -3469,7 +3813,7 @@ msgid "Want to see the data? Please ask an administrator for access."
msgstr "Vous voulez voir les données ? Merci de contacter un administrateur pour en obtenir l’accès."
msgid "We could not verify that one of your projects on GCP has billing enabled. Please try again."
-msgstr ""
+msgstr "Nous n’avons pas pu vérifier que l’un de vos projets sur GCP est activé pour la facturation. Veuillez réessayer."
msgid "We don't have enough data to show this stage."
msgstr "Nous n'avons pas suffisamment de données pour afficher cette étape."
@@ -3477,6 +3821,9 @@ msgstr "Nous n'avons pas suffisamment de données pour afficher cette étape."
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Nous voulons être sûrs que c'est bien vous, merci de confirmer que vous n’êtes pas un robot."
+msgid "Web IDE"
+msgstr "Web IDE"
+
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 "Les webhooks vous permettent d’appeler une URL si, par exemple, du nouveau code est poussé ou un nouveau ticket est créé. Vous pouvez configurer les webhooks pour écouter les événements spécifiques comme des poussées de code, des tickets ou des demandes de fusion. Les webhooks de groupes s’appliqueront à tous les projets dans un groupe, ce qui vous permet de normaliser la fonctionnalité du webhook dans votre groupe entier."
@@ -3502,10 +3849,10 @@ msgid "WikiClone|Start Gollum and edit locally"
msgstr "Démarrer Gollum et modifier localement"
msgid "WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title."
-msgstr ""
+msgstr "Astuce : Vous pouvez déplacer cette page en ajoutant le chemin au début du titre."
msgid "WikiEdit|There is already a page with the same title in that path."
-msgstr ""
+msgstr "Il y a déjà une page avec le même titre pour ce chemin."
msgid "WikiEmptyPageError|You are not allowed to create wiki pages"
msgstr "Vous n’êtes pas autorisé·e à créer des pages wiki"
@@ -3597,6 +3944,9 @@ msgstr "Avec Contribution Analytics vous pouvez avoir un aperçu de l’activitÃ
msgid "Withdraw Access Request"
msgstr "Retirer la demande d'accès"
+msgid "Write a commit message..."
+msgstr "Écrire un message de commit…"
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Vous êtes sur le point de supprimer %{group_name}. Les groupes supprimés NE PEUVENT PAS être restaurés ! Êtes vous ABSOLUMENT sûr·e ?"
@@ -3609,20 +3959,23 @@ msgstr "Vous allez supprimer la relation de fourche avec le projet source %{fork
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Vous allez transférer %{project_name_with_namespace} à un nouveau propriétaire. Êtes vous ABSOLUMENT sûr·e ?"
+msgid "You can also create a project from the command line."
+msgstr "Vous pouvez également créer un projet en ligne de commande."
+
msgid "You can also star a label to make it a priority label."
-msgstr ""
+msgstr "Vous pouvez marquer un label comme important pour en faire un label prioritaire."
-msgid "You can move around the graph by using the arrow keys."
-msgstr ""
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
+msgstr "Vous pouvez facilement installer un Exécuteur sur un cluster Kubernetes. %{link_to_help_page}"
msgid "You can move around the graph by using the arrow keys."
-msgstr ""
+msgstr "Vous pouvez vous déplacer dans le graphique en utilisant les touches fléchées."
msgid "You can only add files when you are on a branch"
msgstr "Vous ne pouvez ajouter de fichier que dans une branche"
msgid "You can only edit files when you are on a branch"
-msgstr ""
+msgstr "Vous ne pouvez éditer de fichier que dans une branche"
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
msgstr "Vous ne pouvez pas écrire sur une instance GitLab Geo secondaire en lecture-seule. Veuillez utiliser le %{link_to_primary_node} à la place."
@@ -3630,12 +3983,24 @@ msgstr "Vous ne pouvez pas écrire sur une instance GitLab Geo secondaire en lec
msgid "You cannot write to this read-only GitLab instance."
msgstr "Vous ne pouvez pas écrire sur cette instance GitLab en lecture-seule."
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr "Vous ne disposez pas des autorisations appropriées pour remplacer les paramètres de synchronisation du groupe LDAP."
+
+msgid "You have no permissions"
+msgstr "Vous n’avez pas les autorisations"
+
msgid "You have reached your project limit"
msgstr "Vous avez atteint votre limite de projet"
+msgid "You must have master access to force delete a lock"
+msgstr "Vous devez avoir un accès Expert pour forcer la suppression d’un verrou"
+
msgid "You must sign in to star a project"
msgstr "Vous devez vous connecter pour mettre un projet en favori"
+msgid "You need a different license to enable FileLocks feature"
+msgstr "Vous avez besoin d’une licence différente pour activer la fonctionnalité FileLocks"
+
msgid "You need permission."
msgstr "Vous avez besoin d’une autorisation."
@@ -3664,10 +4029,13 @@ msgid "You won't be able to pull or push project code via SSH until you add an S
msgstr "Vous ne pourrez pas récupérer ou pousser de code par SSH tant que vous n’aurez pas ajouté de clé SSH à votre profil"
msgid "You'll need to use different branch names to get a valid comparison."
-msgstr ""
+msgstr "Vous devrez utiliser différents noms de branches pour obtenir une comparaison valide."
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
-msgstr ""
+msgstr "Vos informations de cluster Kubernetes sur cette page sont toujours modifiables, mais il est conseillé de désactiver et reconfigurer"
+
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr "Vos modifications ont été validées. Commit %{commitId} %{commitStats}"
msgid "Your comment will not be visible to the public."
msgstr "Votre commentaire ne sera pas visible publiquement."
@@ -3682,7 +4050,7 @@ msgid "Your projects"
msgstr "Vos projets"
msgid "assign yourself"
-msgstr ""
+msgstr "assignez vous"
msgid "branch name"
msgstr "nom de la branche"
@@ -3691,58 +4059,73 @@ msgid "by"
msgstr "par"
msgid "ciReport|Code quality"
-msgstr ""
+msgstr "Qualité du code"
msgid "ciReport|DAST detected no alerts by analyzing the review app"
-msgstr ""
+msgstr "DAST n’a détecté aucune alerte en analysant l’application de revue"
-msgid "ciReport|Failed to load ${type} report"
-msgstr ""
+msgid "ciReport|Failed to load %{reportName} report"
+msgstr "Impossible de charger le rapport %{reportName}"
msgid "ciReport|Fixed:"
-msgstr ""
+msgstr "Réparé :"
msgid "ciReport|Instances"
-msgstr ""
+msgstr "Instances"
msgid "ciReport|Learn more about whitelisting"
-msgstr ""
+msgstr "En savoir plus sur la liste blanche"
-msgid "ciReport|Loading ${type} report"
-msgstr ""
+msgid "ciReport|Loading %{reportName} report"
+msgstr "Chargement du rapport %{reportName}"
msgid "ciReport|No changes to code quality"
-msgstr ""
+msgstr "Aucun changement dans la qualité du code"
msgid "ciReport|No changes to performance metrics"
-msgstr ""
+msgstr "Aucun changement dans les indicateurs de performance"
msgid "ciReport|Performance metrics"
-msgstr ""
+msgstr "Indicateurs de performance"
msgid "ciReport|SAST"
-msgstr ""
+msgstr "SAST"
+
+msgid "ciReport|SAST degraded on"
+msgstr "SAST dégradée sur"
+
+msgid "ciReport|SAST detected"
+msgstr "SAST détectée"
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr "SAST n’a détecté aucune nouvelle vulnérabilité de sécurité"
msgid "ciReport|SAST detected no security vulnerabilities"
-msgstr ""
+msgstr "SAST n’a détecté aucune vulnérabilité de sécurité"
msgid "ciReport|SAST:container no vulnerabilities were found"
-msgstr ""
+msgstr "SAST:conteneur aucune vulnérabilité n’a été trouvée"
msgid "ciReport|Show complete code vulnerabilities report"
-msgstr ""
+msgstr "Afficher le rapport complet sur les vulnérabilités du code"
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
-msgstr ""
+msgstr "Les vulnérabilités non approuvées (en rouge) peuvent être marquées comme approuvées. %{helpLink}"
+
+msgid "ciReport|no security vulnerabilities"
+msgstr "aucune vulnérabilité de sécurité"
+
+msgid "command line instructions"
+msgstr "instructions en ligne de commande"
msgid "commit"
msgstr "validation"
msgid "confidentiality|You are going to turn off the confidentiality. This means <strong>everyone</strong> will be able to see and leave a comment on this issue."
-msgstr ""
+msgstr "Vous allez désactiver la confidentialité. Cela signifie que <strong>tout le monde</strong> sera en mesure de voir et de laisser un commentaire sur ce ticket."
msgid "confidentiality|You are going to turn on the confidentiality. This means that only team members with <strong>at least Reporter access</strong> are able to see and leave comments on the issue."
-msgstr ""
+msgstr "Vous allez activer la confidentialité. Cela signifie que seuls les membres de l’équipe avec <strong>au moins un accès Reporter</strong> sont capables de voir et de laisser des commentaires sur le ticket."
msgid "day"
msgid_plural "days"
@@ -3750,141 +4133,180 @@ msgstr[0] "jour"
msgstr[1] "jours"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
-msgstr ""
+msgstr "%{slash_command} mettra à jour la durée estimée avec la dernière commande."
+
+msgid "is invalid because there is downstream lock"
+msgstr "est invalide car il y a un verrou en aval"
+
+msgid "is invalid because there is upstream lock"
+msgstr "est invalide car il y a un verrou en amont"
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr "verrouillé par %{path_lock_user_name} %{created_at}"
msgid "merge request"
msgid_plural "merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "demande de fusion"
+msgstr[1] "demandes de fusion"
+
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr "Veuillez la restaurer ou utiliser une autre branche %{missingBranchName}"
+
+msgid "mrWidget|Add approval"
+msgstr "Ajouter une approbation"
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr "Une erreur est survenue lors de la suppression de votre approbation."
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr "Une erreur s’est produite lors de la récupération des données d’approbation pour cette demande de fusion."
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr "Une erreur est survenue pendant l’envoi de votre approbation."
+
+msgid "mrWidget|Approve"
+msgstr "Approuver"
+
+msgid "mrWidget|Approved by"
+msgstr "Approuvée par"
msgid "mrWidget|Cancel automatic merge"
-msgstr ""
+msgstr "Annuler la fusion automatique"
msgid "mrWidget|Check out branch"
-msgstr ""
+msgstr "Récupérer la branche"
msgid "mrWidget|Checking ability to merge automatically"
-msgstr ""
+msgstr "Vérification de la possibilité de fusion automatique"
msgid "mrWidget|Cherry-pick"
-msgstr ""
+msgstr "Picorer"
msgid "mrWidget|Cherry-pick this merge request in a new merge request"
-msgstr ""
+msgstr "Picorer cette demande de fusion dans une nouvelle demande de fusion"
msgid "mrWidget|Closed"
-msgstr ""
+msgstr "Fermée"
msgid "mrWidget|Closed by"
-msgstr ""
+msgstr "Fermée par"
msgid "mrWidget|Closes"
-msgstr ""
+msgstr "Résout"
msgid "mrWidget|Did not close"
-msgstr ""
+msgstr "N’a pas résolu"
msgid "mrWidget|Email patches"
-msgstr ""
+msgstr "Patchs par courriel"
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
-msgstr ""
+msgstr "Si la branche %{branch} existe dans votre dépôt local, vous pouvez fusionner cette demande de fusion manuellement à l’aide de"
+
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr "Si la branche %{missingBranchName} existe dans votre dépôt local, vous pouvez fusionner cette demande de fusion manuellement en ligne de commande"
msgid "mrWidget|Mentions"
-msgstr ""
+msgstr "Mentionne"
msgid "mrWidget|Merge"
-msgstr ""
+msgstr "Fusionner"
msgid "mrWidget|Merge failed."
-msgstr ""
+msgstr "La fusion a échoué."
msgid "mrWidget|Merge locally"
-msgstr ""
+msgstr "Fusionner localement"
msgid "mrWidget|Merged by"
-msgstr ""
+msgstr "Fusionnée par"
msgid "mrWidget|Plain diff"
-msgstr ""
+msgstr "Diff simple"
msgid "mrWidget|Refresh"
-msgstr ""
+msgstr "Actualiser"
msgid "mrWidget|Refresh now"
-msgstr ""
+msgstr "Actualiser maintenant"
msgid "mrWidget|Refreshing now"
-msgstr ""
+msgstr "Actualisation en cours"
msgid "mrWidget|Remove Source Branch"
-msgstr ""
+msgstr "Supprimer la branche source"
msgid "mrWidget|Remove source branch"
-msgstr ""
+msgstr "Supprimer la branche source"
+
+msgid "mrWidget|Remove your approval"
+msgstr "Supprimer votre approbation"
msgid "mrWidget|Request to merge"
-msgstr ""
+msgstr "Demander la fusion"
msgid "mrWidget|Resolve conflicts"
-msgstr ""
+msgstr "Résoudre les conflits"
msgid "mrWidget|Revert"
-msgstr ""
+msgstr "Défaire"
msgid "mrWidget|Revert this merge request in a new merge request"
-msgstr ""
+msgstr "Défaire cette demande de fusion dans une nouvelle demande de fusion"
msgid "mrWidget|Set by"
-msgstr ""
+msgstr "Marqué par"
msgid "mrWidget|The changes were merged into"
-msgstr ""
+msgstr "Les modifications ont été fusionnées dans"
msgid "mrWidget|The changes were not merged into"
-msgstr ""
+msgstr "Les modifications n’ont pas été fusionnées dans"
msgid "mrWidget|The changes will be merged into"
-msgstr ""
+msgstr "Les modifications seront fusionnées dans"
msgid "mrWidget|The source branch has been removed"
-msgstr ""
+msgstr "La branche source a été supprimée"
msgid "mrWidget|The source branch is being removed"
-msgstr ""
+msgstr "La branche source est en cours de suppression"
msgid "mrWidget|The source branch will be removed"
-msgstr ""
+msgstr "La branche source sera supprimée"
msgid "mrWidget|The source branch will not be removed"
-msgstr ""
+msgstr "La branche source ne sera pas supprimée"
msgid "mrWidget|There are merge conflicts"
-msgstr ""
+msgstr "Il y a des conflits de fusion"
msgid "mrWidget|This merge request failed to be merged automatically"
-msgstr ""
+msgstr "Cette demande de fusion n’a pas pu être fusionnée automatiquement"
msgid "mrWidget|This merge request is in the process of being merged"
-msgstr ""
+msgstr "Cette demande de fusion est en cours de fusion"
msgid "mrWidget|This project is archived, write access has been disabled"
-msgstr ""
+msgstr "Ce projet est archivé, l’accès en écriture a été désactivé"
msgid "mrWidget|You can merge this merge request manually using the"
-msgstr ""
+msgstr "Vous pouvez fusionner cette demande de fusion manuellement à l’aide de la"
msgid "mrWidget|You can remove source branch now"
-msgstr ""
+msgstr "Vous pouvez maintenant supprimer la branche source"
+
+msgid "mrWidget|branch does not exist."
+msgstr "la branche n’existe pas."
msgid "mrWidget|command line"
-msgstr ""
+msgstr "ligne de commande"
msgid "mrWidget|into"
-msgstr ""
+msgstr "dans"
msgid "mrWidget|to be merged automatically when the pipeline succeeds"
-msgstr ""
+msgstr "pour être fusionnée automatiquement lorsque le pipeline réussit"
msgid "new merge request"
msgstr "nouvelle demande de fusion"
@@ -3893,7 +4315,7 @@ msgid "notification emails"
msgstr "courriels de notification"
msgid "or"
-msgstr ""
+msgstr "ou"
msgid "parent"
msgid_plural "parents"
@@ -3907,13 +4329,13 @@ msgid "personal access token"
msgstr "jeton d’accès personnel"
msgid "remove due date"
-msgstr ""
+msgstr "supprimer la date d’échéance"
msgid "source"
msgstr "source"
msgid "spendCommand|%{slash_command} will update the sum of the time spent."
-msgstr ""
+msgstr "%{slash_command} mettra à jour la somme du temps passé."
msgid "to help your contributors communicate effectively!"
msgstr "pour aider vos contributeurs à communiquer efficacement !"
@@ -3922,5 +4344,8 @@ msgid "username"
msgstr "nom d’utilisateur"
msgid "uses Kubernetes clusters to deploy your code!"
-msgstr ""
+msgstr "utilise les clusters Kubernetes pour déployer votre code !"
+
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr "avec %{additions} ajouts, %{deletions} suppressions."
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index c9b17f1e826..3f05e878cc8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-03-01 18:03+0100\n"
-"PO-Revision-Date: 2018-03-01 18:03+0100\n"
+"POT-Creation-Date: 2018-03-06 17:36+0100\n"
+"PO-Revision-Date: 2018-03-06 17:36+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
@@ -59,6 +59,9 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{loadingIcon} Started"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -102,6 +105,12 @@ msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
msgstr ""
+msgid "A new branch will be created in your fork and a new merge request will be started."
+msgstr ""
+
+msgid "A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), %{among_other_things_link}."
+msgstr ""
+
msgid "About auto deploy"
msgstr ""
@@ -201,9 +210,18 @@ msgstr ""
msgid "All"
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 ""
+
+msgid "Allow edits from maintainers"
+msgstr ""
+
msgid "Allows you to add and manage Kubernetes clusters."
msgstr ""
+msgid "Alternatively, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import."
+msgstr ""
+
msgid "An error occurred previewing the blob"
msgstr ""
@@ -282,9 +300,6 @@ msgstr ""
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr ""
-msgid "Are you sure you want to discard your changes?"
-msgstr ""
-
msgid "Are you sure you want to reset registration token?"
msgstr ""
@@ -386,9 +401,6 @@ msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> 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 is already taken"
msgstr ""
@@ -404,6 +416,15 @@ msgstr ""
msgid "Branches"
msgstr ""
+msgid "Branches|Active"
+msgstr ""
+
+msgid "Branches|Active branches"
+msgstr ""
+
+msgid "Branches|All"
+msgstr ""
+
msgid "Branches|Cant find HEAD commit for this branch"
msgstr ""
@@ -449,12 +470,39 @@ msgstr ""
msgid "Branches|Only a project master or owner can delete a protected branch"
msgstr ""
-msgid "Branches|Protected branches can be managed in %{project_settings_link}"
+msgid "Branches|Overview"
+msgstr ""
+
+msgid "Branches|Protected branches can be managed in %{project_settings_link}."
+msgstr ""
+
+msgid "Branches|Show active branches"
+msgstr ""
+
+msgid "Branches|Show all branches"
+msgstr ""
+
+msgid "Branches|Show more active branches"
+msgstr ""
+
+msgid "Branches|Show more stale branches"
+msgstr ""
+
+msgid "Branches|Show overview of the branches"
+msgstr ""
+
+msgid "Branches|Show stale branches"
msgstr ""
msgid "Branches|Sort by"
msgstr ""
+msgid "Branches|Stale"
+msgstr ""
+
+msgid "Branches|Stale branches"
+msgstr ""
+
msgid "Branches|The default branch cannot be deleted"
msgstr ""
@@ -506,9 +554,6 @@ msgstr ""
msgid "Cancel"
msgstr ""
-msgid "Cancel edit"
-msgstr ""
-
msgid "Cannot modify managed Kubernetes cluster"
msgstr ""
@@ -563,6 +608,9 @@ msgstr ""
msgid "Choose file..."
msgstr ""
+msgid "Choose which repositories you want to import."
+msgstr ""
+
msgid "CiStatusLabel|canceled"
msgstr ""
@@ -656,6 +704,9 @@ msgstr ""
msgid "Clone repository"
msgstr ""
+msgid "Close"
+msgstr ""
+
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr ""
@@ -698,6 +749,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -746,6 +800,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -1020,6 +1077,12 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
+msgid "Connect"
+msgstr ""
+
+msgid "Connect repositories from GitHub"
+msgstr ""
+
msgid "Container Registry"
msgstr ""
@@ -1065,6 +1128,9 @@ msgstr ""
msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
msgstr ""
+msgid "Contribution"
+msgstr ""
+
msgid "Contribution guide"
msgstr ""
@@ -1116,9 +1182,6 @@ msgstr ""
msgid "Create empty bare repository"
msgstr ""
-msgid "Create file"
-msgstr ""
-
msgid "Create lists from labels. Issues with that label appear in that list."
msgstr ""
@@ -1128,15 +1191,6 @@ msgstr ""
msgid "Create merge request and branch"
msgstr ""
-msgid "Create new branch"
-msgstr ""
-
-msgid "Create new directory"
-msgstr ""
-
-msgid "Create new file"
-msgstr ""
-
msgid "Create new label"
msgstr ""
@@ -1226,15 +1280,15 @@ msgstr ""
msgid "Directory name"
msgstr ""
-msgid "Discard changes"
-msgstr ""
-
msgid "Dismiss Cycle Analytics introduction box"
msgstr ""
msgid "Don't show again"
msgstr ""
+msgid "Done"
+msgstr ""
+
msgid "Download"
msgstr ""
@@ -1385,6 +1439,9 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "Failed"
+msgstr ""
+
msgid "Failed Jobs"
msgstr ""
@@ -1409,9 +1466,6 @@ msgstr ""
msgid "Fields on this page are now uneditable, you can configure"
msgstr ""
-msgid "File name"
-msgstr ""
-
msgid "Files"
msgstr ""
@@ -1427,6 +1481,9 @@ msgstr ""
msgid "Find file"
msgstr ""
+msgid "Finished"
+msgstr ""
+
msgid "FirstPushedBy|First"
msgstr ""
@@ -1444,9 +1501,15 @@ msgstr ""
msgid "ForkedFromProjectPath|Forked from %{project_name} (deleted)"
msgstr ""
+msgid "Forking in progress"
+msgstr ""
+
msgid "Format"
msgstr ""
+msgid "From %{provider_title}"
+msgstr ""
+
msgid "From issue creation until deploy to production"
msgstr ""
@@ -1462,6 +1525,9 @@ msgstr ""
msgid "Generate a default set of labels"
msgstr ""
+msgid "Git repository URL"
+msgstr ""
+
msgid "Git revision"
msgstr ""
@@ -1471,12 +1537,18 @@ msgstr ""
msgid "Git version"
msgstr ""
+msgid "GitHub import"
+msgstr ""
+
msgid "GitLab Runner section"
msgstr ""
msgid "Gitaly Servers"
msgstr ""
+msgid "Go back"
+msgstr ""
+
msgid "Go to your fork"
msgstr ""
@@ -1587,6 +1659,21 @@ msgstr ""
msgid "If you already have files you can push them using the %{link_to_cli} below."
msgstr ""
+msgid "If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>."
+msgstr ""
+
+msgid "Import"
+msgstr ""
+
+msgid "Import all repositories"
+msgstr ""
+
+msgid "Import in progress"
+msgstr ""
+
+msgid "Import repositories from GitHub"
+msgstr ""
+
msgid "Import repository"
msgstr ""
@@ -1677,6 +1764,15 @@ msgstr ""
msgid "LFSStatus|Enabled"
msgstr ""
+msgid "Label"
+msgstr ""
+
+msgid "LabelSelect|%{firstLabelName} +%{remainingLabelCount} more"
+msgstr ""
+
+msgid "LabelSelect|%{labelsString}, and %{remainingLabelCount} more"
+msgstr ""
+
msgid "Labels"
msgstr ""
@@ -1736,7 +1832,7 @@ msgstr ""
msgid "Leave project"
msgstr ""
-msgid "Loading the GitLab IDE..."
+msgid "List your GitHub repositories"
msgstr ""
msgid "Lock"
@@ -1823,6 +1919,9 @@ msgstr ""
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -1918,6 +2017,12 @@ msgstr ""
msgid "Not available"
msgstr ""
+msgid "Not available for private projects"
+msgstr ""
+
+msgid "Not available for protected branches"
+msgstr ""
+
msgid "Not confidential"
msgstr ""
@@ -1927,6 +2032,12 @@ msgstr ""
msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
msgstr ""
+msgid "Note: As an administrator you may like to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
+msgstr ""
+
+msgid "Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
+msgstr ""
+
msgid "Notification events"
msgstr ""
@@ -2044,6 +2155,12 @@ msgstr ""
msgid "Password"
msgstr ""
+msgid "Pending"
+msgstr ""
+
+msgid "Personal Access Token"
+msgstr ""
+
msgid "Pipeline"
msgstr ""
@@ -2122,9 +2239,30 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|CI Lint"
+msgstr ""
+
+msgid "Pipelines|Clear Runner Caches"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipelines|Loading Pipelines"
+msgstr ""
+
+msgid "Pipelines|Run Pipeline"
+msgstr ""
+
+msgid "Pipelines|There are currently no %{scope} pipelines."
+msgstr ""
+
+msgid "Pipelines|There are currently no pipelines."
+msgstr ""
+
+msgid "Pipelines|This project is not currently set up to run pipelines."
+msgstr ""
+
msgid "Pipeline|Retry pipeline"
msgstr ""
@@ -2164,6 +2302,9 @@ msgstr ""
msgid "Please solve the reCAPTCHA"
msgstr ""
+msgid "Please wait while we import the repository for you. Refresh at will."
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -2374,6 +2515,9 @@ msgstr ""
msgid "Public - The project can be accessed without any authentication."
msgstr ""
+msgid "Push access to this project is necessary in order to enable this option"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -2460,6 +2604,9 @@ msgstr ""
msgid "Revert this merge request"
msgstr ""
+msgid "Running"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2475,12 +2622,18 @@ msgstr ""
msgid "Schedule a new pipeline"
msgstr ""
+msgid "Scheduled"
+msgstr ""
+
msgid "Schedules"
msgstr ""
msgid "Scheduling Pipelines"
msgstr ""
+msgid "Search"
+msgstr ""
+
msgid "Search branches and tags"
msgstr ""
@@ -2520,6 +2673,9 @@ msgstr ""
msgid "Select target branch"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2720,6 +2876,12 @@ msgstr ""
msgid "Start the Runner!"
msgstr ""
+msgid "Started"
+msgstr ""
+
+msgid "Status"
+msgstr ""
+
msgid "Stopped"
msgstr ""
@@ -2833,6 +2995,9 @@ msgstr ""
msgid "The fork relationship has been removed."
msgstr ""
+msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
+msgstr ""
+
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr ""
@@ -2866,6 +3031,9 @@ msgstr ""
msgid "The repository for this project is empty"
msgstr ""
+msgid "The repository must be accessible over <code>http://</code>, <code>https://</code> or <code>git://</code>."
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
@@ -3131,6 +3299,18 @@ msgstr ""
msgid "Tip:"
msgstr ""
+msgid "To GitLab"
+msgstr ""
+
+msgid "To import GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to import."
+msgstr ""
+
+msgid "To import GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:"
+msgstr ""
+
+msgid "To import an SVN repository, check out %{svn_link}."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3236,9 +3416,6 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "Web IDE"
-msgstr ""
-
msgid "Wiki"
msgstr ""
@@ -3353,13 +3530,13 @@ msgstr ""
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
+msgid "You are going to remove %{project_full_name}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are on a read-only GitLab instance."
@@ -3425,6 +3602,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes can be committed to %{branch_name} because a merge request is open."
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3437,6 +3617,9 @@ msgstr ""
msgid "Your projects"
msgstr ""
+msgid "among other things"
+msgstr ""
+
msgid "assign yourself"
msgstr ""
@@ -3452,6 +3635,9 @@ msgstr ""
msgid "confidentiality|You are going to turn on the confidentiality. This means that only team members with <strong>at least Reporter access</strong> are able to see and leave comments on the issue."
msgstr ""
+msgid "connecting"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] ""
@@ -3460,6 +3646,9 @@ msgstr[1] ""
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "importing"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
@@ -3468,6 +3657,9 @@ msgstr[1] ""
msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
msgstr ""
+msgid "mrWidget|Allows edits from maintainers"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3632,6 +3824,9 @@ msgstr ""
msgid "spendCommand|%{slash_command} will update the sum of the time spent."
msgstr ""
+msgid "this document"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po
new file mode 100644
index 00000000000..183cb996b0a
--- /dev/null
+++ b/locale/id_ID/gitlab.po
@@ -0,0 +1,4325 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: gitlab-ee\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:23-0500\n"
+"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
+"Language-Team: Indonesian\n"
+"Language: id_ID\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: crowdin.com\n"
+"X-Crowdin-Project: gitlab-ee\n"
+"X-Crowdin-Language: id\n"
+"X-Crowdin-File: /master/locale/gitlab.pot\n"
+
+msgid " and"
+msgstr ""
+
+msgid "%d commit"
+msgid_plural "%d commits"
+msgstr[0] ""
+
+msgid "%d commit behind"
+msgid_plural "%d commits behind"
+msgstr[0] ""
+
+msgid "%d issue"
+msgid_plural "%d issues"
+msgstr[0] ""
+
+msgid "%d layer"
+msgid_plural "%d layers"
+msgstr[0] ""
+
+msgid "%d merge request"
+msgid_plural "%d merge requests"
+msgstr[0] ""
+
+msgid "%s additional commit has been omitted to prevent performance issues."
+msgid_plural "%s additional commits have been omitted to prevent performance issues."
+msgstr[0] ""
+
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
+msgid "%{commit_author_link} authored %{commit_timeago}"
+msgstr ""
+
+msgid "%{count} participant"
+msgid_plural "%{count} participants"
+msgstr[0] ""
+
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
+msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
+msgstr ""
+
+msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
+msgstr ""
+
+msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
+msgstr ""
+
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
+msgid "%{storage_name}: failed storage access attempt on host:"
+msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
+msgstr[0] ""
+
+msgid "%{text} is available"
+msgstr ""
+
+msgid "(checkout the %{link} for information on how to install it)."
+msgstr ""
+
+msgid "+ %{moreCount} more"
+msgstr ""
+
+msgid "- show less"
+msgstr ""
+
+msgid "1 pipeline"
+msgid_plural "%d pipelines"
+msgstr[0] ""
+
+msgid "1st contribution!"
+msgstr ""
+
+msgid "2FA enabled"
+msgstr ""
+
+msgid "A collection of graphs regarding Continuous Integration"
+msgstr ""
+
+msgid "About auto deploy"
+msgstr ""
+
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
+msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
+msgstr ""
+
+msgid "Account"
+msgstr ""
+
+msgid "Active"
+msgstr ""
+
+msgid "Activity"
+msgstr ""
+
+msgid "Add"
+msgstr ""
+
+msgid "Add Changelog"
+msgstr ""
+
+msgid "Add Contribution guide"
+msgstr ""
+
+msgid "Add Group Webhooks and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Add Kubernetes cluster"
+msgstr ""
+
+msgid "Add License"
+msgstr ""
+
+msgid "Add Readme"
+msgstr ""
+
+msgid "Add new directory"
+msgstr ""
+
+msgid "Add todo"
+msgstr ""
+
+msgid "AdminArea|Stop all jobs"
+msgstr ""
+
+msgid "AdminArea|Stop all jobs?"
+msgstr ""
+
+msgid "AdminArea|Stop jobs"
+msgstr ""
+
+msgid "AdminArea|Stopping jobs failed"
+msgstr ""
+
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
+msgstr ""
+
+msgid "AdminHealthPageLink|health page"
+msgstr ""
+
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
+msgid "Advanced"
+msgstr ""
+
+msgid "Advanced settings"
+msgstr ""
+
+msgid "All"
+msgstr ""
+
+msgid "All changes are committed"
+msgstr ""
+
+msgid "Allows you to add and manage Kubernetes clusters."
+msgstr ""
+
+msgid "An error occurred previewing the blob"
+msgstr ""
+
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
+msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
+msgstr ""
+
+msgid "An error occurred while fetching markdown preview"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
+msgid "An error occurred while getting projects"
+msgstr ""
+
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
+msgid "An error occurred while loading filenames"
+msgstr ""
+
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
+msgid "An error occurred while rendering KaTeX"
+msgstr ""
+
+msgid "An error occurred while rendering preview broadcast message"
+msgstr ""
+
+msgid "An error occurred while retrieving calendar activity"
+msgstr ""
+
+msgid "An error occurred while retrieving diff"
+msgstr ""
+
+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 validating username"
+msgstr ""
+
+msgid "An error occurred. Please try again."
+msgstr ""
+
+msgid "Appearance"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
+msgid "Archived project! Repository is read-only"
+msgstr ""
+
+msgid "Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
+msgid "Are you sure you want to reset registration token?"
+msgstr ""
+
+msgid "Are you sure you want to reset the health check token?"
+msgstr ""
+
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
+msgid "Are you sure?"
+msgstr ""
+
+msgid "Artifacts"
+msgstr ""
+
+msgid "Assign custom color like #FF0000"
+msgstr ""
+
+msgid "Assign labels"
+msgstr ""
+
+msgid "Assign milestone"
+msgstr ""
+
+msgid "Assign to"
+msgstr ""
+
+msgid "Assignee"
+msgstr ""
+
+msgid "Attach a file by drag &amp; drop or %{upload_link}"
+msgstr ""
+
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Author"
+msgstr ""
+
+msgid "Authors: %{authors}"
+msgstr ""
+
+msgid "Auto DevOps enabled"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and a %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Auto DevOps (Beta)"
+msgstr ""
+
+msgid "AutoDevOps|Auto DevOps documentation"
+msgstr ""
+
+msgid "AutoDevOps|Enable in settings"
+msgstr ""
+
+msgid "AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
+msgstr ""
+
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Available"
+msgstr ""
+
+msgid "Avatar will be removed. Are you sure?"
+msgstr ""
+
+msgid "Average per day: %{average}"
+msgstr ""
+
+msgid "Begin with the selected commit"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Downgrade"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
+
+msgid "Branch <strong>%{branch_name}</strong> 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 is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
+msgid "BranchSwitcherPlaceholder|Search branches"
+msgstr ""
+
+msgid "BranchSwitcherTitle|Switch branch"
+msgstr ""
+
+msgid "Branches"
+msgstr ""
+
+msgid "Branches|Cant find HEAD commit for this branch"
+msgstr ""
+
+msgid "Branches|Compare"
+msgstr ""
+
+msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
+msgstr ""
+
+msgid "Branches|Delete branch"
+msgstr ""
+
+msgid "Branches|Delete merged branches"
+msgstr ""
+
+msgid "Branches|Delete protected branch"
+msgstr ""
+
+msgid "Branches|Delete protected branch '%{branch_name}'?"
+msgstr ""
+
+msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "Branches|Filter by branch name"
+msgstr ""
+
+msgid "Branches|Merged into %{default_branch}"
+msgstr ""
+
+msgid "Branches|New branch"
+msgstr ""
+
+msgid "Branches|No branches to show"
+msgstr ""
+
+msgid "Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered."
+msgstr ""
+
+msgid "Branches|Only a project master or owner can delete a protected branch"
+msgstr ""
+
+msgid "Branches|Protected branches can be managed in %{project_settings_link}"
+msgstr ""
+
+msgid "Branches|Sort by"
+msgstr ""
+
+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 ""
+
+msgid "Branches|This branch hasn’t been merged into %{default_branch}."
+msgstr ""
+
+msgid "Branches|To avoid data loss, consider merging this branch before deleting it."
+msgstr ""
+
+msgid "Branches|To confirm, type %{branch_name_confirmation}:"
+msgstr ""
+
+msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
+msgstr ""
+
+msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
+msgstr ""
+
+msgid "Branches|diverged from upstream"
+msgstr ""
+
+msgid "Branches|merged"
+msgstr ""
+
+msgid "Branches|project settings"
+msgstr ""
+
+msgid "Branches|protected"
+msgstr ""
+
+msgid "Browse Directory"
+msgstr ""
+
+msgid "Browse File"
+msgstr ""
+
+msgid "Browse Files"
+msgstr ""
+
+msgid "Browse files"
+msgstr ""
+
+msgid "ByAuthor|by"
+msgstr ""
+
+msgid "CI / CD"
+msgstr ""
+
+msgid "CI/CD configuration"
+msgstr ""
+
+msgid "CICD|Jobs"
+msgstr ""
+
+msgid "Cancel"
+msgstr ""
+
+msgid "Cancel edit"
+msgstr ""
+
+msgid "Cannot modify managed Kubernetes cluster"
+msgstr ""
+
+msgid "Change Weight"
+msgstr ""
+
+msgid "ChangeTypeActionLabel|Pick into branch"
+msgstr ""
+
+msgid "ChangeTypeActionLabel|Revert in branch"
+msgstr ""
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr ""
+
+msgid "ChangeTypeAction|Revert"
+msgstr ""
+
+msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
+msgstr ""
+
+msgid "Changelog"
+msgstr ""
+
+msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision."
+msgstr ""
+
+msgid "Charts"
+msgstr ""
+
+msgid "Chat"
+msgstr ""
+
+msgid "Check interval"
+msgstr ""
+
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
+msgid "Cherry-pick this commit"
+msgstr ""
+
+msgid "Cherry-pick this merge request"
+msgstr ""
+
+msgid "Choose File ..."
+msgstr ""
+
+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 ""
+
+msgid "Choose file..."
+msgstr ""
+
+msgid "Choose which groups you wish to synchronize to this secondary node."
+msgstr ""
+
+msgid "Choose which shards you wish to synchronize to this secondary node."
+msgstr ""
+
+msgid "CiStatusLabel|canceled"
+msgstr ""
+
+msgid "CiStatusLabel|created"
+msgstr ""
+
+msgid "CiStatusLabel|failed"
+msgstr ""
+
+msgid "CiStatusLabel|manual action"
+msgstr ""
+
+msgid "CiStatusLabel|passed"
+msgstr ""
+
+msgid "CiStatusLabel|passed with warnings"
+msgstr ""
+
+msgid "CiStatusLabel|pending"
+msgstr ""
+
+msgid "CiStatusLabel|skipped"
+msgstr ""
+
+msgid "CiStatusLabel|waiting for manual action"
+msgstr ""
+
+msgid "CiStatusText|blocked"
+msgstr ""
+
+msgid "CiStatusText|canceled"
+msgstr ""
+
+msgid "CiStatusText|created"
+msgstr ""
+
+msgid "CiStatusText|failed"
+msgstr ""
+
+msgid "CiStatusText|manual"
+msgstr ""
+
+msgid "CiStatusText|passed"
+msgstr ""
+
+msgid "CiStatusText|pending"
+msgstr ""
+
+msgid "CiStatusText|skipped"
+msgstr ""
+
+msgid "CiStatus|running"
+msgstr ""
+
+msgid "CiVariables|Input variable key"
+msgstr ""
+
+msgid "CiVariables|Input variable value"
+msgstr ""
+
+msgid "CiVariables|Remove variable row"
+msgstr ""
+
+msgid "CiVariable|* (All environments)"
+msgstr ""
+
+msgid "CiVariable|All environments"
+msgstr ""
+
+msgid "CiVariable|Create wildcard"
+msgstr ""
+
+msgid "CiVariable|Error occured while saving variables"
+msgstr ""
+
+msgid "CiVariable|New environment"
+msgstr ""
+
+msgid "CiVariable|Protected"
+msgstr ""
+
+msgid "CiVariable|Search environments"
+msgstr ""
+
+msgid "CiVariable|Toggle protected"
+msgstr ""
+
+msgid "CiVariable|Validation failed"
+msgstr ""
+
+msgid "CircuitBreakerApiLink|circuitbreaker api"
+msgstr ""
+
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
+msgid "Click to expand text"
+msgstr ""
+
+msgid "Clone repository"
+msgstr ""
+
+msgid "Close"
+msgstr ""
+
+msgid "Closed"
+msgstr ""
+
+msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Add Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|Are you sure you want to remove this Kubernetes cluster's integration? This will not delete your actual Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Choose which of your project's environments will use this Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Control how your Kubernetes cluster integrates with GitLab"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Kubernetes cluster name"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
+msgstr ""
+
+msgid "ClusterIntegration|Create Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Create Kubernetes cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create a new Kubernetes cluster on Google Kubernetes Engine right from GitLab"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment scope"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Integration"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
+msgid "ClusterIntegration|Google Cloud Platform project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Google Kubernetes Engine project"
+msgstr ""
+
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgstr ""
+
+msgid "ClusterIntegration|Integration status"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster details"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is disabled for this project."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project. Disabling this integration will not affect your Kubernetes cluster, it will only temporarily turn off GitLab's connection to it."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster is being created on Google Kubernetes Engine..."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster name"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine. Refresh the page to see Kubernetes cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about environments"
+msgstr ""
+
+msgid "ClusterIntegration|Machine type"
+msgstr ""
+
+msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
+msgstr ""
+
+msgid "ClusterIntegration|Manage"
+msgstr ""
+
+msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
+msgstr ""
+
+msgid "ClusterIntegration|More information"
+msgstr ""
+
+msgid "ClusterIntegration|Multiple Kubernetes clusters are available in GitLab Enterprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
+msgid "ClusterIntegration|Number of nodes"
+msgstr ""
+
+msgid "ClusterIntegration|Please enter access information for your Kubernetes cluster. If you need help, you can read our %{link_to_help_page} on Kubernetes"
+msgstr ""
+
+msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace (optional, unique)"
+msgstr ""
+
+msgid "ClusterIntegration|Prometheus"
+msgstr ""
+
+msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration."
+msgstr ""
+
+msgid "ClusterIntegration|Remove Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Remove integration"
+msgstr ""
+
+msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
+msgstr ""
+
+msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|See machine types"
+msgstr ""
+
+msgid "ClusterIntegration|See your projects"
+msgstr ""
+
+msgid "ClusterIntegration|See zones"
+msgstr ""
+
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong on our end."
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
+msgid "ClusterIntegration|Toggle Kubernetes Cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Toggle Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Token"
+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 ""
+
+msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
+msgstr ""
+
+msgid "ClusterIntegration|Zone"
+msgstr ""
+
+msgid "ClusterIntegration|access to Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|check the pricing here"
+msgstr ""
+
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
+msgid "ClusterIntegration|help page"
+msgstr ""
+
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
+msgid "ClusterIntegration|meets the requirements"
+msgstr ""
+
+msgid "ClusterIntegration|properly configured"
+msgstr ""
+
+msgid "Collapse"
+msgstr ""
+
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
+msgid "Comments"
+msgstr ""
+
+msgid "Commit"
+msgid_plural "Commits"
+msgstr[0] ""
+
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+
+msgid "Commit Message"
+msgstr ""
+
+msgid "Commit duration in minutes for last 30 commits"
+msgstr ""
+
+msgid "Commit message"
+msgstr ""
+
+msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
+msgstr ""
+
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
+msgid "CommitBoxTitle|Commit"
+msgstr ""
+
+msgid "CommitMessage|Add %{file_name}"
+msgstr ""
+
+msgid "Commits"
+msgstr ""
+
+msgid "Commits feed"
+msgstr ""
+
+msgid "Commits per day hour (UTC)"
+msgstr ""
+
+msgid "Commits per day of month"
+msgstr ""
+
+msgid "Commits per weekday"
+msgstr ""
+
+msgid "Commits|An error occurred while fetching merge requests data."
+msgstr ""
+
+msgid "Commits|Commit: %{commitText}"
+msgstr ""
+
+msgid "Commits|History"
+msgstr ""
+
+msgid "Commits|No related merge requests found"
+msgstr ""
+
+msgid "Committed by"
+msgstr ""
+
+msgid "Compare"
+msgstr ""
+
+msgid "Compare Git revisions"
+msgstr ""
+
+msgid "Compare Revisions"
+msgstr ""
+
+msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
+msgstr ""
+
+msgid "CompareBranches|Compare"
+msgstr ""
+
+msgid "CompareBranches|Source"
+msgstr ""
+
+msgid "CompareBranches|Target"
+msgstr ""
+
+msgid "CompareBranches|There isn't anything to compare."
+msgstr ""
+
+msgid "Confidentiality"
+msgstr ""
+
+msgid "Container Registry"
+msgstr ""
+
+msgid "ContainerRegistry|Created"
+msgstr ""
+
+msgid "ContainerRegistry|First log in to GitLab&rsquo;s Container Registry using your GitLab username and password. If you have %{link_2fa} you need to use a %{link_token}:"
+msgstr ""
+
+msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
+msgstr ""
+
+msgid "ContainerRegistry|How to use the Container Registry"
+msgstr ""
+
+msgid "ContainerRegistry|Learn more about"
+msgstr ""
+
+msgid "ContainerRegistry|No tags in Container Registry for this container image."
+msgstr ""
+
+msgid "ContainerRegistry|Once you log in, you&rsquo;re free to create and upload a container image using the common %{build} and %{push} commands"
+msgstr ""
+
+msgid "ContainerRegistry|Remove repository"
+msgstr ""
+
+msgid "ContainerRegistry|Remove tag"
+msgstr ""
+
+msgid "ContainerRegistry|Size"
+msgstr ""
+
+msgid "ContainerRegistry|Tag"
+msgstr ""
+
+msgid "ContainerRegistry|Tag ID"
+msgstr ""
+
+msgid "ContainerRegistry|Use different image names"
+msgstr ""
+
+msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
+msgstr ""
+
+msgid "Contribution guide"
+msgstr ""
+
+msgid "Contributors"
+msgstr ""
+
+msgid "ContributorsPage|%{startDate} – %{endDate}"
+msgstr ""
+
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
+msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
+msgstr ""
+
+msgid "Control the maximum concurrency of repository backfill for this secondary node"
+msgstr ""
+
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
+msgid "Copy URL to clipboard"
+msgstr ""
+
+msgid "Copy branch name to clipboard"
+msgstr ""
+
+msgid "Copy command to clipboard"
+msgstr ""
+
+msgid "Copy commit SHA to clipboard"
+msgstr ""
+
+msgid "Copy reference to clipboard"
+msgstr ""
+
+msgid "Create"
+msgstr ""
+
+msgid "Create New Directory"
+msgstr ""
+
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
+msgid "Create a personal access token on your account to pull or push via %{protocol}."
+msgstr ""
+
+msgid "Create branch"
+msgstr ""
+
+msgid "Create directory"
+msgstr ""
+
+msgid "Create empty bare repository"
+msgstr ""
+
+msgid "Create epic"
+msgstr ""
+
+msgid "Create file"
+msgstr ""
+
+msgid "Create lists from labels. Issues with that label appear in that list."
+msgstr ""
+
+msgid "Create merge request"
+msgstr ""
+
+msgid "Create merge request and branch"
+msgstr ""
+
+msgid "Create new branch"
+msgstr ""
+
+msgid "Create new directory"
+msgstr ""
+
+msgid "Create new file"
+msgstr ""
+
+msgid "Create new label"
+msgstr ""
+
+msgid "Create new..."
+msgstr ""
+
+msgid "CreateNewFork|Fork"
+msgstr ""
+
+msgid "CreateTag|Tag"
+msgstr ""
+
+msgid "CreateTokenToCloneLink|create a personal access token"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
+msgid "Creating epic"
+msgstr ""
+
+msgid "Cron Timezone"
+msgstr ""
+
+msgid "Cron syntax"
+msgstr ""
+
+msgid "Current node"
+msgstr ""
+
+msgid "Custom notification events"
+msgstr ""
+
+msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}."
+msgstr ""
+
+msgid "Cycle Analytics"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Code"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Issue"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Plan"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Production"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Review"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Staging"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Test"
+msgstr ""
+
+msgid "DashboardProjects|All"
+msgstr ""
+
+msgid "DashboardProjects|Personal"
+msgstr ""
+
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
+msgid "Default classification label"
+msgstr ""
+
+msgid "Define a custom pattern with cron syntax"
+msgstr ""
+
+msgid "Delete"
+msgstr ""
+
+msgid "Deploy"
+msgid_plural "Deploys"
+msgstr[0] ""
+
+msgid "Deploy Keys"
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
+msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
+msgstr ""
+
+msgid "Details"
+msgstr ""
+
+msgid "Diffs|No file name available"
+msgstr ""
+
+msgid "Directory name"
+msgstr ""
+
+msgid "Disable"
+msgstr ""
+
+msgid "Discard draft"
+msgstr ""
+
+msgid "Discover GitLab Geo."
+msgstr ""
+
+msgid "Dismiss Cycle Analytics introduction box"
+msgstr ""
+
+msgid "Dismiss Merge Request promotion"
+msgstr ""
+
+msgid "Don't show again"
+msgstr ""
+
+msgid "Download"
+msgstr ""
+
+msgid "Download tar"
+msgstr ""
+
+msgid "Download tar.bz2"
+msgstr ""
+
+msgid "Download tar.gz"
+msgstr ""
+
+msgid "Download zip"
+msgstr ""
+
+msgid "DownloadArtifacts|Download"
+msgstr ""
+
+msgid "DownloadCommit|Email Patches"
+msgstr ""
+
+msgid "DownloadCommit|Plain Diff"
+msgstr ""
+
+msgid "DownloadSource|Download"
+msgstr ""
+
+msgid "Due date"
+msgstr ""
+
+msgid "Edit"
+msgstr ""
+
+msgid "Edit Pipeline Schedule %{id}"
+msgstr ""
+
+msgid "Edit files in the editor and commit changes here"
+msgstr ""
+
+msgid "Emails"
+msgstr ""
+
+msgid "Enable"
+msgstr ""
+
+msgid "Enable Auto DevOps"
+msgstr ""
+
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics Roadmap"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error fetching contributors data."
+msgstr ""
+
+msgid "Error fetching labels."
+msgstr ""
+
+msgid "Error fetching network graph."
+msgstr ""
+
+msgid "Error fetching refs"
+msgstr ""
+
+msgid "Error fetching usage ping data."
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "Error saving label update."
+msgstr ""
+
+msgid "Error updating status for all todos."
+msgstr ""
+
+msgid "Error updating todo status."
+msgstr ""
+
+msgid "EventFilterBy|Filter by all"
+msgstr ""
+
+msgid "EventFilterBy|Filter by comments"
+msgstr ""
+
+msgid "EventFilterBy|Filter by issue events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by merge events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by push events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by team"
+msgstr ""
+
+msgid "Every day (at 4:00am)"
+msgstr ""
+
+msgid "Every month (on the 1st at 4:00am)"
+msgstr ""
+
+msgid "Every week (Sundays at 4:00am)"
+msgstr ""
+
+msgid "Expand"
+msgstr ""
+
+msgid "Explore projects"
+msgstr ""
+
+msgid "Explore public groups"
+msgstr ""
+
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
+msgid "Failed to change the owner"
+msgstr ""
+
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
+msgid "Failed to remove the pipeline schedule"
+msgstr ""
+
+msgid "Failed to update issues, please try again."
+msgstr ""
+
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
+msgid "Fields on this page are now uneditable, you can configure"
+msgstr ""
+
+msgid "File name"
+msgstr ""
+
+msgid "Files"
+msgstr ""
+
+msgid "Files (%{human_size})"
+msgstr ""
+
+msgid "Filter by commit message"
+msgstr ""
+
+msgid "Find by path"
+msgstr ""
+
+msgid "Find file"
+msgstr ""
+
+msgid "FirstPushedBy|First"
+msgstr ""
+
+msgid "FirstPushedBy|pushed by"
+msgstr ""
+
+msgid "Fork"
+msgid_plural "Forks"
+msgstr[0] ""
+
+msgid "ForkedFromProjectPath|Forked from"
+msgstr ""
+
+msgid "ForkedFromProjectPath|Forked from %{project_name} (deleted)"
+msgstr ""
+
+msgid "Format"
+msgstr ""
+
+msgid "From issue creation until deploy to production"
+msgstr ""
+
+msgid "From merge request merge until deploy to production"
+msgstr ""
+
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Generate a default set of labels"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodes|Database replication lag:"
+msgstr ""
+
+msgid "GeoNodes|Disabling a node stops the sync process. Are you sure?"
+msgstr ""
+
+msgid "GeoNodes|Does not match the primary storage configuration"
+msgstr ""
+
+msgid "GeoNodes|Failed"
+msgstr ""
+
+msgid "GeoNodes|Full"
+msgstr ""
+
+msgid "GeoNodes|GitLab version does not match the primary node version"
+msgstr ""
+
+msgid "GeoNodes|GitLab version:"
+msgstr ""
+
+msgid "GeoNodes|Health status:"
+msgstr ""
+
+msgid "GeoNodes|Last event ID processed by cursor:"
+msgstr ""
+
+msgid "GeoNodes|Last event ID seen from primary:"
+msgstr ""
+
+msgid "GeoNodes|Loading nodes"
+msgstr ""
+
+msgid "GeoNodes|Local Attachments:"
+msgstr ""
+
+msgid "GeoNodes|Local LFS objects:"
+msgstr ""
+
+msgid "GeoNodes|Local job artifacts:"
+msgstr ""
+
+msgid "GeoNodes|New node"
+msgstr ""
+
+msgid "GeoNodes|Out of sync"
+msgstr ""
+
+msgid "GeoNodes|Replication slot WAL:"
+msgstr ""
+
+msgid "GeoNodes|Replication slots:"
+msgstr ""
+
+msgid "GeoNodes|Repositories:"
+msgstr ""
+
+msgid "GeoNodes|Selective"
+msgstr ""
+
+msgid "GeoNodes|Storage config:"
+msgstr ""
+
+msgid "GeoNodes|Sync settings:"
+msgstr ""
+
+msgid "GeoNodes|Synced"
+msgstr ""
+
+msgid "GeoNodes|Unused slots"
+msgstr ""
+
+msgid "GeoNodes|Used slots"
+msgstr ""
+
+msgid "GeoNodes|Wikis:"
+msgstr ""
+
+msgid "GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS."
+msgstr ""
+
+msgid "Geo|All projects"
+msgstr ""
+
+msgid "Geo|File sync capacity"
+msgstr ""
+
+msgid "Geo|Groups to synchronize"
+msgstr ""
+
+msgid "Geo|Projects in certain groups"
+msgstr ""
+
+msgid "Geo|Projects in certain storage shards"
+msgstr ""
+
+msgid "Geo|Repository sync capacity"
+msgstr ""
+
+msgid "Geo|Select groups to replicate."
+msgstr ""
+
+msgid "Geo|Shards to synchronize"
+msgstr ""
+
+msgid "Git revision"
+msgstr ""
+
+msgid "Git storage health information has been reset"
+msgstr ""
+
+msgid "Git version"
+msgstr ""
+
+msgid "GitLab Runner section"
+msgstr ""
+
+msgid "Gitaly Servers"
+msgstr ""
+
+msgid "Go to your fork"
+msgstr ""
+
+msgid "GoToYourFork|Fork"
+msgstr ""
+
+msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
+msgstr ""
+
+msgid "Got it!"
+msgstr ""
+
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
+msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
+msgstr ""
+
+msgid "GroupSettings|Share with group lock"
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
+msgstr ""
+
+msgid "GroupSettings|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 ""
+
+msgid "GroupSettings|cannot be disabled when the parent group \"Share with group lock\" is enabled, except by the owner of the parent group"
+msgstr ""
+
+msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name}"
+msgstr ""
+
+msgid "GroupsEmptyState|A group is a collection of several projects."
+msgstr ""
+
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+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 ""
+
+msgid "GroupsTree|Are you sure you want to leave the \"${group.fullName}\" group?"
+msgstr ""
+
+msgid "GroupsTree|Create a project in this group."
+msgstr ""
+
+msgid "GroupsTree|Create a subgroup in this group."
+msgstr ""
+
+msgid "GroupsTree|Edit group"
+msgstr ""
+
+msgid "GroupsTree|Failed to leave the group. Please make sure you are not the only owner."
+msgstr ""
+
+msgid "GroupsTree|Filter by name..."
+msgstr ""
+
+msgid "GroupsTree|Leave this group"
+msgstr ""
+
+msgid "GroupsTree|Loading groups"
+msgstr ""
+
+msgid "GroupsTree|Sorry, no groups matched your search"
+msgstr ""
+
+msgid "GroupsTree|Sorry, no groups or projects matched your search"
+msgstr ""
+
+msgid "Have your users email"
+msgstr ""
+
+msgid "Health Check"
+msgstr ""
+
+msgid "Health information can be retrieved from the following endpoints. More information is available"
+msgstr ""
+
+msgid "HealthCheck|Access token is"
+msgstr ""
+
+msgid "HealthCheck|Healthy"
+msgstr ""
+
+msgid "HealthCheck|No Health Problems Detected"
+msgstr ""
+
+msgid "HealthCheck|Unhealthy"
+msgstr ""
+
+msgid "Hide value"
+msgid_plural "Hide values"
+msgstr[0] ""
+
+msgid "History"
+msgstr ""
+
+msgid "Housekeeping successfully started"
+msgstr ""
+
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
+msgid "Import repository"
+msgstr ""
+
+msgid "Improve Issue boards with GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
+msgid "Install a Runner compatible with GitLab CI"
+msgstr ""
+
+msgid "Instance"
+msgid_plural "Instances"
+msgstr[0] ""
+
+msgid "Instance does not support multiple Kubernetes clusters"
+msgstr ""
+
+msgid "Interested parties can even contribute by pushing commits if they want to."
+msgstr ""
+
+msgid "Internal - The group and any internal projects can be viewed by any logged in user."
+msgstr ""
+
+msgid "Internal - The project can be accessed by any logged in user."
+msgstr ""
+
+msgid "Interval Pattern"
+msgstr ""
+
+msgid "Introducing Cycle Analytics"
+msgstr ""
+
+msgid "Issue board focus mode"
+msgstr ""
+
+msgid "Issue events"
+msgstr ""
+
+msgid "IssueBoards|Board"
+msgstr ""
+
+msgid "IssueBoards|Boards"
+msgstr ""
+
+msgid "Issues"
+msgstr ""
+
+msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
+msgstr ""
+
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jobs"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
+msgid "Kubernetes"
+msgstr ""
+
+msgid "Kubernetes Cluster"
+msgstr ""
+
+msgid "Kubernetes cluster creation time exceeds timeout; %{timeout}"
+msgstr ""
+
+msgid "Kubernetes cluster integration was not removed."
+msgstr ""
+
+msgid "Kubernetes cluster integration was successfully removed."
+msgstr ""
+
+msgid "Kubernetes cluster was successfully updated."
+msgstr ""
+
+msgid "Kubernetes configured"
+msgstr ""
+
+msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
+msgstr ""
+
+msgid "LFSStatus|Disabled"
+msgstr ""
+
+msgid "LFSStatus|Enabled"
+msgstr ""
+
+msgid "Labels"
+msgstr ""
+
+msgid "Labels can be applied to issues and merge requests to categorize them."
+msgstr ""
+
+msgid "Last %d day"
+msgid_plural "Last %d days"
+msgstr[0] ""
+
+msgid "Last Pipeline"
+msgstr ""
+
+msgid "Last commit"
+msgstr ""
+
+msgid "Last edited %{date}"
+msgstr ""
+
+msgid "Last edited by %{name}"
+msgstr ""
+
+msgid "Last update"
+msgstr ""
+
+msgid "Last updated"
+msgstr ""
+
+msgid "LastPushEvent|You pushed to"
+msgstr ""
+
+msgid "LastPushEvent|at"
+msgstr ""
+
+msgid "Learn more"
+msgstr ""
+
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
+msgid "Learn more in the"
+msgstr ""
+
+msgid "Learn more in the|pipeline schedules documentation"
+msgstr ""
+
+msgid "Leave"
+msgstr ""
+
+msgid "Leave group"
+msgstr ""
+
+msgid "Leave project"
+msgstr ""
+
+msgid "License"
+msgstr ""
+
+msgid "List"
+msgstr ""
+
+msgid "Loading the GitLab IDE..."
+msgstr ""
+
+msgid "Lock"
+msgstr ""
+
+msgid "Lock %{issuableDisplayName}"
+msgstr ""
+
+msgid "Lock not found"
+msgstr ""
+
+msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
+msgstr ""
+
+msgid "Locked"
+msgstr ""
+
+msgid "Locked Files"
+msgstr ""
+
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
+msgid "Login"
+msgstr ""
+
+msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
+msgstr ""
+
+msgid "Manage labels"
+msgstr ""
+
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
+msgid "Mark done"
+msgstr ""
+
+msgid "Maximum git storage failures"
+msgstr ""
+
+msgid "May"
+msgstr ""
+
+msgid "Median"
+msgstr ""
+
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
+msgid "Merge events"
+msgstr ""
+
+msgid "Merge request"
+msgstr ""
+
+msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
+msgstr ""
+
+msgid "MergeRequest|Approved"
+msgstr ""
+
+msgid "Merged"
+msgstr ""
+
+msgid "Messages"
+msgstr ""
+
+msgid "Milestone"
+msgstr ""
+
+msgid "Milestones|Delete milestone"
+msgstr ""
+
+msgid "Milestones|Delete milestone %{milestoneTitle}?"
+msgstr ""
+
+msgid "Milestones|Failed to delete milestone %{milestoneTitle}"
+msgstr ""
+
+msgid "Milestones|Milestone %{milestoneTitle} was not found"
+msgstr ""
+
+msgid "MissingSSHKeyWarningLink|add an SSH key"
+msgstr ""
+
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
+msgid "Monitoring"
+msgstr ""
+
+msgid "More information"
+msgstr ""
+
+msgid "More information is available|here"
+msgstr ""
+
+msgid "Move"
+msgstr ""
+
+msgid "Move issue"
+msgstr ""
+
+msgid "Multiple issue boards"
+msgstr ""
+
+msgid "Name new label"
+msgstr ""
+
+msgid "New Issue"
+msgid_plural "New Issues"
+msgstr[0] ""
+
+msgid "New Kubernetes Cluster"
+msgstr ""
+
+msgid "New Kubernetes cluster"
+msgstr ""
+
+msgid "New Pipeline Schedule"
+msgstr ""
+
+msgid "New branch"
+msgstr ""
+
+msgid "New branch unavailable"
+msgstr ""
+
+msgid "New directory"
+msgstr ""
+
+msgid "New epic"
+msgstr ""
+
+msgid "New file"
+msgstr ""
+
+msgid "New group"
+msgstr ""
+
+msgid "New issue"
+msgstr ""
+
+msgid "New label"
+msgstr ""
+
+msgid "New merge request"
+msgstr ""
+
+msgid "New project"
+msgstr ""
+
+msgid "New schedule"
+msgstr ""
+
+msgid "New snippet"
+msgstr ""
+
+msgid "New subgroup"
+msgstr ""
+
+msgid "New tag"
+msgstr ""
+
+msgid "No assignee"
+msgstr ""
+
+msgid "No changes"
+msgstr ""
+
+msgid "No connection could be made to a Gitaly Server, please check your logs!"
+msgstr ""
+
+msgid "No due date"
+msgstr ""
+
+msgid "No estimate or time spent"
+msgstr ""
+
+msgid "No file chosen"
+msgstr ""
+
+msgid "No repository"
+msgstr ""
+
+msgid "No schedules"
+msgstr ""
+
+msgid "None"
+msgstr ""
+
+msgid "Not allowed to merge"
+msgstr ""
+
+msgid "Not available"
+msgstr ""
+
+msgid "Not confidential"
+msgstr ""
+
+msgid "Not enough data"
+msgstr ""
+
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
+msgid "Notification events"
+msgstr ""
+
+msgid "NotificationEvent|Close issue"
+msgstr ""
+
+msgid "NotificationEvent|Close merge request"
+msgstr ""
+
+msgid "NotificationEvent|Failed pipeline"
+msgstr ""
+
+msgid "NotificationEvent|Merge merge request"
+msgstr ""
+
+msgid "NotificationEvent|New issue"
+msgstr ""
+
+msgid "NotificationEvent|New merge request"
+msgstr ""
+
+msgid "NotificationEvent|New note"
+msgstr ""
+
+msgid "NotificationEvent|Reassign issue"
+msgstr ""
+
+msgid "NotificationEvent|Reassign merge request"
+msgstr ""
+
+msgid "NotificationEvent|Reopen issue"
+msgstr ""
+
+msgid "NotificationEvent|Successful pipeline"
+msgstr ""
+
+msgid "NotificationLevel|Custom"
+msgstr ""
+
+msgid "NotificationLevel|Disabled"
+msgstr ""
+
+msgid "NotificationLevel|Global"
+msgstr ""
+
+msgid "NotificationLevel|On mention"
+msgstr ""
+
+msgid "NotificationLevel|Participate"
+msgstr ""
+
+msgid "NotificationLevel|Watch"
+msgstr ""
+
+msgid "Notifications"
+msgstr ""
+
+msgid "Notifications off"
+msgstr ""
+
+msgid "Notifications on"
+msgstr ""
+
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
+msgid "Number of access attempts"
+msgstr ""
+
+msgid "OK"
+msgstr ""
+
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
+msgid "OfSearchInADropdown|Filter"
+msgstr ""
+
+msgid "Only project members can comment."
+msgstr ""
+
+msgid "Open"
+msgstr ""
+
+msgid "Opened"
+msgstr ""
+
+msgid "OpenedNDaysAgo|Opened"
+msgstr ""
+
+msgid "Opens in a new window"
+msgstr ""
+
+msgid "Options"
+msgstr ""
+
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
+msgid "Overview"
+msgstr ""
+
+msgid "Owner"
+msgstr ""
+
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
+msgid "Password"
+msgstr ""
+
+msgid "Pipeline"
+msgstr ""
+
+msgid "Pipeline Health"
+msgstr ""
+
+msgid "Pipeline Schedule"
+msgstr ""
+
+msgid "Pipeline Schedules"
+msgstr ""
+
+msgid "Pipeline quota"
+msgstr ""
+
+msgid "PipelineCharts|Failed:"
+msgstr ""
+
+msgid "PipelineCharts|Overall statistics"
+msgstr ""
+
+msgid "PipelineCharts|Success ratio:"
+msgstr ""
+
+msgid "PipelineCharts|Successful:"
+msgstr ""
+
+msgid "PipelineCharts|Total:"
+msgstr ""
+
+msgid "PipelineSchedules|Activated"
+msgstr ""
+
+msgid "PipelineSchedules|Active"
+msgstr ""
+
+msgid "PipelineSchedules|All"
+msgstr ""
+
+msgid "PipelineSchedules|Inactive"
+msgstr ""
+
+msgid "PipelineSchedules|Next Run"
+msgstr ""
+
+msgid "PipelineSchedules|None"
+msgstr ""
+
+msgid "PipelineSchedules|Provide a short description for this pipeline"
+msgstr ""
+
+msgid "PipelineSchedules|Take ownership"
+msgstr ""
+
+msgid "PipelineSchedules|Target"
+msgstr ""
+
+msgid "PipelineSchedules|Variables"
+msgstr ""
+
+msgid "PipelineSheduleIntervalPattern|Custom"
+msgstr ""
+
+msgid "Pipelines"
+msgstr ""
+
+msgid "Pipelines charts"
+msgstr ""
+
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
+msgid "Pipelines|Build with confidence"
+msgstr ""
+
+msgid "Pipelines|Get started with Pipelines"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|all"
+msgstr ""
+
+msgid "Pipeline|success"
+msgstr ""
+
+msgid "Pipeline|with stage"
+msgstr ""
+
+msgid "Pipeline|with stages"
+msgstr ""
+
+msgid "Play"
+msgstr ""
+
+msgid "Please <a href=%{link_to_billing} target=\"_blank\" rel=\"noopener noreferrer\">enable billing for one of your projects to be able to create a Kubernetes cluster</a>, then try again."
+msgstr ""
+
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
+msgid "Preferences"
+msgstr ""
+
+msgid "Primary"
+msgstr ""
+
+msgid "Private - Project access must be granted explicitly to each user."
+msgstr ""
+
+msgid "Private - The group and its projects can only be viewed by members."
+msgstr ""
+
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
+msgid "Profile"
+msgstr ""
+
+msgid "Profiles|Account scheduled for removal."
+msgstr ""
+
+msgid "Profiles|Delete Account"
+msgstr ""
+
+msgid "Profiles|Delete account"
+msgstr ""
+
+msgid "Profiles|Delete your account?"
+msgstr ""
+
+msgid "Profiles|Deleting an account has the following effects:"
+msgstr ""
+
+msgid "Profiles|Invalid password"
+msgstr ""
+
+msgid "Profiles|Invalid username"
+msgstr ""
+
+msgid "Profiles|Type your %{confirmationValue} to confirm:"
+msgstr ""
+
+msgid "Profiles|You don't have access to delete this user."
+msgstr ""
+
+msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
+msgstr ""
+
+msgid "Profiles|Your account is currently an owner in these groups:"
+msgstr ""
+
+msgid "Profiles|your account"
+msgstr ""
+
+msgid "Programming languages used in this repository"
+msgstr ""
+
+msgid "Project '%{project_name}' is in the process of being deleted."
+msgstr ""
+
+msgid "Project '%{project_name}' queued for deletion."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully created."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully updated."
+msgstr ""
+
+msgid "Project access must be granted explicitly to each user."
+msgstr ""
+
+msgid "Project avatar"
+msgstr ""
+
+msgid "Project avatar in repository: %{link}"
+msgstr ""
+
+msgid "Project cache successfully reset."
+msgstr ""
+
+msgid "Project details"
+msgstr ""
+
+msgid "Project export could not be deleted."
+msgstr ""
+
+msgid "Project export has been deleted."
+msgstr ""
+
+msgid "Project export link has expired. Please generate a new export from your project settings."
+msgstr ""
+
+msgid "Project export started. A download link will be sent by email."
+msgstr ""
+
+msgid "ProjectActivityRSS|Subscribe"
+msgstr ""
+
+msgid "ProjectCreationLevel|Allowed to create projects"
+msgstr ""
+
+msgid "ProjectCreationLevel|Default project creation protection"
+msgstr ""
+
+msgid "ProjectCreationLevel|Developers + Masters"
+msgstr ""
+
+msgid "ProjectCreationLevel|Masters"
+msgstr ""
+
+msgid "ProjectCreationLevel|No one"
+msgstr ""
+
+msgid "ProjectFeature|Disabled"
+msgstr ""
+
+msgid "ProjectFeature|Everyone with access"
+msgstr ""
+
+msgid "ProjectFeature|Only team members"
+msgstr ""
+
+msgid "ProjectFileTree|Name"
+msgstr ""
+
+msgid "ProjectLastActivity|Never"
+msgstr ""
+
+msgid "ProjectLifecycle|Stage"
+msgstr ""
+
+msgid "ProjectNetworkGraph|Graph"
+msgstr ""
+
+msgid "ProjectSettings|Contact an admin to change this setting."
+msgstr ""
+
+msgid "ProjectSettings|Only signed commits can be pushed to this repository."
+msgstr ""
+
+msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
+msgstr ""
+
+msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
+msgstr ""
+
+msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
+msgstr ""
+
+msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
+msgstr ""
+
+msgid "Projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Frequently visited"
+msgstr ""
+
+msgid "ProjectsDropdown|Loading projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Projects you visit often will appear here"
+msgstr ""
+
+msgid "ProjectsDropdown|Search your projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Something went wrong on our end."
+msgstr ""
+
+msgid "ProjectsDropdown|Sorry, no projects matched your search"
+msgstr ""
+
+msgid "ProjectsDropdown|This feature requires browser localStorage support"
+msgstr ""
+
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
+msgid "PrometheusService|Time-series monitoring service"
+msgstr ""
+
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
+msgid "Protip:"
+msgstr ""
+
+msgid "Public - The group and any public projects can be viewed without any authentication."
+msgstr ""
+
+msgid "Public - The project can be accessed without any authentication."
+msgstr ""
+
+msgid "Push Rules"
+msgstr ""
+
+msgid "Push events"
+msgstr ""
+
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
+msgid "PushRule|Committer restriction"
+msgstr ""
+
+msgid "Quick actions can be used in the issues description and comment boxes."
+msgstr ""
+
+msgid "Read more"
+msgstr ""
+
+msgid "Readme"
+msgstr ""
+
+msgid "RefSwitcher|Branches"
+msgstr ""
+
+msgid "RefSwitcher|Tags"
+msgstr ""
+
+msgid "Reference:"
+msgstr ""
+
+msgid "Register / Sign In"
+msgstr ""
+
+msgid "Registry"
+msgstr ""
+
+msgid "Related Commits"
+msgstr ""
+
+msgid "Related Deployed Jobs"
+msgstr ""
+
+msgid "Related Issues"
+msgstr ""
+
+msgid "Related Jobs"
+msgstr ""
+
+msgid "Related Merge Requests"
+msgstr ""
+
+msgid "Related Merged Requests"
+msgstr ""
+
+msgid "Remind later"
+msgstr ""
+
+msgid "Remove"
+msgstr ""
+
+msgid "Remove avatar"
+msgstr ""
+
+msgid "Remove project"
+msgstr ""
+
+msgid "Repair authentication"
+msgstr ""
+
+msgid "Repository"
+msgstr ""
+
+msgid "Repository has no locks."
+msgstr ""
+
+msgid "Request Access"
+msgstr ""
+
+msgid "Reset git storage health information"
+msgstr ""
+
+msgid "Reset health check access token"
+msgstr ""
+
+msgid "Reset runners registration token"
+msgstr ""
+
+msgid "Resolve discussion"
+msgstr ""
+
+msgid "Reveal value"
+msgid_plural "Reveal values"
+msgstr[0] ""
+
+msgid "Revert this commit"
+msgstr ""
+
+msgid "Revert this merge request"
+msgstr ""
+
+msgid "Roadmap"
+msgstr ""
+
+msgid "SSH Keys"
+msgstr ""
+
+msgid "Save changes"
+msgstr ""
+
+msgid "Save pipeline schedule"
+msgstr ""
+
+msgid "Save variables"
+msgstr ""
+
+msgid "Schedule a new pipeline"
+msgstr ""
+
+msgid "Schedules"
+msgstr ""
+
+msgid "Scheduling Pipelines"
+msgstr ""
+
+msgid "Scoped issue boards"
+msgstr ""
+
+msgid "Search branches and tags"
+msgstr ""
+
+msgid "Search milestones"
+msgstr ""
+
+msgid "Search project"
+msgstr ""
+
+msgid "Search users"
+msgstr ""
+
+msgid "Seconds before reseting failure information"
+msgstr ""
+
+msgid "Seconds to wait for a storage access attempt"
+msgstr ""
+
+msgid "Secret variables"
+msgstr ""
+
+msgid "Security report"
+msgstr ""
+
+msgid "Select Archive Format"
+msgstr ""
+
+msgid "Select a timezone"
+msgstr ""
+
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
+msgid "Select assignee"
+msgstr ""
+
+msgid "Select branch/tag"
+msgstr ""
+
+msgid "Select target branch"
+msgstr ""
+
+msgid "Selective synchronization"
+msgstr ""
+
+msgid "Send email"
+msgstr ""
+
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
+msgid "Server version"
+msgstr ""
+
+msgid "Service Templates"
+msgstr ""
+
+msgid "Service URL"
+msgstr ""
+
+msgid "Set a password on your account to pull or push via %{protocol}."
+msgstr ""
+
+msgid "Set up CI/CD"
+msgstr ""
+
+msgid "Set up Koding"
+msgstr ""
+
+msgid "SetPasswordToCloneLink|set a password"
+msgstr ""
+
+msgid "Settings"
+msgstr ""
+
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
+msgstr ""
+
+msgid "Show command"
+msgstr ""
+
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
+msgid "Showing %d event"
+msgid_plural "Showing %d events"
+msgstr[0] ""
+
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
+msgid "Snippets"
+msgstr ""
+
+msgid "Something went wrong on our end"
+msgstr ""
+
+msgid "Something went wrong on our end."
+msgstr ""
+
+msgid "Something went wrong trying to change the confidentiality of this issue"
+msgstr ""
+
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr ""
+
+msgid "Something went wrong when toggling the button"
+msgstr ""
+
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
+msgid "Something went wrong while fetching the projects."
+msgstr ""
+
+msgid "Something went wrong while fetching the registry list."
+msgstr ""
+
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
+msgid "Something went wrong. Please try again."
+msgstr ""
+
+msgid "Sort by"
+msgstr ""
+
+msgid "SortOptions|Access level, ascending"
+msgstr ""
+
+msgid "SortOptions|Access level, descending"
+msgstr ""
+
+msgid "SortOptions|Created date"
+msgstr ""
+
+msgid "SortOptions|Due date"
+msgstr ""
+
+msgid "SortOptions|Due later"
+msgstr ""
+
+msgid "SortOptions|Due soon"
+msgstr ""
+
+msgid "SortOptions|Label priority"
+msgstr ""
+
+msgid "SortOptions|Largest group"
+msgstr ""
+
+msgid "SortOptions|Largest repository"
+msgstr ""
+
+msgid "SortOptions|Last created"
+msgstr ""
+
+msgid "SortOptions|Last joined"
+msgstr ""
+
+msgid "SortOptions|Last updated"
+msgstr ""
+
+msgid "SortOptions|Least popular"
+msgstr ""
+
+msgid "SortOptions|Less weight"
+msgstr ""
+
+msgid "SortOptions|Milestone"
+msgstr ""
+
+msgid "SortOptions|Milestone due later"
+msgstr ""
+
+msgid "SortOptions|Milestone due soon"
+msgstr ""
+
+msgid "SortOptions|More weight"
+msgstr ""
+
+msgid "SortOptions|Most popular"
+msgstr ""
+
+msgid "SortOptions|Name"
+msgstr ""
+
+msgid "SortOptions|Name, ascending"
+msgstr ""
+
+msgid "SortOptions|Name, descending"
+msgstr ""
+
+msgid "SortOptions|Oldest created"
+msgstr ""
+
+msgid "SortOptions|Oldest joined"
+msgstr ""
+
+msgid "SortOptions|Oldest sign in"
+msgstr ""
+
+msgid "SortOptions|Oldest updated"
+msgstr ""
+
+msgid "SortOptions|Popularity"
+msgstr ""
+
+msgid "SortOptions|Priority"
+msgstr ""
+
+msgid "SortOptions|Recent sign in"
+msgstr ""
+
+msgid "SortOptions|Start later"
+msgstr ""
+
+msgid "SortOptions|Start soon"
+msgstr ""
+
+msgid "SortOptions|Weight"
+msgstr ""
+
+msgid "Source"
+msgstr ""
+
+msgid "Source (branch or tag)"
+msgstr ""
+
+msgid "Source code"
+msgstr ""
+
+msgid "Source is not available"
+msgstr ""
+
+msgid "Spam Logs"
+msgstr ""
+
+msgid "Specify the following URL during the Runner setup:"
+msgstr ""
+
+msgid "StarProject|Star"
+msgstr ""
+
+msgid "Starred projects"
+msgstr ""
+
+msgid "Start a %{new_merge_request} with these changes"
+msgstr ""
+
+msgid "Start the Runner!"
+msgstr ""
+
+msgid "Stopped"
+msgstr ""
+
+msgid "Storage"
+msgstr ""
+
+msgid "Subgroups"
+msgstr ""
+
+msgid "Switch branch/tag"
+msgstr ""
+
+msgid "System Hooks"
+msgstr ""
+
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
+
+msgid "Tags"
+msgstr ""
+
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+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 ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
+msgid "Target Branch"
+msgstr ""
+
+msgid "Team"
+msgstr ""
+
+msgid "Thanks! Don't show me this again"
+msgstr ""
+
+msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
+msgstr ""
+
+msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
+msgstr ""
+
+msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project."
+msgstr ""
+
+msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
+msgstr ""
+
+msgid "The collection of events added to the data gathered for that stage."
+msgstr ""
+
+msgid "The fork relationship has been removed."
+msgstr ""
+
+msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
+msgstr ""
+
+msgid "The maximum file size allowed is 200KB."
+msgstr ""
+
+msgid "The number of attempts GitLab will make to access a storage."
+msgstr ""
+
+msgid "The number of failures of after which GitLab will completely prevent access to the storage. The number of failures can be reset in the admin interface: %{link_to_health_page} or using the %{api_documentation_link}."
+msgstr ""
+
+msgid "The phase of the development lifecycle."
+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 ""
+
+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 ""
+
+msgid "The project can be accessed without any authentication."
+msgstr ""
+
+msgid "The repository for this project does not exist."
+msgstr ""
+
+msgid "The repository for this project is empty"
+msgstr ""
+
+msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
+msgstr ""
+
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
+msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
+msgstr ""
+
+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 ""
+
+msgid "The time in seconds GitLab will keep failure information. When no failures occur during this time, information about the mount is reset."
+msgstr ""
+
+msgid "The time in seconds GitLab will try to access storage. After this time a timeout error will be raised."
+msgstr ""
+
+msgid "The time in seconds between storage checks. When a previous check did complete yet, GitLab will skip a check."
+msgstr ""
+
+msgid "The time taken by each data entry gathered by that stage."
+msgstr ""
+
+msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
+msgstr ""
+
+msgid "There are no issues to show"
+msgstr ""
+
+msgid "There are no merge requests to show"
+msgstr ""
+
+msgid "There are problems accessing Git storage: "
+msgstr ""
+
+msgid "There was an error loading users activity calendar."
+msgstr ""
+
+msgid "There was an error saving your notification settings."
+msgstr ""
+
+msgid "There was an error subscribing to this label."
+msgstr ""
+
+msgid "There was an error when reseting email token."
+msgstr ""
+
+msgid "There was an error when subscribing to this label."
+msgstr ""
+
+msgid "There was an error when unsubscribing from this label."
+msgstr ""
+
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
+msgid "This directory"
+msgstr ""
+
+msgid "This is a confidential issue."
+msgstr ""
+
+msgid "This is the author's first Merge Request to this project."
+msgstr ""
+
+msgid "This issue is confidential"
+msgstr ""
+
+msgid "This issue is confidential and locked."
+msgstr ""
+
+msgid "This issue is locked."
+msgstr ""
+
+msgid "This job depends on a user to trigger its process. Often they are used to deploy code to production environments"
+msgstr ""
+
+msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
+msgstr ""
+
+msgid "This job has not been triggered yet"
+msgstr ""
+
+msgid "This job has not started yet"
+msgstr ""
+
+msgid "This job is in pending state and is waiting to be picked by a runner"
+msgstr ""
+
+msgid "This job requires a manual action"
+msgstr ""
+
+msgid "This means you can not push code until you create an empty repository or import existing one."
+msgstr ""
+
+msgid "This merge request is locked."
+msgstr ""
+
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
+msgid "This project"
+msgstr ""
+
+msgid "This repository"
+msgstr ""
+
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
+msgid "Time before an issue gets scheduled"
+msgstr ""
+
+msgid "Time before an issue starts implementation"
+msgstr ""
+
+msgid "Time between merge request creation and merge/close"
+msgstr ""
+
+msgid "Time tracking"
+msgstr ""
+
+msgid "Time until first merge request"
+msgstr ""
+
+msgid "TimeTrackingEstimated|Est"
+msgstr ""
+
+msgid "TimeTracking|Estimated:"
+msgstr ""
+
+msgid "TimeTracking|Spent"
+msgstr ""
+
+msgid "Timeago|%s days ago"
+msgstr ""
+
+msgid "Timeago|%s days remaining"
+msgstr ""
+
+msgid "Timeago|%s hours remaining"
+msgstr ""
+
+msgid "Timeago|%s minutes ago"
+msgstr ""
+
+msgid "Timeago|%s minutes remaining"
+msgstr ""
+
+msgid "Timeago|%s months ago"
+msgstr ""
+
+msgid "Timeago|%s months remaining"
+msgstr ""
+
+msgid "Timeago|%s seconds remaining"
+msgstr ""
+
+msgid "Timeago|%s weeks ago"
+msgstr ""
+
+msgid "Timeago|%s weeks remaining"
+msgstr ""
+
+msgid "Timeago|%s years ago"
+msgstr ""
+
+msgid "Timeago|%s years remaining"
+msgstr ""
+
+msgid "Timeago|1 day remaining"
+msgstr ""
+
+msgid "Timeago|1 hour remaining"
+msgstr ""
+
+msgid "Timeago|1 minute remaining"
+msgstr ""
+
+msgid "Timeago|1 month remaining"
+msgstr ""
+
+msgid "Timeago|1 week remaining"
+msgstr ""
+
+msgid "Timeago|1 year remaining"
+msgstr ""
+
+msgid "Timeago|Past due"
+msgstr ""
+
+msgid "Timeago|a day ago"
+msgstr ""
+
+msgid "Timeago|a month ago"
+msgstr ""
+
+msgid "Timeago|a week ago"
+msgstr ""
+
+msgid "Timeago|a year ago"
+msgstr ""
+
+msgid "Timeago|about %s hours ago"
+msgstr ""
+
+msgid "Timeago|about a minute ago"
+msgstr ""
+
+msgid "Timeago|about an hour ago"
+msgstr ""
+
+msgid "Timeago|in %s days"
+msgstr ""
+
+msgid "Timeago|in %s hours"
+msgstr ""
+
+msgid "Timeago|in %s minutes"
+msgstr ""
+
+msgid "Timeago|in %s months"
+msgstr ""
+
+msgid "Timeago|in %s seconds"
+msgstr ""
+
+msgid "Timeago|in %s weeks"
+msgstr ""
+
+msgid "Timeago|in %s years"
+msgstr ""
+
+msgid "Timeago|in 1 day"
+msgstr ""
+
+msgid "Timeago|in 1 hour"
+msgstr ""
+
+msgid "Timeago|in 1 minute"
+msgstr ""
+
+msgid "Timeago|in 1 month"
+msgstr ""
+
+msgid "Timeago|in 1 week"
+msgstr ""
+
+msgid "Timeago|in 1 year"
+msgstr ""
+
+msgid "Timeago|in a while"
+msgstr ""
+
+msgid "Timeago|less than a minute ago"
+msgstr ""
+
+msgid "Time|hr"
+msgid_plural "Time|hrs"
+msgstr[0] ""
+
+msgid "Time|min"
+msgid_plural "Time|mins"
+msgstr[0] ""
+
+msgid "Time|s"
+msgstr ""
+
+msgid "Tip:"
+msgstr ""
+
+msgid "Title"
+msgstr ""
+
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
+msgid "Todo"
+msgstr ""
+
+msgid "Toggle sidebar"
+msgstr ""
+
+msgid "ToggleButton|Toggle Status: OFF"
+msgstr ""
+
+msgid "ToggleButton|Toggle Status: ON"
+msgstr ""
+
+msgid "Total Time"
+msgstr ""
+
+msgid "Total test time for all commits/merges"
+msgstr ""
+
+msgid "Total: %{total}"
+msgstr ""
+
+msgid "Track activity with Contribution Analytics."
+msgstr ""
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Track time with quick actions"
+msgstr ""
+
+msgid "Trigger this manual action"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
+msgid "Unable to reset project cache."
+msgstr ""
+
+msgid "Unknown"
+msgstr ""
+
+msgid "Unlock"
+msgstr ""
+
+msgid "Unlock this %{issuableDisplayName}? <strong>Everyone</strong> will be able to comment."
+msgstr ""
+
+msgid "Unlocked"
+msgstr ""
+
+msgid "Unresolve discussion"
+msgstr ""
+
+msgid "Unstar"
+msgstr ""
+
+msgid "Up to date"
+msgstr ""
+
+msgid "Upgrade your plan to activate Advanced Global Search."
+msgstr ""
+
+msgid "Upgrade your plan to activate Contribution Analytics."
+msgstr ""
+
+msgid "Upgrade your plan to activate Group Webhooks."
+msgstr ""
+
+msgid "Upgrade your plan to activate Issue weight."
+msgstr ""
+
+msgid "Upgrade your plan to improve Issue boards."
+msgstr ""
+
+msgid "Upload New File"
+msgstr ""
+
+msgid "Upload file"
+msgstr ""
+
+msgid "Upload new avatar"
+msgstr ""
+
+msgid "UploadLink|click to upload"
+msgstr ""
+
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
+msgid "Use the following registration token during setup:"
+msgstr ""
+
+msgid "Use your global notification setting"
+msgstr ""
+
+msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
+msgstr ""
+
+msgid "View epics list"
+msgstr ""
+
+msgid "View file @ "
+msgstr ""
+
+msgid "View labels"
+msgstr ""
+
+msgid "View open merge request"
+msgstr ""
+
+msgid "View replaced file @ "
+msgstr ""
+
+msgid "VisibilityLevel|Internal"
+msgstr ""
+
+msgid "VisibilityLevel|Private"
+msgstr ""
+
+msgid "VisibilityLevel|Public"
+msgstr ""
+
+msgid "VisibilityLevel|Unknown"
+msgstr ""
+
+msgid "Want to see the data? Please ask an administrator for access."
+msgstr ""
+
+msgid "We could not verify that one of your projects on GCP has billing enabled. Please try again."
+msgstr ""
+
+msgid "We don't have enough data to show this stage."
+msgstr ""
+
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
+msgid "Web IDE"
+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 ""
+
+msgid "Weight"
+msgstr ""
+
+msgid "Wiki"
+msgstr ""
+
+msgid "WikiClone|Clone your wiki"
+msgstr ""
+
+msgid "WikiClone|Git Access"
+msgstr ""
+
+msgid "WikiClone|Install Gollum"
+msgstr ""
+
+msgid "WikiClone|It is recommended to install %{markdown} so that GFM features render locally:"
+msgstr ""
+
+msgid "WikiClone|Start Gollum and edit locally"
+msgstr ""
+
+msgid "WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title."
+msgstr ""
+
+msgid "WikiEdit|There is already a page with the same title in that path."
+msgstr ""
+
+msgid "WikiEmptyPageError|You are not allowed to create wiki pages"
+msgstr ""
+
+msgid "WikiHistoricalPage|This is an old version of this page."
+msgstr ""
+
+msgid "WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}."
+msgstr ""
+
+msgid "WikiHistoricalPage|history"
+msgstr ""
+
+msgid "WikiHistoricalPage|most recent version"
+msgstr ""
+
+msgid "WikiMarkdownDocs|More examples are in the %{docs_link}"
+msgstr ""
+
+msgid "WikiMarkdownDocs|documentation"
+msgstr ""
+
+msgid "WikiMarkdownTip|To link to a (new) page, simply type %{link_example}"
+msgstr ""
+
+msgid "WikiNewPagePlaceholder|how-to-setup"
+msgstr ""
+
+msgid "WikiNewPageTip|Tip: You can specify the full path for the new file. We will automatically create any missing directories."
+msgstr ""
+
+msgid "WikiNewPageTitle|New Wiki Page"
+msgstr ""
+
+msgid "WikiPageConfirmDelete|Are you sure you want to delete this page?"
+msgstr ""
+
+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 ""
+
+msgid "WikiPageCreate|Create %{page_title}"
+msgstr ""
+
+msgid "WikiPageEdit|Update %{page_title}"
+msgstr ""
+
+msgid "WikiPage|Page slug"
+msgstr ""
+
+msgid "WikiPage|Write your content or drag files here..."
+msgstr ""
+
+msgid "Wiki|Create Page"
+msgstr ""
+
+msgid "Wiki|Create page"
+msgstr ""
+
+msgid "Wiki|Edit Page"
+msgstr ""
+
+msgid "Wiki|Empty page"
+msgstr ""
+
+msgid "Wiki|More Pages"
+msgstr ""
+
+msgid "Wiki|New page"
+msgstr ""
+
+msgid "Wiki|Page history"
+msgstr ""
+
+msgid "Wiki|Page version"
+msgstr ""
+
+msgid "Wiki|Pages"
+msgstr ""
+
+msgid "Wiki|Wiki Pages"
+msgstr ""
+
+msgid "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 ""
+
+msgid "Withdraw Access Request"
+msgstr ""
+
+msgid "Write a commit message..."
+msgstr ""
+
+msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You can also create a project from the command line."
+msgstr ""
+
+msgid "You can also star a label to make it a priority label."
+msgstr ""
+
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
+msgstr ""
+
+msgid "You can move around the graph by using the arrow keys."
+msgstr ""
+
+msgid "You can only add files when you are on a branch"
+msgstr ""
+
+msgid "You can only edit files when you are on a branch"
+msgstr ""
+
+msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
+msgstr ""
+
+msgid "You cannot write to this read-only GitLab instance."
+msgstr ""
+
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
+msgid "You have reached your project limit"
+msgstr ""
+
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
+msgid "You must sign in to star a project"
+msgstr ""
+
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
+msgid "You need permission."
+msgstr ""
+
+msgid "You will not get any notifications via email"
+msgstr ""
+
+msgid "You will only receive notifications for the events you choose"
+msgstr ""
+
+msgid "You will only receive notifications for threads you have participated in"
+msgstr ""
+
+msgid "You will receive notifications for any activity"
+msgstr ""
+
+msgid "You will receive notifications only for comments in which you were @mentioned"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
+msgid "You'll need to use different branch names to get a valid comparison."
+msgstr ""
+
+msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
+msgstr ""
+
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
+msgid "Your comment will not be visible to the public."
+msgstr ""
+
+msgid "Your groups"
+msgstr ""
+
+msgid "Your name"
+msgstr ""
+
+msgid "Your projects"
+msgstr ""
+
+msgid "assign yourself"
+msgstr ""
+
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
+msgid "ciReport|Code quality"
+msgstr ""
+
+msgid "ciReport|DAST detected no alerts by analyzing the review app"
+msgstr ""
+
+msgid "ciReport|Failed to load %{reportName} report"
+msgstr ""
+
+msgid "ciReport|Fixed:"
+msgstr ""
+
+msgid "ciReport|Instances"
+msgstr ""
+
+msgid "ciReport|Learn more about whitelisting"
+msgstr ""
+
+msgid "ciReport|Loading %{reportName} report"
+msgstr ""
+
+msgid "ciReport|No changes to code quality"
+msgstr ""
+
+msgid "ciReport|No changes to performance metrics"
+msgstr ""
+
+msgid "ciReport|Performance metrics"
+msgstr ""
+
+msgid "ciReport|SAST"
+msgstr ""
+
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
+msgid "ciReport|SAST detected no security vulnerabilities"
+msgstr ""
+
+msgid "ciReport|SAST:container no vulnerabilities were found"
+msgstr ""
+
+msgid "ciReport|Show complete code vulnerabilities report"
+msgstr ""
+
+msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
+msgstr ""
+
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
+msgid "confidentiality|You are going to turn off the confidentiality. This means <strong>everyone</strong> will be able to see and leave a comment on this issue."
+msgstr ""
+
+msgid "confidentiality|You are going to turn on the confidentiality. This means that only team members with <strong>at least Reporter access</strong> are able to see and leave comments on the issue."
+msgstr ""
+
+msgid "day"
+msgid_plural "days"
+msgstr[0] ""
+
+msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
+msgstr ""
+
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
+msgid "merge request"
+msgid_plural "merge requests"
+msgstr[0] ""
+
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
+msgid "mrWidget|Cancel automatic merge"
+msgstr ""
+
+msgid "mrWidget|Check out branch"
+msgstr ""
+
+msgid "mrWidget|Checking ability to merge automatically"
+msgstr ""
+
+msgid "mrWidget|Cherry-pick"
+msgstr ""
+
+msgid "mrWidget|Cherry-pick this merge request in a new merge request"
+msgstr ""
+
+msgid "mrWidget|Closed"
+msgstr ""
+
+msgid "mrWidget|Closed by"
+msgstr ""
+
+msgid "mrWidget|Closes"
+msgstr ""
+
+msgid "mrWidget|Did not close"
+msgstr ""
+
+msgid "mrWidget|Email patches"
+msgstr ""
+
+msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
+msgstr ""
+
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
+msgid "mrWidget|Mentions"
+msgstr ""
+
+msgid "mrWidget|Merge"
+msgstr ""
+
+msgid "mrWidget|Merge failed."
+msgstr ""
+
+msgid "mrWidget|Merge locally"
+msgstr ""
+
+msgid "mrWidget|Merged by"
+msgstr ""
+
+msgid "mrWidget|Plain diff"
+msgstr ""
+
+msgid "mrWidget|Refresh"
+msgstr ""
+
+msgid "mrWidget|Refresh now"
+msgstr ""
+
+msgid "mrWidget|Refreshing now"
+msgstr ""
+
+msgid "mrWidget|Remove Source Branch"
+msgstr ""
+
+msgid "mrWidget|Remove source branch"
+msgstr ""
+
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
+msgid "mrWidget|Request to merge"
+msgstr ""
+
+msgid "mrWidget|Resolve conflicts"
+msgstr ""
+
+msgid "mrWidget|Revert"
+msgstr ""
+
+msgid "mrWidget|Revert this merge request in a new merge request"
+msgstr ""
+
+msgid "mrWidget|Set by"
+msgstr ""
+
+msgid "mrWidget|The changes were merged into"
+msgstr ""
+
+msgid "mrWidget|The changes were not merged into"
+msgstr ""
+
+msgid "mrWidget|The changes will be merged into"
+msgstr ""
+
+msgid "mrWidget|The source branch has been removed"
+msgstr ""
+
+msgid "mrWidget|The source branch is being removed"
+msgstr ""
+
+msgid "mrWidget|The source branch will be removed"
+msgstr ""
+
+msgid "mrWidget|The source branch will not be removed"
+msgstr ""
+
+msgid "mrWidget|There are merge conflicts"
+msgstr ""
+
+msgid "mrWidget|This merge request failed to be merged automatically"
+msgstr ""
+
+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 ""
+
+msgid "mrWidget|You can merge this merge request manually using the"
+msgstr ""
+
+msgid "mrWidget|You can remove source branch now"
+msgstr ""
+
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
+msgid "mrWidget|command line"
+msgstr ""
+
+msgid "mrWidget|into"
+msgstr ""
+
+msgid "mrWidget|to be merged automatically when the pipeline succeeds"
+msgstr ""
+
+msgid "new merge request"
+msgstr ""
+
+msgid "notification emails"
+msgstr ""
+
+msgid "or"
+msgstr ""
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] ""
+
+msgid "password"
+msgstr ""
+
+msgid "personal access token"
+msgstr ""
+
+msgid "remove due date"
+msgstr ""
+
+msgid "source"
+msgstr ""
+
+msgid "spendCommand|%{slash_command} will update the sum of the time spent."
+msgstr ""
+
+msgid "to help your contributors communicate effectively!"
+msgstr ""
+
+msgid "username"
+msgstr ""
+
+msgid "uses Kubernetes clusters to deploy your code!"
+msgstr ""
+
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index 62a6da1604a..0cb814ac59c 100644
--- a/locale/it/gitlab.po
+++ b/locale/it/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 04:00-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:21-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@@ -49,6 +49,9 @@ msgid_plural "%s additional commits have been omitted to prevent performance iss
msgstr[0] "%s commit aggiuntivo è stato omesso per evitare degradi di prestazioni negli issues."
msgstr[1] "%s commit aggiuntivi sono stati omessi per evitare degradi di prestazioni negli issues."
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -57,6 +60,9 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} partecipante"
msgstr[1] "%{count} partecipanti"
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr "%{number_commits_behind} commits precedenti %{default_branch}, %{number_commits_ahead} commits avanti"
@@ -66,6 +72,9 @@ msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. GitLab consenti
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. Gitlab non ritenterà automaticamente. Ripristina l'informazioni d'archiviazione quando il problema è risolto."
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}: tentativo d'accesso all'archiviazione fallito da parte dell'host:"
@@ -130,9 +139,15 @@ msgstr "Aggiungi Guida per contribuire"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "Aggiungi Licenza"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "Aggiungi una directory (cartella)"
@@ -151,12 +166,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr "Pagina di stato"
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -181,6 +229,12 @@ msgstr "Errore durante l'attivazione/disattivazione della sottoscrizione per l'i
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -190,12 +244,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr "Errore durante il recupero dei dati della barra laterale"
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -208,6 +286,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -232,15 +316,15 @@ msgstr "Progetto archiviato! La Repository è sola-lettura"
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Sei sicuro di voler cancellare questa pipeline programmata?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "Vuoi davvero ignorare le modifiche?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "Sei sicuro di voler ripristinare il token di registrazione?"
msgid "Are you sure you want to reset the health check token?"
msgstr "Confermi di voler resettare il token di controllo di stato?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "Sei sicuro?"
@@ -280,6 +364,9 @@ msgstr "Autore"
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -304,8 +391,14 @@ msgstr "Farà automaticamente le build, i test e i rilasci della tua applicazion
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "Approfondisci: %{link_to_documentation}"
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
-msgstr "Puoi attivare %{link_to_settings} per questo progetto."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr ""
msgid "Available"
msgstr "Disponibile"
@@ -316,6 +409,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -370,11 +466,8 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
msgstr[0] ""
msgstr[1] ""
@@ -669,6 +762,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr "api circuitbreaker"
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -723,6 +819,9 @@ msgstr "Copia URL API"
msgid "ClusterIntegration|Copy CA Certificate"
msgstr "Copia Certificato CA"
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -771,6 +870,9 @@ msgstr "Helm Tiller"
msgid "ClusterIntegration|Ingress"
msgstr "Ingresso"
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr "Installa"
@@ -822,9 +924,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -960,6 +1059,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "Commenti"
@@ -968,6 +1073,11 @@ msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Commit Message"
msgstr "Messaggio di commit"
@@ -980,6 +1090,9 @@ msgstr "Messaggio del commit"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "Commit"
@@ -1121,6 +1234,9 @@ msgstr "Copia URL negli appunti"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "Copia l'SHA del commit negli appunti"
@@ -1133,9 +1249,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "Crea una nuova cartella"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Creare un token di accesso sul tuo account per eseguire pull o push tramite %{protocol}"
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "Crea cartella"
@@ -1154,6 +1279,9 @@ msgstr ""
msgid "Create merge request"
msgstr "Crea una richiesta di merge"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr "Crea un nuova branch"
@@ -1178,6 +1306,12 @@ msgstr "Tag"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Crea token d'accesso personale"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1232,6 +1366,9 @@ msgstr "Dic"
msgid "December"
msgstr "Dicembre"
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Definisci un patter personalizzato mediante la sintassi cron"
@@ -1264,8 +1401,8 @@ msgstr "Nome cartella"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
-msgstr "Annulla modifiche"
+msgid "Discard draft"
+msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
@@ -1324,6 +1461,9 @@ msgstr "E-mail"
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr "Errore durante il fetch degli ambienti."
@@ -1378,9 +1518,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1447,12 +1596,36 @@ msgstr "Esplora progetti"
msgid "Explore public groups"
msgstr "Esplora gruppi pubblici"
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Impossibile cambiare owner"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "Impossibile rimuovere la pipeline pianificata"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr "Feb"
@@ -1468,6 +1641,9 @@ msgstr "Nome file"
msgid "Files"
msgstr "Files"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "Filtra per messaggio di commit"
@@ -1503,6 +1679,9 @@ msgstr "Dalla creazione di un issue fino al rilascio in produzione"
msgid "From merge request merge until deploy to production"
msgstr "Dalla richiesta di merge fino effettua il merge fino al rilascio in produzione"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr "Chiavi GPG"
@@ -1650,6 +1829,24 @@ msgstr "L'autenticazione Google non è %{link_to_documentation}. Richiedi al tuo
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr "Blocca la condivisione di un progetto di %{group} con altri gruppi"
@@ -1748,6 +1945,9 @@ msgstr "Cronologia"
msgid "Housekeeping successfully started"
msgstr "Housekeeping iniziato con successo"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "Importa repository"
@@ -1760,6 +1960,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr ""
@@ -1810,6 +2013,9 @@ msgstr "Gen"
msgid "January"
msgstr "Gennaio"
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr "Lug"
@@ -1840,6 +2046,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1887,6 +2096,12 @@ msgstr ""
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "Leggi di più su"
@@ -1905,6 +2120,9 @@ msgstr "Abbandona il progetto"
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1914,6 +2132,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1923,6 +2144,9 @@ msgstr "Bloccato"
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr "Login"
@@ -1953,9 +2177,6 @@ msgstr "Mediano"
msgid "Members"
msgstr "Membri"
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr "Richieste di merge"
@@ -1968,6 +2189,9 @@ msgstr "Richiesta di merge"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1992,9 +2216,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "aggiungi una chiave SSH"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr "Monitoraggio"
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr "Ulteriori informazioni sono disponibili | qui"
@@ -2090,9 +2323,6 @@ msgstr "Nessuna Repository"
msgid "No schedules"
msgstr "Nessuna pianificazione"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr "Nessuno"
@@ -2108,6 +2338,9 @@ msgstr ""
msgid "Not enough data"
msgstr "Dati insufficienti "
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "Notifica eventi"
@@ -2210,6 +2443,9 @@ msgstr "Si apre in una nuova finestra"
msgid "Options"
msgstr "Opzioni"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr "Panoramica"
@@ -2315,6 +2551,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "tutto"
@@ -2348,6 +2602,9 @@ msgstr "Privato - L'accesso al progetto deve essere fornito esplicitamente ad og
msgid "Private - The group and its projects can only be viewed by members."
msgstr "Privato - Il gruppo e i suoi progetti possono essere visualizzati solo dai membri."
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr "Profilo"
@@ -2510,12 +2767,30 @@ msgstr "Siamo spiacenti, non ci sono progetti che corrispondono alla tua ricerca
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Questa feature richiede il supporto del localStorage del browser"
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr "Di default, Prometheus è in ascolto su ‘http://localhost:9090‘. Non è consigliabile cambiare l'indirizzo e la porta di default in quanto ciò potrebbe influenzare o causare conflitto con altri servizi in esecuzione sul server GitLab."
msgid "PrometheusService|Finding and configuring metrics..."
msgstr "Ricerco e configuro le metriche..."
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr "Metriche"
@@ -2537,9 +2812,18 @@ msgstr "Nessuna metrica è stata monitorata. Per iniziare a monitorare, rilascia
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2558,6 +2842,12 @@ msgstr ""
msgid "Push events"
msgstr ""
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2621,6 +2911,9 @@ msgstr ""
msgid "Repository"
msgstr ""
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "Richiedi accesso"
@@ -2633,6 +2926,9 @@ msgstr ""
msgid "Reset runners registration token"
msgstr ""
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2644,6 +2940,9 @@ msgstr "Ripristina questo commit"
msgid "Revert this merge request"
msgstr "Ripristina questa richiesta di merge"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr "Chiavi SSH"
@@ -2689,12 +2988,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "Seleziona formato d'archivio"
msgid "Select a timezone"
msgstr "Seleziona una timezone"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2707,6 +3012,9 @@ msgstr "Seleziona una branch di destinazione"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr "Set"
@@ -2719,6 +3027,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Establezca una contraseña en su cuenta para actualizar o enviar a través de %{protocol}."
@@ -2728,15 +3039,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "Configura Koding"
-msgid "Set up auto deploy"
-msgstr "Configura il rilascio automatico"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "imposta una password"
msgid "Settings"
msgstr "Impostazioni"
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2746,6 +3057,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2787,12 +3101,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr "Qualcosa è andato storto durante il fetch dei progetti."
msgid "Something went wrong while fetching the registry list."
msgstr "Qualcosa è andato storto durante il recupero dell'elenco dei registri."
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2898,6 +3224,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "Codice Sorgente"
@@ -2937,8 +3266,8 @@ msgstr "Cambia branch/tag"
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
msgstr[0] ""
msgstr[1] ""
@@ -3071,9 +3400,15 @@ msgstr "Chiunque può accedere a questo progetto (senza alcuna autenticazione)."
msgid "The repository for this project does not exist."
msgstr "La repository di questo progetto non esiste."
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "Lo stadio di revisione mostra il tempo tra una richiesta di merge al suo svolgimento effettivo. Questo dato sarà disponibile appena avrai completato una MR (Merger Request)"
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "Lo stadio di pre-rilascio mostra il tempo che trascorre da una MR (Richiesta di Merge) completata al suo rilascio in ambiente di produzione. Questa informazione sarà disponibile dal tuo primo rilascio in produzione"
@@ -3167,6 +3502,9 @@ msgstr "Questo significa che non è possibile effettuare push di codice fino a c
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3336,9 +3674,15 @@ msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3354,19 +3698,16 @@ msgstr ""
msgid "Total Time"
msgstr "Tempo Totale"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "Tempo totale di test per tutti i commits/merges"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3378,9 +3719,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3396,6 +3734,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr ""
@@ -3441,6 +3782,9 @@ msgstr "Usa le tue impostazioni globali "
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3477,6 +3821,9 @@ msgstr "Non ci sono sufficienti dati da mostrare su questo stadio"
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3597,6 +3944,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "Ritira richiesta d'accesso"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Stai per rimuovere il gruppo %{group_name}. I gruppi rimossi NON POSSONO esser ripristinati! Sei ASSOLUTAMENTE sicuro?"
@@ -3609,10 +3959,13 @@ msgstr "Stai per rimuovere la relazione con il progetto sorgente %{forked_from_p
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Stai per trasferire %{project_name_with_namespace} ad un altro owner. Sei ASSOLUTAMENTE sicuro?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3630,12 +3983,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "Hai raggiunto il tuo limite di progetto"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "Devi accedere per porre una star al progetto"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "Necessiti del permesso."
@@ -3669,6 +4034,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3696,7 +4064,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3708,7 +4076,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3723,6 +4091,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3735,6 +4112,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3752,11 +4135,41 @@ msgstr[1] "giorni"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3790,6 +4203,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3823,6 +4239,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3877,6 +4296,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3924,3 +4346,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index 31c4422c928..180f1f0fbe7 100644
--- a/locale/ja/gitlab.po
+++ b/locale/ja/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 04:00-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:21-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Japanese\n"
"Language: ja_JP\n"
@@ -43,6 +43,9 @@ msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "パフォーマンス低下をé¿ã‘ã‚‹ãŸã‚ %s 個ã®ã‚³ãƒŸãƒƒãƒˆã‚’çœç•¥ã—ã¾ã—ãŸã€‚"
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -50,6 +53,9 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -59,6 +65,9 @@ msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr ""
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] ""
@@ -121,9 +130,15 @@ msgstr "貢献者å‘ã‘ガイドを追加"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "ライセンスを追加"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "æ–°è¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’追加"
@@ -142,12 +157,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -172,6 +220,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -181,12 +235,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -199,6 +277,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -223,15 +307,15 @@ msgstr "アーカイブ済ã¿ãƒ—ロジェクトï¼ï¼ˆãƒ¬ãƒã‚¸ãƒˆãƒªãƒ¼ã¯èª­ã¿
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "ã“ã®ãƒ‘イプラインスケジュールを削除ã—ã¾ã™ã‹ï¼Ÿ"
-msgid "Are you sure you want to discard your changes?"
-msgstr ""
-
msgid "Are you sure you want to reset registration token?"
msgstr ""
msgid "Are you sure you want to reset the health check token?"
msgstr ""
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr ""
@@ -271,6 +355,9 @@ msgstr ""
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -295,7 +382,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -307,6 +400,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -361,12 +457,9 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "ブランãƒ"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "<strong>%{branch_name}</strong> ブランãƒãŒä½œæˆã•ã‚Œã¾ã—ãŸã€‚自動デプロイを設定ã™ã‚‹ã«ã¯ã€GitLab CI Yaml テンプレートをé¸æŠžã—ã¦ã€å¤‰æ›´ã‚’コミットã—ã¦ãã ã•ã„。 %{link_to_autodeploy_doc}"
@@ -659,6 +752,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -713,6 +809,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -761,6 +860,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -812,9 +914,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -950,6 +1049,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr ""
@@ -957,6 +1062,10 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "コミット"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+
msgid "Commit Message"
msgstr ""
@@ -969,6 +1078,9 @@ msgstr "コミットメッセージ"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "コミット"
@@ -1110,6 +1222,9 @@ msgstr "クリップボードã«URLをコピー"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "コミットã®SHAをクリップボードã«ã‚³ãƒ”ー"
@@ -1122,9 +1237,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "æ–°è¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’作æˆ"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "%{protocol} ã§ãƒ—ッシュやプルã™ã‚‹ãŸã‚ã®ã‚ãªãŸå€‹äººç”¨ã‚¢ã‚¯ã‚»ã‚¹ãƒˆãƒ¼ã‚¯ãƒ³ã‚’作æˆ"
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "ディレクトリを作æˆ"
@@ -1143,6 +1267,9 @@ msgstr ""
msgid "Create merge request"
msgstr "マージリクエストを作æˆ"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr ""
@@ -1167,6 +1294,12 @@ msgstr "ã‚¿ã‚°"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "個人用アクセストークンを作æˆ"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1221,6 +1354,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Cron 構文ã§ã‚«ã‚¹ã‚¿ãƒ ãªãƒ‘ターンを指定ã™ã‚‹"
@@ -1252,7 +1388,7 @@ msgstr "ディレクトリå"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
+msgid "Discard draft"
msgstr ""
msgid "Discover GitLab Geo."
@@ -1312,6 +1448,9 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1366,9 +1505,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1435,12 +1583,36 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "オーナーを変更ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "パイプラインスケジュールを削除ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1456,6 +1628,9 @@ msgstr ""
msgid "Files"
msgstr "ファイル"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "コミットメッセージã§çµžã‚Šè¾¼ã¿"
@@ -1490,6 +1665,9 @@ msgstr "課題ãŒç™»éŒ²ã•ã‚Œã¦ã‹ã‚‰ãƒ—ロダクションã«ãƒ‡ãƒ—ロイã•ã‚Œ
msgid "From merge request merge until deploy to production"
msgstr "マージリクエストãŒãƒžãƒ¼ã‚¸ã•ã‚Œã¦ã‹ã‚‰ãƒ—ロダクションã«ãƒ‡ãƒ—ロイã•ã‚Œã‚‹ã¾ã§"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr ""
@@ -1637,6 +1815,24 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -1734,6 +1930,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr "ãƒã‚¦ã‚¹ã‚­ãƒ¼ãƒ”ングã¯æ­£å¸¸ã«èµ·å‹•ã—ã¾ã—ãŸã€‚"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "レãƒã‚¸ãƒˆãƒªãƒ¼ã‚’インãƒãƒ¼ãƒˆ"
@@ -1746,6 +1945,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr ""
@@ -1795,6 +1997,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1825,6 +2030,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1871,6 +2079,12 @@ msgstr ""
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "詳ã—ã見る:"
@@ -1889,6 +2103,9 @@ msgstr "プロジェクトを離脱"
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1898,6 +2115,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1907,6 +2127,9 @@ msgstr ""
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr ""
@@ -1937,9 +2160,6 @@ msgstr "中央値"
msgid "Members"
msgstr ""
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr ""
@@ -1952,6 +2172,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1976,9 +2199,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "SSH éµã‚’追加"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -2073,9 +2305,6 @@ msgstr "レãƒã‚¸ãƒˆãƒªãƒ¼ã¯ã‚ã‚Šã¾ã›ã‚“"
msgid "No schedules"
msgstr "スケジュールãªã—"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr ""
@@ -2091,6 +2320,9 @@ msgstr ""
msgid "Not enough data"
msgstr "データä¸è¶³"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "イベント通知"
@@ -2193,6 +2425,9 @@ msgstr ""
msgid "Options"
msgstr "オプション"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr ""
@@ -2298,6 +2533,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "全件"
@@ -2331,6 +2584,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr ""
@@ -2493,12 +2749,30 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2520,9 +2794,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2541,6 +2824,12 @@ msgstr ""
msgid "Push events"
msgstr ""
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2604,6 +2893,9 @@ msgstr ""
msgid "Repository"
msgstr ""
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "アクセス権é™ã‚’リクエストã™ã‚‹"
@@ -2616,6 +2908,9 @@ msgstr ""
msgid "Reset runners registration token"
msgstr ""
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2626,6 +2921,9 @@ msgstr "ã“ã®ã‚³ãƒŸãƒƒãƒˆã‚’リãƒãƒ¼ãƒˆ"
msgid "Revert this merge request"
msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’リãƒãƒ¼ãƒˆ"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2671,12 +2969,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "アーカイブã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã‚’é¸æŠž"
msgid "Select a timezone"
msgstr "タイムゾーンをé¸æŠž"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2689,6 +2993,9 @@ msgstr "ターゲットブランãƒã‚’é¸æŠž"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2701,6 +3008,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "%{protocol} プロコトル経由ã§ãƒ—ルã€ãƒ—ッシュã™ã‚‹ãŸã‚ã«ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®ãƒ‘スワードを設定。"
@@ -2710,15 +3020,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "Koding を設定"
-msgid "Set up auto deploy"
-msgstr "自動デプロイを設定"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "パスワードを設定"
msgid "Settings"
msgstr ""
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2728,6 +3038,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2768,12 +3081,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2879,6 +3204,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "ソースコード"
@@ -2918,9 +3246,9 @@ msgstr "ブランãƒãƒ»ã‚¿ã‚°åˆ‡ã‚Šæ›¿ãˆ"
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "ã‚¿ã‚°"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
msgid "Tags"
msgstr "ã‚¿ã‚°"
@@ -3051,9 +3379,15 @@ msgstr "プロジェクトã¯ã€ãƒ­ã‚°ã‚¤ãƒ³ãªã—ã«èª°ã§ã‚‚アクセスã§ã
msgid "The repository for this project does not exist."
msgstr "ã“ã®ãƒ—ロジェクトã«ãƒ¬ãƒã‚¸ãƒˆãƒªãƒ¼ã¯ã‚ã‚Šã¾ã›ã‚“。"
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "レビューステージã¨ã¯ã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’作æˆã—ã¦ã‹ã‚‰ãƒžãƒ¼ã‚¸ã™ã‚‹ã¾ã§ã®æ™‚é–“ã§ã™ã€‚ã“ã®ãƒ‡ãƒ¼ã‚¿ã¯æœ€åˆã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒãƒžãƒ¼ã‚¸ã•ã‚ŒãŸã¨ãã«è‡ªå‹•çš„ã«è¿½åŠ ã•ã‚Œã¾ã™ã€‚"
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "ステージングステージã§ã¯ã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒãƒžãƒ¼ã‚¸ã•ã‚Œã¦ã‹ã‚‰ã‚³ãƒ¼ãƒ‰ãŒãƒ—ロダクション環境ã«ãƒ‡ãƒ—ロイã•ã‚Œã‚‹ã¾ã§ã®æ™‚é–“ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®ãƒ‡ãƒ¼ã‚¿ã¯æœ€åˆã«ãƒ—ロダクションã«ãƒ‡ãƒ—ロイã—ãŸã¨ãã«è‡ªå‹•çš„ã«è¿½åŠ ã•ã‚Œã¾ã™ã€‚"
@@ -3147,6 +3481,9 @@ msgstr "空レãƒã‚¸ãƒˆãƒªãƒ¼ã‚’作æˆã¾ãŸã¯æ—¢å­˜ãƒ¬ãƒã‚¸ãƒˆãƒªãƒ¼ã‚’イン
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3314,9 +3651,15 @@ msgstr[0] "分"
msgid "Time|s"
msgstr "秒"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3332,19 +3675,16 @@ msgstr ""
msgid "Total Time"
msgstr "åˆè¨ˆæ™‚é–“"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "ã™ã¹ã¦ã®ã‚³ãƒŸãƒƒãƒˆ/マージã®åˆè¨ˆãƒ†ã‚¹ãƒˆæ™‚é–“"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3356,9 +3696,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3374,6 +3711,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "スターを外ã™"
@@ -3419,6 +3759,9 @@ msgstr "全体通知設定を利用"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3455,6 +3798,9 @@ msgstr "データä¸è¶³ã®ãŸã‚ã€ã“ã®ã‚¹ãƒ†ãƒ¼ã‚¸ã®è¡¨ç¤ºã¯ã§ãã¾ã›ã‚“
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3575,6 +3921,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "アクセスリクエストをå–り消ã™"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "%{group_name} グループを削除ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ 削除ã•ã‚ŒãŸã‚°ãƒ«ãƒ¼ãƒ—ã¯çµ¶å¯¾ã«å…ƒã«æˆ»ã›ã¾ã›ã‚“ï¼æœ¬å½“ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
@@ -3587,10 +3936,13 @@ msgstr "å…ƒã®ãƒ—ロジェクト (%{forked_from_project}) ã¨ã®ãƒªãƒ¬ãƒ¼ã‚·ãƒ§ã
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "%{project_name_with_namespace} プロジェクトを別ã®ã‚ªãƒ¼ãƒŠãƒ¼ã«ç§»è­²ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3608,12 +3960,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "プロジェクト数ã®ä¸Šé™ã«é”ã—ã¦ã„ã¾ã™"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "プロジェクトã«ã‚¹ã‚¿ãƒ¼ã‚’ã¤ã‘ãŸã„å ´åˆã¯ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "権é™ãŒå¿…è¦ã§ã™"
@@ -3647,6 +4011,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3674,7 +4041,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3686,7 +4053,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3701,6 +4068,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3713,6 +4089,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3729,10 +4111,40 @@ msgstr[0] "æ—¥"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3766,6 +4178,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3799,6 +4214,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3853,6 +4271,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3899,3 +4320,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index 73909e6f6de..13634091ed7 100644
--- a/locale/ko/gitlab.po
+++ b/locale/ko/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 04:00-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:19-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Korean\n"
"Language: ko_KR\n"
@@ -43,6 +43,9 @@ msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s 추가 ì»¤ë°‹ì€ ì„±ëŠ¥ ì´ìŠˆë¥¼ 방지하기 위해 ìƒëžµë˜ì—ˆìŠµë‹ˆë‹¤."
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -50,6 +53,9 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -59,6 +65,9 @@ msgstr "%{number_of_failures} / %{maximum_failures} 실패. GitLab ì€ ë‹¤ìŒ ì‹
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "%{number_of_failures} / %{maximum_failures} 실패. GitLab ì€ ìžë™ìœ¼ë¡œ 다시 ì‹œë„하지 않습니다. 문제가 í•´ê²°ë˜ë©´ 저장 공간 정보를 초기화 해주세요. "
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] ""
@@ -121,9 +130,15 @@ msgstr "기여 ê°€ì´ë“œ 추가"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "ë¼ì´ì„ ìŠ¤ 추가"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "새 디렉토리 추가"
@@ -142,12 +157,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -172,6 +220,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -181,12 +235,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -199,6 +277,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -223,15 +307,15 @@ msgstr "프로ì íŠ¸ê°€ ë³´ê´€ë˜ì—ˆìŠµë‹ˆë‹¤! 저장소는 ì½ê¸°ë§Œ 가능합ë
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "ì´ íŒŒì´í”„ë¼ì¸ ìŠ¤ì¼€ì¥´ì„ ì‚­ì œ 하시겠습니까?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "변경 ë‚´ìš©ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "ë“±ë¡ í† í°ì„ 초기화 하시겠습니까?"
msgid "Are you sure you want to reset the health check token?"
msgstr "헬스 ì²´í¬ í† í°ì„ 초기화 하시겠습니까?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "확실합니까?"
@@ -271,6 +355,9 @@ msgstr ""
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -295,7 +382,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -307,6 +400,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -361,12 +457,9 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "브랜치"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "<strong>%{branch_name}</strong> 브랜치가 ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤. ìžë™ ë°°í¬ë¥¼ 설정하려면 GitLab CI Yaml í…œí”Œë¦¿ì„ ì„ íƒí•˜ê³  변경 ì‚¬í•­ì„ ì ìš©í•˜ì‹­ì‹œì˜¤. %{link_to_autodeploy_doc}"
@@ -659,6 +752,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -713,6 +809,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -761,6 +860,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -812,9 +914,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -950,6 +1049,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr ""
@@ -957,6 +1062,10 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "커밋"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+
msgid "Commit Message"
msgstr ""
@@ -969,6 +1078,9 @@ msgstr "커밋 메시지"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "커밋"
@@ -1110,6 +1222,9 @@ msgstr "URLì„ í´ë¦½ë³´ë“œì— 복사"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "ì»¤ë°‹ì˜ SHA를 í´ë¦½ë³´ë“œë¡œ 복사합니다"
@@ -1122,9 +1237,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "새 디렉토리 만들기"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "%{protocol}ì„ (를) 통해 Pull 하거나 Push í•  ê°œì¸ ì•¡ì„¸ìŠ¤ 토í°ì„ 만드십시오."
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "디렉토리 만들기"
@@ -1143,6 +1267,9 @@ msgstr ""
msgid "Create merge request"
msgstr "머지 리퀘스트 만들기"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr ""
@@ -1167,6 +1294,12 @@ msgstr "태그"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "ê°œì¸ ì•¡ì„¸ìŠ¤ í† í° ë§Œë“¤ê¸°"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1221,6 +1354,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "cron êµ¬ë¬¸ì„ ì‚¬ìš©í•˜ì—¬ ì‚¬ìš©ìž ì •ì˜ íŒ¨í„´ ì •ì˜"
@@ -1252,8 +1388,8 @@ msgstr "디렉토리 ì´ë¦„"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
-msgstr "변경 내용 취소"
+msgid "Discard draft"
+msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
@@ -1312,6 +1448,9 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1366,9 +1505,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1435,12 +1583,36 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "소유ìžë¥¼ 변경하지 못했습니다"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "파ì´í”„ë¼ì¸ ìŠ¤ì¼€ì¤„ì„ ì œê±°í•˜ì§€ 못했습니다."
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1456,6 +1628,9 @@ msgstr ""
msgid "Files"
msgstr "파ì¼"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "커밋 메시지로 필터"
@@ -1490,6 +1665,9 @@ msgstr "ì´ìŠˆ ìƒì„±ì—ì„œ 프로ë•ì…˜ ë°°í¬ê¹Œì§€"
msgid "From merge request merge until deploy to production"
msgstr "머지 리퀘스트 머지ì—ì„œ 프로ë•ì…˜ í™˜ê²½ì— ë°°í¬ê¹Œì§€"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr ""
@@ -1637,6 +1815,24 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -1734,6 +1930,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr "Housekeepingì´ ì„±ê³µì ìœ¼ë¡œ 시작ë˜ì—ˆìŠµë‹ˆë‹¤"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "저장소 가져 오기"
@@ -1746,6 +1945,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "GitLab CI 와 호환ë˜ëŠ” Runner 설치"
@@ -1795,6 +1997,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1825,6 +2030,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1871,6 +2079,12 @@ msgstr "at"
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "ë” ìžì„¸ížˆ 알아보기"
@@ -1889,6 +2103,9 @@ msgstr "프로ì íŠ¸ì—ì„œ 나가기"
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1898,6 +2115,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1907,6 +2127,9 @@ msgstr ""
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr ""
@@ -1937,9 +2160,6 @@ msgstr "중앙값"
msgid "Members"
msgstr ""
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr ""
@@ -1952,6 +2172,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1976,9 +2199,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "SSH 키 추가"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr "여기"
@@ -2073,9 +2305,6 @@ msgstr "저장소 ì—†ìŒ"
msgid "No schedules"
msgstr "ì¼ì • ì—†ìŒ"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr ""
@@ -2091,6 +2320,9 @@ msgstr ""
msgid "Not enough data"
msgstr "ë°ì´í„°ê°€ 충분하지 않습니다."
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "알림 ì´ë²¤íŠ¸"
@@ -2193,6 +2425,9 @@ msgstr ""
msgid "Options"
msgstr "옵션 "
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr ""
@@ -2298,6 +2533,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "모ë‘"
@@ -2331,6 +2584,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr ""
@@ -2493,12 +2749,30 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2520,9 +2794,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2541,6 +2824,12 @@ msgstr ""
msgid "Push events"
msgstr "푸쉬 ì´ë²¤íŠ¸"
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2604,6 +2893,9 @@ msgstr ""
msgid "Repository"
msgstr ""
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "액세스 요청"
@@ -2616,6 +2908,9 @@ msgstr "헬스 ì²´í¬ ì ‘ê·¼ í† í° ì´ˆê¸°í™”"
msgid "Reset runners registration token"
msgstr "runner ë“±ë¡ í† í° ì´ˆê¸°í™”"
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2626,6 +2921,9 @@ msgstr "ì´ ì»¤ë°‹ ë˜ëŒë¦¬ê¸°"
msgid "Revert this merge request"
msgstr "ì´ ë¨¸ì§€ 리퀘스트 ë˜ëŒë¦¬ê¸°"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2671,12 +2969,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "ì•„ì¹´ì´ë¸Œ í¬ë§· ì„ íƒ"
msgid "Select a timezone"
msgstr "시간대 ì„ íƒ"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2689,6 +2993,9 @@ msgstr "ëŒ€ìƒ ë¸Œëžœì¹˜ ì„ íƒ"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2701,6 +3008,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "%{protocol} í”„ë¡œí† ì½œì„ í†µí•´ Pull 하거나 Push하려면 ê³„ì •ì— íŒ¨ìŠ¤ì›Œë“œë¥¼ 설정하십시오."
@@ -2710,15 +3020,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "Koding 설정"
-msgid "Set up auto deploy"
-msgstr "ìžë™ ë°°í¬ ì„¤ì •"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "패스워드 설정"
msgid "Settings"
msgstr ""
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2728,6 +3038,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2768,12 +3081,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2879,6 +3204,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "소스 코드"
@@ -2918,9 +3246,9 @@ msgstr "스위치 브랜치/태그"
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "태그"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
msgid "Tags"
msgstr "태그 "
@@ -3051,9 +3379,15 @@ msgstr "ì´ í”„ë¡œì íŠ¸ëŠ” ì¸ì¦ì—†ì´ 액세스 í•  수 있습니다."
msgid "The repository for this project does not exist."
msgstr "ì´ í”„ë¡œì íŠ¸ì˜ 저장소가 존재하지 않습니다."
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "Review 단계ì—서는 머지 리퀘스트를 작성한 후 ë¨¸ì§€í•˜ê¸°ê¹Œì§€ì˜ ì‹œê°„ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. ë°ì´í„°ëŠ” 첫 번째 머지 ë¦¬í€˜ìŠ¤íŠ¸ì„ ë¨¸ì§€ í•œ í›„ì— ìžë™ìœ¼ë¡œ 추가ë©ë‹ˆë‹¤."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "Staging 단계ì—서는 MR 머지과 프로ë•ì…˜ í™˜ê²½ì— ì½”ë“œ ë°°í¬ ì‚¬ì´ì˜ ì‹œê°„ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. ë°ì´í„°ë¥¼ Production í™˜ê²½ì— ì²˜ìŒ ë°°í¬í•˜ë©´ ë°ì´í„°ê°€ ìžë™ìœ¼ë¡œ 추가ë©ë‹ˆë‹¤."
@@ -3147,6 +3481,9 @@ msgstr "즉, 빈 저장소를 만들거나 기존 저장소를 가져올 때까ì
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3314,9 +3651,15 @@ msgstr[0] "분"
msgid "Time|s"
msgstr "ì´ˆ"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3332,19 +3675,16 @@ msgstr ""
msgid "Total Time"
msgstr "시간 합계:"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "모든 커밋 / ë¨¸ì§€ì˜ ì´ í…ŒìŠ¤íŠ¸ 시간"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3356,9 +3696,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3374,6 +3711,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "별표 제거"
@@ -3419,6 +3759,9 @@ msgstr "전체 알림 설정 사용"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3455,6 +3798,9 @@ msgstr "ì´ ë‹¨ê³„ë¥¼ ë³´ì—¬ì£¼ê¸°ì— ì¶©ë¶„í•œ ë°ì´í„°ê°€ 없습니다."
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3575,6 +3921,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "액세스 요청 철회"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "%{group_name} ê·¸ë£¹ì„ ì œê±°í•˜ë ¤ê³ í•©ë‹ˆë‹¤. \\\"ì •ë§ë¡œ\\\" 확실합니까?"
@@ -3587,10 +3936,13 @@ msgstr "í¬í¬ 관계를 소스 프로ì íŠ¸ %{forked_from_project}ì— ëŒ€í•´ ì 
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "%{project_name_with_namespace}ì„ ë‹¤ë¥¸ 소유ìžì—게 ì´ì „하려고합니다. \"ì •ë§ë¡œ\" 확실합니까?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3608,12 +3960,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "프로ì íŠ¸ ìˆ«ìž í•œë„ì— ë„달했습니다."
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "프로ì íŠ¸ì— 별표를 표시하려면 ë¡œê·¸ì¸ í•´ì•¼ 합니다."
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "ê¶Œí•œì´ í•„ìš”í•©ë‹ˆë‹¤."
@@ -3647,6 +4011,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3674,7 +4041,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3686,7 +4053,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3701,6 +4068,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3713,6 +4089,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3729,10 +4111,40 @@ msgstr[0] "ì¼"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3766,6 +4178,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3799,6 +4214,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3853,6 +4271,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3899,3 +4320,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index 451be6434db..ce3f2e5627e 100644
--- a/locale/nl_NL/gitlab.po
+++ b/locale/nl_NL/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 03:59-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:22-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
@@ -49,6 +49,9 @@ msgid_plural "%s additional commits have been omitted to prevent performance iss
msgstr[0] "%s andere commit is weggelaten om prestatieproblemen te voorkomen."
msgstr[1] "%s andere commits zijn weggelaten om prestatieproblemen te voorkomen."
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -57,6 +60,9 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -66,6 +72,9 @@ msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr ""
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] ""
@@ -130,9 +139,15 @@ msgstr ""
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "Licentie toevoegen"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "Nieuwe map toevoegen"
@@ -151,12 +166,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -181,6 +229,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -190,12 +244,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -208,6 +286,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -232,15 +316,15 @@ msgstr ""
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr ""
-msgid "Are you sure you want to discard your changes?"
-msgstr ""
-
msgid "Are you sure you want to reset registration token?"
msgstr ""
msgid "Are you sure you want to reset the health check token?"
msgstr ""
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr ""
@@ -280,6 +364,9 @@ msgstr "Auteur"
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -304,7 +391,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -316,6 +409,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -370,11 +466,8 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
msgstr[0] ""
msgstr[1] ""
@@ -669,6 +762,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -723,6 +819,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -771,6 +870,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -822,9 +924,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -960,6 +1059,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "Opmerkingen"
@@ -968,6 +1073,11 @@ msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Commit Message"
msgstr ""
@@ -980,6 +1090,9 @@ msgstr ""
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "Commit"
@@ -1121,6 +1234,9 @@ msgstr ""
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr ""
@@ -1133,9 +1249,18 @@ msgstr ""
msgid "Create New Directory"
msgstr ""
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr ""
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "Maak map aan"
@@ -1154,6 +1279,9 @@ msgstr ""
msgid "Create merge request"
msgstr ""
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr ""
@@ -1178,6 +1306,12 @@ msgstr ""
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr ""
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1232,6 +1366,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr ""
@@ -1264,7 +1401,7 @@ msgstr ""
msgid "Disable"
msgstr ""
-msgid "Discard changes"
+msgid "Discard draft"
msgstr ""
msgid "Discover GitLab Geo."
@@ -1324,6 +1461,9 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1378,9 +1518,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1447,12 +1596,36 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr ""
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr ""
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1468,6 +1641,9 @@ msgstr ""
msgid "Files"
msgstr ""
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr ""
@@ -1503,6 +1679,9 @@ msgstr ""
msgid "From merge request merge until deploy to production"
msgstr ""
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr ""
@@ -1650,6 +1829,24 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -1748,6 +1945,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr ""
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr ""
@@ -1760,6 +1960,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr ""
@@ -1810,6 +2013,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1840,6 +2046,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1887,6 +2096,12 @@ msgstr ""
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr ""
@@ -1905,6 +2120,9 @@ msgstr ""
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1914,6 +2132,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1923,6 +2144,9 @@ msgstr ""
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr ""
@@ -1953,9 +2177,6 @@ msgstr ""
msgid "Members"
msgstr ""
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr ""
@@ -1968,6 +2189,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1992,9 +2216,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr ""
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -2090,9 +2323,6 @@ msgstr ""
msgid "No schedules"
msgstr ""
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr ""
@@ -2108,6 +2338,9 @@ msgstr ""
msgid "Not enough data"
msgstr ""
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr ""
@@ -2210,6 +2443,9 @@ msgstr ""
msgid "Options"
msgstr ""
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr ""
@@ -2315,6 +2551,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr ""
@@ -2348,6 +2602,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr ""
@@ -2510,12 +2767,30 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2537,9 +2812,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2558,6 +2842,12 @@ msgstr ""
msgid "Push events"
msgstr ""
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2621,6 +2911,9 @@ msgstr ""
msgid "Repository"
msgstr ""
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr ""
@@ -2633,6 +2926,9 @@ msgstr ""
msgid "Reset runners registration token"
msgstr ""
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2644,6 +2940,9 @@ msgstr ""
msgid "Revert this merge request"
msgstr ""
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2689,12 +2988,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr ""
msgid "Select a timezone"
msgstr ""
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2707,6 +3012,9 @@ msgstr ""
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2719,6 +3027,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr ""
@@ -2728,15 +3039,15 @@ msgstr ""
msgid "Set up Koding"
msgstr ""
-msgid "Set up auto deploy"
-msgstr ""
-
msgid "SetPasswordToCloneLink|set a password"
msgstr ""
msgid "Settings"
msgstr ""
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2746,6 +3057,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2787,12 +3101,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2898,6 +3224,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -2937,8 +3266,8 @@ msgstr ""
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
msgstr[0] ""
msgstr[1] ""
@@ -3071,9 +3400,15 @@ msgstr ""
msgid "The repository for this project does not exist."
msgstr ""
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr ""
@@ -3167,6 +3502,9 @@ msgstr ""
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3336,9 +3674,15 @@ msgstr[1] ""
msgid "Time|s"
msgstr "s"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3354,10 +3698,10 @@ msgstr ""
msgid "Total Time"
msgstr ""
-msgid "Total issue time spent"
+msgid "Total test time for all commits/merges"
msgstr ""
-msgid "Total test time for all commits/merges"
+msgid "Total: %{total}"
msgstr ""
msgid "Track activity with Contribution Analytics."
@@ -3366,9 +3710,6 @@ msgstr ""
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
-msgid "Total: %{total}"
-msgstr ""
-
msgid "Track time with quick actions"
msgstr ""
@@ -3378,9 +3719,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3396,6 +3734,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr ""
@@ -3441,6 +3782,9 @@ msgstr ""
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3477,6 +3821,9 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3597,6 +3944,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr ""
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr ""
@@ -3609,10 +3959,13 @@ msgstr ""
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3630,12 +3983,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr ""
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr ""
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr ""
@@ -3669,6 +4034,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3696,7 +4064,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3708,7 +4076,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3723,6 +4091,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3735,6 +4112,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3752,11 +4135,41 @@ msgstr[1] ""
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3790,6 +4203,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3823,6 +4239,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3877,6 +4296,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3924,3 +4346,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index 9c5455eac67..8e414d0d07b 100644
--- a/locale/pl_PL/gitlab.po
+++ b/locale/pl_PL/gitlab.po
@@ -2,15 +2,15 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 04:01-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:21-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Polish\n"
"Language: pl_PL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"Plural-Forms: nplurals=4; plural=((n == 1) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || n%10 == 1 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 12 && n%100 <= 14)) ? 2 : 3));\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: gitlab-ee\n"
"X-Crowdin-Language: pl\n"
@@ -24,36 +24,45 @@ msgid_plural "%d commits"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "%d commit behind"
msgid_plural "%d commits behind"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "%d issue"
msgid_plural "%d issues"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "%d layer"
msgid_plural "%d layers"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "%d merge request"
msgid_plural "%d merge requests"
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] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -63,6 +72,10 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -73,11 +86,15 @@ msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr ""
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "%{text} is available"
msgstr ""
@@ -96,6 +113,7 @@ msgid_plural "%d pipelines"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "1st contribution!"
msgstr ""
@@ -139,9 +157,15 @@ msgstr ""
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr ""
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr ""
@@ -160,12 +184,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -190,6 +247,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -199,12 +262,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -217,6 +304,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -241,15 +334,15 @@ msgstr ""
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr ""
-msgid "Are you sure you want to discard your changes?"
-msgstr ""
-
msgid "Are you sure you want to reset registration token?"
msgstr ""
msgid "Are you sure you want to reset the health check token?"
msgstr ""
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr ""
@@ -289,6 +382,9 @@ msgstr ""
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -313,7 +409,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -325,6 +427,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -379,14 +484,12 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
@@ -679,6 +782,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -733,6 +839,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -781,6 +890,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -832,9 +944,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -970,6 +1079,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr ""
@@ -978,6 +1093,14 @@ msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
+
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
msgid "Commit Message"
msgstr ""
@@ -991,6 +1114,9 @@ msgstr ""
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr ""
@@ -1132,6 +1258,9 @@ msgstr ""
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr ""
@@ -1144,9 +1273,18 @@ msgstr ""
msgid "Create New Directory"
msgstr ""
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr ""
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr ""
@@ -1165,6 +1303,9 @@ msgstr ""
msgid "Create merge request"
msgstr ""
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr ""
@@ -1189,6 +1330,12 @@ msgstr ""
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr ""
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1243,6 +1390,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr ""
@@ -1254,6 +1404,7 @@ msgid_plural "Deploys"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Deploy Keys"
msgstr ""
@@ -1276,7 +1427,7 @@ msgstr ""
msgid "Disable"
msgstr ""
-msgid "Discard changes"
+msgid "Discard draft"
msgstr ""
msgid "Discover GitLab Geo."
@@ -1336,6 +1487,9 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1390,9 +1544,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1459,12 +1622,36 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr ""
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr ""
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1480,6 +1667,9 @@ msgstr ""
msgid "Files"
msgstr ""
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr ""
@@ -1500,6 +1690,7 @@ msgid_plural "Forks"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "ForkedFromProjectPath|Forked from"
msgstr ""
@@ -1516,6 +1707,9 @@ msgstr ""
msgid "From merge request merge until deploy to production"
msgstr ""
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr ""
@@ -1663,6 +1857,24 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -1755,6 +1967,7 @@ msgid_plural "Hide values"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "History"
msgstr ""
@@ -1762,6 +1975,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr ""
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr ""
@@ -1774,6 +1990,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr ""
@@ -1782,6 +2001,7 @@ msgid_plural "Instances"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Instance does not support multiple Kubernetes clusters"
msgstr ""
@@ -1825,6 +2045,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1855,6 +2078,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1875,6 +2101,7 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Last Pipeline"
msgstr ""
@@ -1903,6 +2130,12 @@ msgstr ""
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr ""
@@ -1921,6 +2154,9 @@ msgstr ""
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1930,6 +2166,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1939,6 +2178,9 @@ msgstr ""
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr ""
@@ -1969,9 +2211,6 @@ msgstr ""
msgid "Members"
msgstr ""
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr ""
@@ -1984,6 +2223,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -2008,9 +2250,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr ""
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -2031,6 +2282,7 @@ msgid_plural "New Issues"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "New Kubernetes Cluster"
msgstr ""
@@ -2107,9 +2359,6 @@ msgstr ""
msgid "No schedules"
msgstr ""
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr ""
@@ -2125,6 +2374,9 @@ msgstr ""
msgid "Not enough data"
msgstr ""
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr ""
@@ -2227,6 +2479,9 @@ msgstr ""
msgid "Options"
msgstr ""
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr ""
@@ -2332,6 +2587,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr ""
@@ -2365,6 +2638,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr ""
@@ -2527,12 +2803,30 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2554,9 +2848,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2575,6 +2878,12 @@ msgstr ""
msgid "Push events"
msgstr ""
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2638,6 +2947,9 @@ msgstr ""
msgid "Repository"
msgstr ""
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr ""
@@ -2650,11 +2962,15 @@ msgstr ""
msgid "Reset runners registration token"
msgstr ""
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Revert this commit"
msgstr ""
@@ -2662,6 +2978,9 @@ msgstr ""
msgid "Revert this merge request"
msgstr ""
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2707,12 +3026,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr ""
msgid "Select a timezone"
msgstr ""
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2725,6 +3050,9 @@ msgstr ""
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2737,6 +3065,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr ""
@@ -2746,15 +3077,15 @@ msgstr ""
msgid "Set up Koding"
msgstr ""
-msgid "Set up auto deploy"
-msgstr ""
-
msgid "SetPasswordToCloneLink|set a password"
msgstr ""
msgid "Settings"
msgstr ""
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2764,6 +3095,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2775,6 +3109,7 @@ msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Sidebar|Change weight"
msgstr ""
@@ -2806,12 +3141,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2917,6 +3264,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -2956,11 +3306,12 @@ msgstr ""
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Tags"
msgstr ""
@@ -3091,9 +3442,15 @@ msgstr ""
msgid "The repository for this project does not exist."
msgstr ""
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr ""
@@ -3187,6 +3544,9 @@ msgstr ""
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3348,19 +3708,27 @@ msgid_plural "Time|hrs"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Time|min"
msgid_plural "Time|mins"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Time|s"
msgstr ""
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3376,10 +3744,10 @@ msgstr ""
msgid "Total Time"
msgstr ""
-msgid "Total issue time spent"
+msgid "Total test time for all commits/merges"
msgstr ""
-msgid "Total test time for all commits/merges"
+msgid "Total: %{total}"
msgstr ""
msgid "Track activity with Contribution Analytics."
@@ -3388,9 +3756,6 @@ msgstr ""
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
-msgid "Total: %{total}"
-msgstr ""
-
msgid "Track time with quick actions"
msgstr ""
@@ -3400,9 +3765,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3418,6 +3780,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr ""
@@ -3463,6 +3828,9 @@ msgstr ""
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3499,6 +3867,9 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3619,6 +3990,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr ""
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr ""
@@ -3631,10 +4005,13 @@ msgstr ""
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3652,12 +4029,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr ""
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr ""
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr ""
@@ -3691,6 +4080,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3718,7 +4110,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3730,7 +4122,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3745,6 +4137,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3757,6 +4158,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3771,15 +4178,47 @@ msgid_plural "days"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
+
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3814,6 +4253,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3847,6 +4289,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3901,6 +4346,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3924,6 +4372,7 @@ msgid_plural "parents"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "password"
msgstr ""
@@ -3949,3 +4398,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 5aef8f45234..277552a8d02 100644
--- a/locale/pt_BR/gitlab.po
+++ b/locale/pt_BR/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 04:01-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:20-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Portuguese, Brazilian\n"
"Language: pt_BR\n"
@@ -49,6 +49,9 @@ msgid_plural "%s additional commits have been omitted to prevent performance iss
msgstr[0] "%s commit adicional foi omitido para prevenir problemas de performance."
msgstr[1] "%s commits adicionais foram omitidos para prevenir problemas de performance."
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -57,6 +60,9 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participante"
msgstr[1] "%{count} participantes"
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr "%{number_commits_behind} commits atrás de %{default_branch}, %{number_commits_ahead} commits à frente"
@@ -66,6 +72,9 @@ msgstr "%{number_of_failures} de %{maximum_failures} falhas. O GitLab permitirá
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "%{number_of_failures} de %{maximum_failures} falhas. O GitLab não tentará mais automaticamente. Redefina as informações de storage quando o problema for resolvido."
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}: falha na tentativa de acesso ao storage no host:"
@@ -130,9 +139,15 @@ msgstr "Adicionar Guia de contribuição"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr "Adicione o Webhooks de Grupos e GitLab Enterprise Edition."
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "Adicionar Licença"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "Adicionar novo diretório"
@@ -151,12 +166,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr "página de saúde"
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -181,6 +229,12 @@ msgstr "Erro ao modificar notificação de assinatura"
msgid "An error occurred when updating the issue weight"
msgstr "Um erro aconteceu ao atualizar o peso da issue"
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -190,12 +244,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr "Erro ao recuperar informações da barra lateral"
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -208,6 +286,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -232,15 +316,15 @@ msgstr "Projeto arquivado! O repositório é somente leitura"
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Tem certeza que deseja excluir este agendamento de pipeline?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "Você tem certeza que deseja descartar suas alterações?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "Você tem certeza que quer recriar o token de registro?"
msgid "Are you sure you want to reset the health check token?"
msgstr "Você tem certeza que quer reiniciar o token de status de saúde?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "Você tem certeza?"
@@ -280,6 +364,9 @@ msgstr "Autor"
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -304,8 +391,14 @@ msgstr "Ele gerará a build, testará e fará deploy de sua aplicação automati
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "Saiba mais em %{link_to_documentation}"
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
-msgstr "Você pode ativar %{link_to_settings} para esse projeto."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr ""
msgid "Available"
msgstr "Disponível"
@@ -316,6 +409,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr "Cobrança"
@@ -370,13 +466,10 @@ msgstr "pago %{price_per_year} anualmente"
msgid "BillingPlans|per user"
msgstr "por usuário"
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "Branch"
-msgstr[1] "Branches"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "O branch <strong>%{branch_name}</strong> foi criado. Para configurar o deploy automático, selecione um modelo de Yaml do GitLab CI e commit suas mudanças. %{link_to_autodeploy_doc}"
@@ -669,6 +762,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr "interruptor da api"
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -723,6 +819,9 @@ msgstr "Copiar URL da API"
msgid "ClusterIntegration|Copy CA Certificate"
msgstr "Copiar certificado CA"
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -771,6 +870,9 @@ msgstr "Helm Tiller"
msgid "ClusterIntegration|Ingress"
msgstr "Ingressar"
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr "Instalar"
@@ -822,9 +924,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "Leia mais sobre %{link_to_documentation}"
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -960,6 +1059,12 @@ msgstr "configurado corretamente"
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "Comentários"
@@ -968,6 +1073,11 @@ msgid_plural "Commits"
msgstr[0] "Commit"
msgstr[1] "Commits"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Commit Message"
msgstr "Mensagem de Commit"
@@ -980,6 +1090,9 @@ msgstr "Mensagem de commit"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "Commit"
@@ -1121,6 +1234,9 @@ msgstr "Copiar URL para área de transferência"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "Copiar SHA do commit para a área de transferência"
@@ -1133,9 +1249,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "Criar Novo Diretório"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Crie um token de acesso pessoal na sua conta para dar pull ou push via %{protocol}."
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "Criar diretório"
@@ -1154,6 +1279,9 @@ msgstr ""
msgid "Create merge request"
msgstr "Criar merge request"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr "Criar novo branch"
@@ -1178,6 +1306,12 @@ msgstr "Tag"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "criar um token de acesso pessoal"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr "Criando épico"
@@ -1232,6 +1366,9 @@ msgstr "Dez"
msgid "December"
msgstr "Dezembro"
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Defina um padrão personalizado utilizando a sintaxe do cron"
@@ -1264,8 +1401,8 @@ msgstr "Nome do diretório"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
-msgstr "Descartar alterações"
+msgid "Discard draft"
+msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
@@ -1324,6 +1461,9 @@ msgstr "Emails"
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr "Um erro ocorreu ao recuperar ambientes."
@@ -1378,9 +1518,18 @@ msgstr "Épico será removido! Tem certeza?"
msgid "Epics"
msgstr "Épicos"
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr "Epics permite que você gerencie seu portfólio de projetos de forma mais eficiente e com menos esforço"
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr "Erro ao criar épico"
@@ -1447,12 +1596,36 @@ msgstr "Explorar projetos"
msgid "Explore public groups"
msgstr "Explorar grupos públicos"
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Erro ao alterar o proprietário"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "Erro ao excluir o agendamento do pipeline"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr "Fev"
@@ -1468,6 +1641,9 @@ msgstr "Nome do arquivo"
msgid "Files"
msgstr "Arquivos"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "Filtrar por mensagem de commit"
@@ -1503,6 +1679,9 @@ msgstr "Da abertura de tarefas até a implantação para a produção"
msgid "From merge request merge until deploy to production"
msgstr "Do merge request até a implantação em produção"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr "Chaves GPG"
@@ -1650,6 +1829,24 @@ msgstr "Autenticação do Google não está %{link_to_documentation}. Peça ao a
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr "Bloquear compartilhamento de projetos do grupo %{group} com outros grupos"
@@ -1748,6 +1945,9 @@ msgstr "Histórico"
msgid "Housekeeping successfully started"
msgstr "Manutenção iniciada com sucesso"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "Importar repositório"
@@ -1760,6 +1960,9 @@ msgstr "Melhore a gerência de issues com pesos no GitLab Enterprise Edition."
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr "Encontre o que precisa mais facilmente com a pesquisa global avançada com GitLab Enterprise Edition."
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "Instalar um Runner compatível com o GitLab CI"
@@ -1810,6 +2013,9 @@ msgstr "Jan"
msgid "January"
msgstr "Janeiro"
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr "Jul"
@@ -1840,6 +2046,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1887,6 +2096,12 @@ msgstr "em"
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "Saiba mais em"
@@ -1905,6 +2120,9 @@ msgstr "Sair do projeto"
msgid "License"
msgstr "Licença"
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1914,6 +2132,9 @@ msgstr "Bloquear"
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1923,6 +2144,9 @@ msgstr "Bloqueado"
msgid "Locked Files"
msgstr "Arquivos bloqueados"
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr "Entrar"
@@ -1953,9 +2177,6 @@ msgstr "Mediana"
msgid "Members"
msgstr "Membros"
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr "Merge Requests"
@@ -1968,6 +2189,9 @@ msgstr "Merge requests"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1992,9 +2216,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "adicione uma chave SSH"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr "Monitoramento"
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr "Mais informações estão disponíveis|aqui"
@@ -2090,9 +2323,6 @@ msgstr "Nenhum repositório"
msgid "No schedules"
msgstr "Nenhum agendamento"
-msgid "No time spent"
-msgstr "Nenhum tempo gasto"
-
msgid "None"
msgstr "Nenhum"
@@ -2108,6 +2338,9 @@ msgstr ""
msgid "Not enough data"
msgstr "Dados insuficientes"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "Eventos de notificação"
@@ -2210,6 +2443,9 @@ msgstr "Abrir em nova janela"
msgid "Options"
msgstr "Opções"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr "Visão geral"
@@ -2315,6 +2551,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "todos"
@@ -2348,6 +2602,9 @@ msgstr "Privado - O acesso ao projeto deve ser concedido explicitamente para cad
msgid "Private - The group and its projects can only be viewed by members."
msgstr "Privado - O grupo e seus projetos só podem ser vistos por seus membros."
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr "Perfil"
@@ -2510,12 +2767,30 @@ msgstr "Desculpe, nenhum projeto corresponde a sua pesquisa"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Esta funcionalidade necessita de suporte à localStorage do navegador"
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr "Por padrão, Prometheus escuta em 'http://localhost:9090'. Não é recomendado mudar o endereço padrão e sua porta, porque pode conflitar com outros serviços que estão executando no sevidor do Gitlab."
msgid "PrometheusService|Finding and configuring metrics..."
msgstr "Encontrando e configurando métricas..."
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr "Métricas"
@@ -2537,9 +2812,18 @@ msgstr "Nenhuma métrica está sendo monitorada. Para inicar o monitoramento, fa
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr "URL da API base do Prometheus. como http://prometheus.example.com/"
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr "Ver ambientes"
@@ -2558,6 +2842,12 @@ msgstr "Regras de push"
msgid "Push events"
msgstr "Eventos de push"
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr "Restrição de commit"
@@ -2621,6 +2911,9 @@ msgstr ""
msgid "Repository"
msgstr "Repositório"
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "Solicitar acesso"
@@ -2633,6 +2926,9 @@ msgstr "Recriar o token de status de saúde"
msgid "Reset runners registration token"
msgstr "Recriar o token de registro de runners"
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2644,6 +2940,9 @@ msgstr "Reverter este commit"
msgid "Revert this merge request"
msgstr "Reverter esse merge request"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr "Chaves SSH"
@@ -2689,12 +2988,18 @@ msgstr "Segundo de espera para tentativa de acesso ao storage"
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "Selecionar Formato do Arquivo"
msgid "Select a timezone"
msgstr "Selecionar fuso horário"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2707,6 +3012,9 @@ msgstr "Selecionar branch de destino"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr "Set"
@@ -2719,6 +3027,9 @@ msgstr ""
msgid "Service Templates"
msgstr "Modelos de serviço"
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Defina uma senha para sua conta para aceitar ou entregar código via %{protocol}."
@@ -2728,15 +3039,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "Configurar Koding"
-msgid "Set up auto deploy"
-msgstr "Configurar implantação automática"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "defina uma senha"
msgid "Settings"
msgstr "Configurações"
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2746,6 +3057,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr "Mostrar páginas acima"
@@ -2787,12 +3101,24 @@ msgstr "Algo deu errado ao tentar mudar o estado de ${this.issuableDisplayName}"
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr "Algo deu errado ao recuperar os projetos."
msgid "Something went wrong while fetching the registry list."
msgstr "Algo deu errado ao recuperar a lista de registro."
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2898,6 +3224,9 @@ msgstr "Peso"
msgid "Source"
msgstr "Origem"
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "Código-fonte"
@@ -2937,10 +3266,10 @@ msgstr "Trocar branch/tag"
msgid "System Hooks"
msgstr "Hooks do sistema"
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "Tag"
-msgstr[1] "Tags"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
+msgstr[1] ""
msgid "Tags"
msgstr "Tags"
@@ -3071,9 +3400,15 @@ msgstr "O projeto pode ser acessado sem a necessidade de autenticação."
msgid "The repository for this project does not exist."
msgstr "Não existe repositório para este projeto."
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "A etapa de revisão mostra o tempo de criação de uma solicitação de incorporação até sua aceitação. Os dados serão automaticamente adicionados depois que sua primeira solicitação de incorporação for aceita."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "A etapa de homologação mostra o tempo entre o aceite da solicitação de incorporação e a implantação do código no ambiente de produção. Os dados serão automaticamente adicionados depois que você implantar em produção pela primeira vez."
@@ -3167,6 +3502,9 @@ msgstr "Isto significa que você não pode entregar código até que crie um rep
msgid "This merge request is locked."
msgstr "Esse merge request está bloqueado."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3336,9 +3674,15 @@ msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr "Título"
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3354,21 +3698,18 @@ msgstr ""
msgid "Total Time"
msgstr "Tempo Total"
-msgid "Total issue time spent"
-msgstr "Tempo total gasto"
-
msgid "Total test time for all commits/merges"
msgstr "Tempo de teste total para todos os commits/merges"
+msgid "Total: %{total}"
+msgstr ""
+
msgid "Track activity with Contribution Analytics."
msgstr "Acompanhe a atividade com o Contribution Analytics."
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr "Acompanhe grupos de questões que compartilhem um tema, em projetos e milestones"
-msgid "Total: %{total}"
-msgstr ""
-
msgid "Track time with quick actions"
msgstr ""
@@ -3378,9 +3719,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr "Ativar Service Desk"
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3396,6 +3734,9 @@ msgstr ""
msgid "Unlocked"
msgstr "Desbloqueado"
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "Desmarcar"
@@ -3441,6 +3782,9 @@ msgstr "Utilizar configuração de notificação global"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr "Ver arquivo @ "
@@ -3477,6 +3821,9 @@ msgstr "Esta etapa não possui dados suficientes para exibição."
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 "Web IDE"
+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 "Webhooks permitem que você acione uma URL se, por exemplo, quando um novo código for feito push ou uma nova issue criada. Você pode configurar os webhooks para escutar eventos específicos como push, issue ou merge request. Webhooks de grupo aplicarão para todos os projetos no grupo, permitindo você padronizar o funcionamento em todo o grupo."
@@ -3597,6 +3944,9 @@ msgstr "Com a análise de contribuição, você pode ter uma visão geral da ati
msgid "Withdraw Access Request"
msgstr "Remover Requisição de Acesso"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Você vai remover %{group_name}. Grupos removidos NÃO PODEM ser restaurados! Você está ABSOLUTAMENTE certo?"
@@ -3609,10 +3959,13 @@ msgstr "Você está prestes a remover a relação de fork do projeto original %{
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Você irá transferir %{project_name_with_namespace} para outro proprietário. Tem certeza ABSOLUTA?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3630,12 +3983,24 @@ msgstr "Você não pode escrever numa instância secundária de somente leitura
msgid "You cannot write to this read-only GitLab instance."
msgstr "Você não pode escrever nesta instância somente-leitura do GitLab."
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "Você atingiu o limite de seu projeto"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "Você deve estar autenticado para marcar um projeto"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "Você precisa de permissão."
@@ -3669,6 +4034,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr "Seu comentário não estará visível ao público."
@@ -3696,7 +4064,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3708,7 +4076,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3723,6 +4091,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3735,6 +4112,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr "commit"
@@ -3752,11 +4135,41 @@ msgstr[1] "dias"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3790,6 +4203,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3823,6 +4239,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3877,6 +4296,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3924,3 +4346,6 @@ msgstr "nome do usuário"
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index 0adb8e5b716..6214460fc21 100644
--- a/locale/ru/gitlab.po
+++ b/locale/ru/gitlab.po
@@ -2,15 +2,15 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 04:01-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:53-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Russian\n"
"Language: ru_RU\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: gitlab-ee\n"
"X-Crowdin-Language: ru\n"
@@ -24,36 +24,45 @@ msgid_plural "%d commits"
msgstr[0] "%d коммит"
msgstr[1] "%d коммита"
msgstr[2] "%d коммитов"
+msgstr[3] "%d коммитов"
msgid "%d commit behind"
msgid_plural "%d commits behind"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "на %d коммит позади"
+msgstr[1] "на %d коммита позади"
+msgstr[2] "на %d коммитов позади"
+msgstr[3] "на %d коммитов позади"
msgid "%d issue"
msgid_plural "%d issues"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d обÑуждение"
+msgstr[1] "%d обÑуждений"
+msgstr[2] "%d обÑуждений"
+msgstr[3] "%d обÑуждений"
msgid "%d layer"
msgid_plural "%d layers"
msgstr[0] "%d Ñлой"
msgstr[1] "%d ÑлоÑ"
-msgstr[2] "%d Ñлоёв"
+msgstr[2] "%d Ñлоев"
+msgstr[3] "%d Ñлоёв"
msgid "%d merge request"
msgid_plural "%d merge requests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
+msgstr[1] "%d запроÑа на ÑлиÑние"
+msgstr[2] "%d запроÑов на ÑлиÑние"
+msgstr[3] "%d запроÑов на ÑлиÑние"
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
-msgstr[0] "%s добавленный коммит был иÑключен Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
-msgstr[1] "%s добавленных коммита были иÑключены Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
-msgstr[2] "%s добавленных коммитов были иÑключены Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
+msgstr[0] "%s дополнительный коммит был пропущен Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
+msgstr[1] "%s дополнительных коммита было пропущено Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
+msgstr[2] "%s дополнительных коммитов было пропущено Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
+msgstr[3] "%s дополнительных коммитов было пропущено Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
+
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -63,6 +72,10 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} учаÑтник"
msgstr[1] "%{count} учаÑтника"
msgstr[2] "%{count} учаÑтников"
+msgstr[3] "%{count} учаÑтников"
+
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr "на %{number_commits_behind} коммитов позади %{default_branch}, на %{number_commits_ahead} коммитов впереди"
@@ -73,11 +86,15 @@ msgstr "%{number_of_failures} из %{maximum_failures} возможных неу
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "%{number_of_failures} из %{maximum_failures} возможных неудачных попыток. GitLab не будет автоматичеÑки повторÑÑ‚ÑŒ попытку. СброÑьте информацию хранилища поÑле уÑÑ‚Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ñ‹."
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}: Ð½ÐµÑƒÐ´Ð°Ñ‡Ð½Ð°Ñ Ð¿Ð¾Ð¿Ñ‹Ñ‚ÐºÐ° доÑтупа к хранилищу на хоÑте:"
-msgstr[1] "%{storage_name}: %{failed_attempts} - неудачные попытки доÑтупа к хранилищу:"
-msgstr[2] "%{storage_name}: %{failed_attempts} - неудачные попытки доÑтупа к хранилищу:"
+msgstr[1] "%{storage_name}: %{failed_attempts} неудачные попытки доÑтупа к хранилищу:"
+msgstr[2] "%{storage_name}: %{failed_attempts} неудачных попыток доÑтупа к хранилищу:"
+msgstr[3] "%{storage_name}: %{failed_attempts} неудачных попыток доÑтупа к хранилищу:"
msgid "%{text} is available"
msgstr "%{text} доÑтупен"
@@ -96,6 +113,7 @@ msgid_plural "%d pipelines"
msgstr[0] "1 ÑÐ±Ð¾Ñ€Ð¾Ñ‡Ð½Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ"
msgstr[1] "%d Ñборочных линии"
msgstr[2] "%d Ñборочных линий"
+msgstr[3] "%d Ñборочных линий"
msgid "1st contribution!"
msgstr "Первый вклад!"
@@ -139,9 +157,15 @@ msgstr "Добавить РуководÑтво учаÑтника"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr "Добавить групповые веб-обработчики и GitLab Enterprise Edition."
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "Добавить Лицензию"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "Добавить новый каталог"
@@ -149,23 +173,56 @@ msgid "Add todo"
msgstr ""
msgid "AdminArea|Stop all jobs"
-msgstr ""
+msgstr "ОÑтановить вÑе заданиÑ"
msgid "AdminArea|Stop all jobs?"
-msgstr ""
+msgstr "ОÑтановить вÑе заданиÑ?"
msgid "AdminArea|Stop jobs"
-msgstr ""
+msgstr "ОÑтановить заданиÑ"
msgid "AdminArea|Stopping jobs failed"
-msgstr ""
+msgstr "ОÑтановка заданий не удалаÑÑŒ"
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
-msgstr ""
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
+msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ оÑтановить вÑе заданиÑ. Это дейÑтвие оÑтановит вÑе текущие заданиÑ, находÑщиеÑÑ Ð² процеÑÑе выполнениÑ."
msgid "AdminHealthPageLink|health page"
msgstr "Ñтраница работоÑпоÑобноÑти"
+msgid "AdminProjects|Delete"
+msgstr "Удалить"
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr "Удалить Проект %{projectName}?"
+
+msgid "AdminProjects|Delete project"
+msgstr "Удалить проект"
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr "Заблокировать пользователÑ"
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr "Удалить ÐŸÐ¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %{username} и внеÑённые им Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ?"
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr "Удалить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %{username} ?"
+
+msgid "AdminUsers|Delete user"
+msgstr "Удалить пользователÑ"
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr "Удалить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ внеÑённые им изменениÑ"
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr "Ð”Ð»Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ, введите %{projectName}"
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr "Ð”Ð»Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ, введите %{username}"
+
msgid "Advanced"
msgstr ""
@@ -182,7 +239,7 @@ msgid "Allows you to add and manage Kubernetes clusters."
msgstr ""
msgid "An error occurred previewing the blob"
-msgstr ""
+msgstr "Произошла ошибка при предварительном проÑмотре объекта"
msgid "An error occurred when toggling the notification subscription"
msgstr "Произошла ошибка при переключении подпиÑки на оповещениÑ"
@@ -190,35 +247,71 @@ msgstr "Произошла ошибка при переключении подп
msgid "An error occurred when updating the issue weight"
msgstr "Произошла ошибка при обновлении веÑа обÑуждениÑ"
+msgid "An error occurred while adding approver"
+msgstr "Произошла ошибка при добавлении утверждающего"
+
+msgid "An error occurred while detecting host keys"
+msgstr "Произошла ошибка при обнаружении ключей хоÑта"
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
-msgstr ""
+msgstr "Произошла ошибка при отключении ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ функции. Обновите Ñтраницу и повторите попытку."
msgid "An error occurred while fetching markdown preview"
-msgstr ""
+msgstr "Произошла ошибка при предварительном проÑмотре markdown"
msgid "An error occurred while fetching sidebar data"
msgstr "Произошла ошибка при получении денег данных Ð´Ð»Ñ Ð±Ð¾ÐºÐ¾Ð²Ð¾Ð¹ панели"
+msgid "An error occurred while fetching the pipeline."
+msgstr "Произошла ошибка при получении Ñборочной линии."
+
msgid "An error occurred while getting projects"
-msgstr ""
+msgstr "Произошла ошибка при получении ÑпиÑка проектов"
+
+msgid "An error occurred while importing project"
+msgstr "Произошла ошибка при импорте проекта"
+
+msgid "An error occurred while initializing path locks"
+msgstr "Произошла ошибка при инициализации блокировок пути"
+
+msgid "An error occurred while loading commits"
+msgstr "Произошла ошибка при загрузке коммитов"
+
+msgid "An error occurred while loading diff"
+msgstr "Произошла ошибка при загрузке различий"
msgid "An error occurred while loading filenames"
-msgstr ""
+msgstr "Произошла ошибка при загрузке ÑпиÑка файлов"
+
+msgid "An error occurred while loading the file"
+msgstr "Произошла ошибка при загрузке файла"
+
+msgid "An error occurred while making the request."
+msgstr "Произошла ошибка при выполнении запроÑа."
+
+msgid "An error occurred while removing approver"
+msgstr "Произошла ошибка при удалении утверждающего"
msgid "An error occurred while rendering KaTeX"
-msgstr ""
+msgstr "Произошла ошибка при рендеринге KaTeX"
msgid "An error occurred while rendering preview broadcast message"
-msgstr ""
+msgstr "Произошла ошибка при визуализации проÑмотра широковещательного ÑообщениÑ"
msgid "An error occurred while retrieving calendar activity"
-msgstr ""
+msgstr "Произошла ошибка при получении ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ð¾Ñти"
msgid "An error occurred while retrieving diff"
-msgstr ""
+msgstr "Произошла ошибка при получении различий"
+
+msgid "An error occurred while saving LDAP override status. Please try again."
+msgstr "Произошла ошибка при Ñохранении ÑтатуÑа наÑтроенного LDAP. ПожалуйÑта, попробуйте еще раз."
+
+msgid "An error occurred while saving assignees"
+msgstr "Произошла ошибка при Ñохранении иÑполнителÑ"
msgid "An error occurred while validating username"
-msgstr ""
+msgstr "Произошла ошибка при проверке имени пользователÑ"
msgid "An error occurred. Please try again."
msgstr "Произошла ошибка. ПожалуйÑта, попробуйте Ñнова."
@@ -241,15 +334,15 @@ msgstr "Ðрхивный проект! Репозиторий доÑтупен Ñ
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Ð’Ñ‹ дейÑтвительно хотите удалить Ñто раÑпиÑание Ñборочной линии?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "Ð’Ñ‹ уверены, что хотите отменить ваши изменениÑ?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "Ð’Ñ‹ уверены, что хотите ÑброÑить Ñтот региÑтрационный токен?"
msgid "Are you sure you want to reset the health check token?"
msgstr "Ð’Ñ‹ уверены, что хотите ÑброÑить Ñтот токен проверки работоÑпоÑобноÑти?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "Вы уверены?"
@@ -289,6 +382,9 @@ msgstr "Ðвтор"
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -313,8 +409,14 @@ msgstr "Ð”Ð»Ñ Ñтого проекта может быть активировÐ
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "Подробнее по ÑÑылке %{link_to_documentation}"
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
-msgstr "Ð’Ñ‹ можете активировать %{link_to_settings} Ð´Ð»Ñ Ñтого проекта."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr ""
msgid "Available"
msgstr "ДоÑтупен"
@@ -325,6 +427,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr "Тариф"
@@ -379,14 +484,12 @@ msgstr "оплачиваетÑÑ ÐµÐ¶ÐµÐ³Ð¾Ð´Ð½Ð¾ в размере %{price_per_
msgid "BillingPlans|per user"
msgstr "за пользователÑ"
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "Ветка"
-msgstr[1] "Ветки"
-msgstr[2] "Ветки"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] "Ветка (%{branch_count})"
+msgstr[1] "Ветки (%{branch_count})"
+msgstr[2] "Ветки (%{branch_count})"
+msgstr[3] "Ветки (%{branch_count})"
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "Ветка <strong>%{branch_name}</strong> Ñоздана. Ð”Ð»Ñ Ð½Ð°Ñтройки автоматичеÑкого Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð²Ñ‹Ð±ÐµÑ€Ð¸Ñ‚Ðµ YAML-шаблон Ð´Ð»Ñ GitLab CI и зафикÑируйте Ñвои изменениÑ. %{link_to_autodeploy_doc}"
@@ -679,6 +782,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr "CircuitBreaker API"
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -733,6 +839,9 @@ msgstr "Скопировать Ð°Ð´Ñ€ÐµÑ API"
msgid "ClusterIntegration|Copy CA Certificate"
msgstr "Копировать Сертификат УдоÑтоверÑющего Центра"
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -781,6 +890,9 @@ msgstr "Helm Tiller"
msgid "ClusterIntegration|Ingress"
msgstr "Ingress"
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr "УÑтановить"
@@ -832,9 +944,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "Узнайте больше на %{link_to_documentation}"
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -970,14 +1079,28 @@ msgstr "правильно наÑтроен"
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "Комментарии"
msgid "Commit"
msgid_plural "Commits"
msgstr[0] "Коммит"
-msgstr[1] "Коммиты"
-msgstr[2] "Коммиты"
+msgstr[1] "Коммита"
+msgstr[2] "Коммитов"
+msgstr[3] "Коммиты"
+
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] "Коммит (%{commit_count})"
+msgstr[1] "Коммита (%{commit_count})"
+msgstr[2] "Коммитов (%{commit_count})"
+msgstr[3] "Коммитов (%{commit_count})"
msgid "Commit Message"
msgstr "ОпиÑание Коммита"
@@ -991,6 +1114,9 @@ msgstr "ОпиÑание коммита"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "Коммит"
@@ -1013,7 +1139,7 @@ msgid "Commits per weekday"
msgstr ""
msgid "Commits|An error occurred while fetching merge requests data."
-msgstr ""
+msgstr "Произошла ошибка при получении данных запроÑа на ÑлиÑниÑ."
msgid "Commits|Commit: %{commitText}"
msgstr ""
@@ -1132,6 +1258,9 @@ msgstr "Копировать URL в буфер обмена"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "Копировать SHA коммита в буфер обмена"
@@ -1144,9 +1273,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "Создать Ðовый каталог"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Создать личный токен на аккаунте Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ отправки через %{protocol}."
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "Создать каталог"
@@ -1165,6 +1303,9 @@ msgstr ""
msgid "Create merge request"
msgstr "Создать Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr "Создать новую ветку"
@@ -1189,6 +1330,12 @@ msgstr "Тег"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Ñоздать перÑональный токен доÑтупа"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr "Создание Ñпика"
@@ -1243,6 +1390,9 @@ msgstr "Дек."
msgid "December"
msgstr "Декабрь"
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Определить наÑтраиваемый шаблон Ñ ÑинтакÑиÑом cron"
@@ -1251,9 +1401,10 @@ msgstr "Удалить"
msgid "Deploy"
msgid_plural "Deploys"
-msgstr[0] "Развернуть"
-msgstr[1] "Развертывание"
-msgstr[2] "Развертывание"
+msgstr[0] "Развертывание"
+msgstr[1] "РазвертываниÑ"
+msgstr[2] "Развертываний"
+msgstr[3] "РазвертываниÑ"
msgid "Deploy Keys"
msgstr "Ключи РазвертываниÑ"
@@ -1276,8 +1427,8 @@ msgstr "Ð˜Ð¼Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð°"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
-msgstr "Отменить изменениÑ"
+msgid "Discard draft"
+msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
@@ -1336,6 +1487,9 @@ msgstr "Email-адреÑа"
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr "Произошла ошибка при получении окружений."
@@ -1390,9 +1544,18 @@ msgstr "Эпик будет удален! Вы уверены?"
msgid "Epics"
msgstr "Эпики"
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr "Эпики позволÑÑ‚ вам управлÑÑ‚ÑŒ портфелем проектов более Ñффективно и Ñ Ð¼ÐµÐ½ÑŒÑˆÐ¸Ð¼Ð¸ уÑилиÑми"
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr "Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñпика"
@@ -1459,12 +1622,36 @@ msgstr "Обзор проектов"
msgid "Explore public groups"
msgstr "ИÑÑледовать публичные группы"
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr "Ðевыполненные ЗаданиÑ"
+
msgid "Failed to change the owner"
msgstr "Ðе удалоÑÑŒ изменить владельца"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "Ðе удалоÑÑŒ удалить раÑпиÑание Ñборочной линии"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr "Фев."
@@ -1480,6 +1667,9 @@ msgstr "Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°"
msgid "Files"
msgstr "Файлы"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "Фильтр по комментариÑми к коммитам"
@@ -1497,9 +1687,10 @@ msgstr "отправлено автором"
msgid "Fork"
msgid_plural "Forks"
-msgstr[0] "Ответвление"
-msgstr[1] "ОтветвлениÑ"
-msgstr[2] "ОтветвлениÑ"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
msgid "ForkedFromProjectPath|Forked from"
msgstr "Ответвлено от"
@@ -1516,6 +1707,9 @@ msgstr "От ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ð±ÑÑƒÐ¶Ð´ÐµÐ½Ð¸Ñ Ð´Ð¾ развертывани
msgid "From merge request merge until deploy to production"
msgstr "От запроÑа на ÑлиÑние до Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð² рабочей Ñреде"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr "GPG Ключи"
@@ -1663,6 +1857,24 @@ msgstr "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Google не %{link_to_documentation}. ПоÐ
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr "Запретить публикацию проектов из %{group} в других группах"
@@ -1755,6 +1967,7 @@ msgid_plural "Hide values"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "History"
msgstr "ИÑториÑ"
@@ -1762,6 +1975,9 @@ msgstr "ИÑториÑ"
msgid "Housekeeping successfully started"
msgstr "ОчиÑтка уÑпешно запущена"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "Импорт репозиториÑ"
@@ -1774,14 +1990,18 @@ msgstr "Улучшить управление обÑуждениÑми возмÐ
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr "Улучшить поиÑк при помощи РаÑширенного Глобального ПоиÑка и GitLab Enterprise Edition."
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "УÑтановите Gitlab Runner ÑовмеÑтимый Ñ Gitlab CI"
msgid "Instance"
msgid_plural "Instances"
-msgstr[0] "ЭкземплÑÑ€"
-msgstr[1] "ЭкземплÑра"
-msgstr[2] "ЭкземплÑров"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
msgid "Instance does not support multiple Kubernetes clusters"
msgstr ""
@@ -1825,6 +2045,9 @@ msgstr "Янв."
msgid "January"
msgstr "Январь"
+msgid "Jobs"
+msgstr "ЗаданиÑ"
+
msgid "Jul"
msgstr "Июл."
@@ -1855,6 +2078,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1873,8 +2099,9 @@ msgstr ""
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "ПоÑледний %d день"
-msgstr[1] "ПоÑледние %d дни"
-msgstr[2] "ПоÑледние %d дни"
+msgstr[1] "ПоÑледние %d днÑ"
+msgstr[2] "ПоÑледние %d дней"
+msgstr[3] "ПоÑледние %d дни"
msgid "Last Pipeline"
msgstr "ПоÑледнÑÑ Ð¡Ð±Ð¾Ñ€Ð¾Ñ‡Ð½Ð°Ñ Ð›Ð¸Ð½Ð¸Ñ"
@@ -1903,6 +2130,12 @@ msgstr "в"
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "Узнайте больше в"
@@ -1921,6 +2154,9 @@ msgstr "Покинуть проект"
msgid "License"
msgstr "ЛицензиÑ"
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1930,6 +2166,9 @@ msgstr "Блокировка"
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1939,6 +2178,9 @@ msgstr "Заблокировано"
msgid "Locked Files"
msgstr "Заблокированные Файлы"
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr "Войти"
@@ -1969,9 +2211,6 @@ msgstr "Среднее"
msgid "Members"
msgstr "УчаÑтники"
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr "ЗапроÑÑ‹ на СлиÑние"
@@ -1984,6 +2223,9 @@ msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -2008,9 +2250,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "добавить ключ SSH"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr "Мониторинг"
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr "Больше информации доÑтупно|тут"
@@ -2031,6 +2282,7 @@ msgid_plural "New Issues"
msgstr[0] "Ðовое ОбÑуждение"
msgstr[1] "Ðовых ОбÑуждениÑ"
msgstr[2] "Ðовых ОбÑуждений"
+msgstr[3] "Ðовые ОбÑуждениÑ"
msgid "New Kubernetes Cluster"
msgstr ""
@@ -2107,9 +2359,6 @@ msgstr "Ðет репозиториÑ"
msgid "No schedules"
msgstr "Ðет раÑпиÑаний"
-msgid "No time spent"
-msgstr "Ðет затраченного времени"
-
msgid "None"
msgstr "ПуÑто"
@@ -2125,6 +2374,9 @@ msgstr ""
msgid "Not enough data"
msgstr "ÐедоÑтаточно данных"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ ÑобытиÑÑ…"
@@ -2227,6 +2479,9 @@ msgstr "ОткроетÑÑ Ð² новом окне"
msgid "Options"
msgstr "ÐаÑтройки"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr "Обзор"
@@ -2332,6 +2587,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "вÑе"
@@ -2365,6 +2638,9 @@ msgstr "Приватный - ДоÑтуп к проекту должен преÐ
msgid "Private - The group and its projects can only be viewed by members."
msgstr "ÐŸÑ€Ð¸Ð²Ð°Ñ‚Ð½Ð°Ñ - Группу и включённые в неё проекты могут видеть только члены группы."
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr "Профиль"
@@ -2527,12 +2803,30 @@ msgstr "К Ñожалению, по вашему запроÑу проекты Ð
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Эта функциональноÑÑ‚ÑŒ требует поддержки localStorage в вашем браузере"
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr "По умолчанию, Prometheus запуÑкаетÑÑ Ð¿Ð¾ адреÑу ‘http://localhost:9090’. Ðе рекомендуетÑÑ Ð¸Ð·Ð¼ÐµÐ½ÑÑ‚ÑŒ Ð°Ð´Ñ€ÐµÑ Ð¸ порт по умолчанию, так как Ñто может привеÑти к конфликту Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼ ÑервиÑами запущенными на GitLab Ñервере."
msgid "PrometheusService|Finding and configuring metrics..."
msgstr "Определение и наÑтройка метрик..."
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr "Метрики"
@@ -2554,9 +2848,18 @@ msgstr "Ðи одной метрики не отÑлеживаетÑÑ. Ð”Ð»Ñ Ð
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr "Базовый Ð°Ð´Ñ€ÐµÑ Prometheus API, например http://prometheus.example.com/"
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr "ПроÑмотр окружений"
@@ -2575,6 +2878,12 @@ msgstr "Правила Отправки"
msgid "Push events"
msgstr "Ð¡Ð¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸"
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr "ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¼Ð¸Ñ‚ÐµÑ€Ð°"
@@ -2606,13 +2915,13 @@ msgid "Related Commits"
msgstr "СвÑзанные коммиты"
msgid "Related Deployed Jobs"
-msgstr "СвÑзанные задачи выгрузки"
+msgstr "СвÑзанные Ð—Ð°Ð´Ð°Ð½Ð¸Ñ Ð Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ"
msgid "Related Issues"
msgstr "СвÑзанные ОбÑуждениÑ"
msgid "Related Jobs"
-msgstr "СвÑзанные задачи"
+msgstr "СвÑзанные ЗаданиÑ"
msgid "Related Merge Requests"
msgstr "СвÑзанные ЗапроÑÑ‹ на СлиÑние"
@@ -2638,6 +2947,9 @@ msgstr ""
msgid "Repository"
msgstr "Репозиторий"
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ñтупа"
@@ -2650,11 +2962,15 @@ msgstr "СброÑить ключ доÑтупа проверки работоÑ
msgid "Reset runners registration token"
msgstr "СброÑить ключ региÑтрации Gitlab Runners"
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
msgid "Revert this commit"
msgstr "Отменить Ñто коммит"
@@ -2662,6 +2978,9 @@ msgstr "Отменить Ñто коммит"
msgid "Revert this merge request"
msgstr "Отменить Ñтот Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr "SSH Ключи"
@@ -2707,12 +3026,18 @@ msgstr "Секунд задержки между попытками доÑтуп
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "Выбрать формат архива"
msgid "Select a timezone"
msgstr "Выбор временной зоны"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2725,6 +3050,9 @@ msgstr "Выбор целевой ветки"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr "Сент."
@@ -2737,6 +3065,9 @@ msgstr ""
msgid "Service Templates"
msgstr "Шаблоны Служб"
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "УÑтановите пароль в Ñвоем аккаунте, чтобы отправлÑÑ‚ÑŒ или получать код через %{protocol}."
@@ -2746,15 +3077,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "ÐаÑтройка Koding"
-msgid "Set up auto deploy"
-msgstr "ÐаÑтройка автоматичеÑкого развертываниÑ"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "уÑтановите пароль"
msgid "Settings"
msgstr "ÐаÑтройки"
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2764,6 +3095,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr "Показать родительÑкие Ñтраницы"
@@ -2773,8 +3107,9 @@ msgstr "Показать родительÑкие подгруппы"
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Показано %d Ñобытие"
-msgstr[1] "Показано %d Ñобытий"
+msgstr[1] "Показано %d ÑобытиÑ"
msgstr[2] "Показано %d Ñобытий"
+msgstr[3] "Показано %d Ñобытий"
msgid "Sidebar|Change weight"
msgstr "Изменить веÑ"
@@ -2806,12 +3141,24 @@ msgstr "Что-то пошло не так при попытке измененÐ
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr "Что-то пошло не так при получении проектов."
msgid "Something went wrong while fetching the registry list."
msgstr "Что-то пошло не так при получении ÑпиÑка рееÑтров."
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2917,6 +3264,9 @@ msgstr "ВеÑ"
msgid "Source"
msgstr "ИÑточник"
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "ИÑходный код"
@@ -2956,11 +3306,12 @@ msgstr "Переключить ветка/тег"
msgid "System Hooks"
msgstr "СиÑтемные Обработчики"
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "Тег"
-msgstr[1] "Теги"
-msgstr[2] "Теги"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
msgid "Tags"
msgstr "Теги"
@@ -3091,9 +3442,15 @@ msgstr "ДоÑтуп к проекту возможен без какой-либ
msgid "The repository for this project does not exist."
msgstr "Репозиторий Ð´Ð»Ñ Ñтого проекта не ÑущеÑтвует."
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "Этап обзора показывает Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа ÑлиÑÐ½Ð¸Ñ Ð´Ð¾ его выполнениÑ. Данные будут автоматичеÑки добавлены поÑле Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ запроÑа на ÑлиÑние."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "Этап поÑтановки показывает Ð²Ñ€ÐµÐ¼Ñ Ð¼ÐµÐ¶Ð´Ñƒ ÑлиÑнием \"MR\" и развертыванием кода в производÑтвенной Ñреде. Данные будут автоматичеÑки добавлены поÑле Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð² производÑтве первый раз."
@@ -3167,7 +3524,7 @@ msgid "This job depends on a user to trigger its process. Often they are used to
msgstr ""
msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
-msgstr ""
+msgstr "Это задание завиÑит от рабочих заданий на верхнем уровне, которые должны завершитьÑÑ ÑƒÑпешно, чтобы Ñто задание было запущено"
msgid "This job has not been triggered yet"
msgstr ""
@@ -3187,6 +3544,9 @@ msgstr "Это означает, что вы не можете отправитÑ
msgid "This merge request is locked."
msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние заблокирован."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3348,19 +3708,27 @@ msgid_plural "Time|hrs"
msgstr[0] "ч"
msgstr[1] "ч"
msgstr[2] "ч"
+msgstr[3] "ч"
msgid "Time|min"
msgid_plural "Time|mins"
msgstr[0] "мин"
msgstr[1] "мин"
msgstr[2] "мин"
+msgstr[3] "мин"
msgid "Time|s"
msgstr "Ñ"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr "Заголовок"
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3376,21 +3744,18 @@ msgstr ""
msgid "Total Time"
msgstr "Общее времÑ"
-msgid "Total issue time spent"
-msgstr "Общее времÑ, затраченное на обÑуждение"
-
msgid "Total test time for all commits/merges"
msgstr "Общее Ð²Ñ€ÐµÐ¼Ñ Ñ‚ÐµÑÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð¸ÐºÑаций/ÑлиÑний"
+msgid "Total: %{total}"
+msgstr ""
+
msgid "Track activity with Contribution Analytics."
msgstr "ОтÑлеживать активноÑÑ‚ÑŒ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Ðналитики УчаÑтников."
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr "Следите за обÑуждениÑми, Ñгруппированными по темам, Ñразу из неÑкольких проектов и Ñтапов"
-msgid "Total: %{total}"
-msgstr ""
-
msgid "Track time with quick actions"
msgstr ""
@@ -3400,9 +3765,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr "Включить Службу Поддержки"
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3418,6 +3780,9 @@ msgstr ""
msgid "Unlocked"
msgstr "Разблокировано"
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "СнÑÑ‚ÑŒ отметку"
@@ -3463,6 +3828,9 @@ msgstr "ИÑпользуютÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ñ‹Ð¹ наÑтройки увеÐ
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr "ПроÑмотр файла @ "
@@ -3499,6 +3867,9 @@ msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾ Ñтапу отÑутÑтвует."
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Мы хотим быть уверены, что Ñто вы, пожалуйÑта, подтвердите, что вы не робот."
+msgid "Web IDE"
+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 еÑли, например, отправлен новый код или Ñоздано новое обÑуждение. Ð’Ñ‹ можете наÑтроить веб-обработчики так, чтобы они реагировали на определённые ÑобытиÑ, такие как отправки кода, обÑÑƒÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ запроÑÑ‹ на ÑлиÑние. Групповые веб-обработчики применÑÑŽÑ‚ÑÑ ÐºÐ¾ вÑем проектам в группе и позволÑÑŽÑ‚ вам Ñтандартизовать функциональноÑÑ‚ÑŒ веб-обработчиков Ð´Ð»Ñ Ð²Ñей вашей группы."
@@ -3619,6 +3990,9 @@ msgstr "С аналитикой учаÑтников вы можете изучÐ
msgid "Withdraw Access Request"
msgstr "Отменить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ñтупа"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ удалить %{group_name}. Удаленные группы ÐЕ МОГУТ быть воÑÑтановлены! Ð’Ñ‹ ÐБСОЛЮТÐО уверены?"
@@ -3631,10 +4005,13 @@ msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ удалить ÑвÑзь ответвлен
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ передать проект %{project_name_with_namespace} другому владельцу. Ð’Ñ‹ ÐБСОЛЮТÐО уверены?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3652,12 +4029,24 @@ msgstr "Ð’Ñ‹ не можете запиÑывать на подчиненные
msgid "You cannot write to this read-only GitLab instance."
msgstr "Ð’Ñ‹ не можете запиÑывать на Ñтот ÑкземплÑÑ€ \"только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ\" клаÑтера GitLab."
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "Ð’Ñ‹ доÑтигли Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð² вашем проекте"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "Ðеобходимо войти, чтобы оценить проект"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "Вам нужно разрешение."
@@ -3691,6 +4080,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr "Ваш комментарий не будет виден вÑем."
@@ -3718,7 +4110,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3730,7 +4122,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3745,6 +4137,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3757,6 +4158,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr "коммит"
@@ -3768,18 +4175,50 @@ msgstr ""
msgid "day"
msgid_plural "days"
-msgstr[0] "день"
-msgstr[1] "дней"
-msgstr[2] "дней"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgstr[3] ""
+
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3814,6 +4253,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3847,6 +4289,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3901,6 +4346,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3921,9 +4369,10 @@ msgstr ""
msgid "parent"
msgid_plural "parents"
-msgstr[0] "иÑточник"
-msgstr[1] "иÑточники"
-msgstr[2] "иÑточники"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
msgid "password"
msgstr "пароль"
@@ -3949,3 +4398,6 @@ msgstr "Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po
new file mode 100644
index 00000000000..b4df4c4b1af
--- /dev/null
+++ b/locale/tr_TR/gitlab.po
@@ -0,0 +1,4351 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: gitlab-ee\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:20-0500\n"
+"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
+"Language-Team: Turkish\n"
+"Language: tr_TR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: crowdin.com\n"
+"X-Crowdin-Project: gitlab-ee\n"
+"X-Crowdin-Language: tr\n"
+"X-Crowdin-File: /master/locale/gitlab.pot\n"
+
+msgid " and"
+msgstr " ve"
+
+msgid "%d commit"
+msgid_plural "%d commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d commit behind"
+msgid_plural "%d commits behind"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d issue"
+msgid_plural "%d issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d layer"
+msgid_plural "%d layers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d merge request"
+msgid_plural "%d merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%s additional commit has been omitted to prevent performance issues."
+msgid_plural "%s additional commits have been omitted to prevent performance issues."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
+msgid "%{commit_author_link} authored %{commit_timeago}"
+msgstr ""
+
+msgid "%{count} participant"
+msgid_plural "%{count} participants"
+msgstr[0] "%{count} katılımcı"
+msgstr[1] "%{count} katılımcı"
+
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
+msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
+msgstr ""
+
+msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
+msgstr ""
+
+msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
+msgstr ""
+
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
+msgid "%{storage_name}: failed storage access attempt on host:"
+msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{text} is available"
+msgstr ""
+
+msgid "(checkout the %{link} for information on how to install it)."
+msgstr ""
+
+msgid "+ %{moreCount} more"
+msgstr "+ %{moreCount} daha fazla"
+
+msgid "- show less"
+msgstr "- daha az göster"
+
+msgid "1 pipeline"
+msgid_plural "%d pipelines"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1st contribution!"
+msgstr "İlk katkı!"
+
+msgid "2FA enabled"
+msgstr ""
+
+msgid "A collection of graphs regarding Continuous Integration"
+msgstr ""
+
+msgid "About auto deploy"
+msgstr ""
+
+msgid "Abuse Reports"
+msgstr "Kötüye Kullanım Raporları"
+
+msgid "Access Tokens"
+msgstr "Erişim anahtarları"
+
+msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
+msgstr ""
+
+msgid "Account"
+msgstr "Hesap"
+
+msgid "Active"
+msgstr "Etkin"
+
+msgid "Activity"
+msgstr "Etkinlik"
+
+msgid "Add"
+msgstr "Ekle"
+
+msgid "Add Changelog"
+msgstr "DeÄŸiÅŸiklik Bilgisi Ekle"
+
+msgid "Add Contribution guide"
+msgstr "Katkı kılavuzu ekle"
+
+msgid "Add Group Webhooks and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Add Kubernetes cluster"
+msgstr ""
+
+msgid "Add License"
+msgstr "Lisans Ekle"
+
+msgid "Add Readme"
+msgstr ""
+
+msgid "Add new directory"
+msgstr "Yeni dizin ekle"
+
+msgid "Add todo"
+msgstr "Yapılacaklara Ekle"
+
+msgid "AdminArea|Stop all jobs"
+msgstr "Tüm işleri durdur"
+
+msgid "AdminArea|Stop all jobs?"
+msgstr "Tüm işleri durdur?"
+
+msgid "AdminArea|Stop jobs"
+msgstr "Ä°ÅŸleri durdur"
+
+msgid "AdminArea|Stopping jobs failed"
+msgstr ""
+
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
+msgstr ""
+
+msgid "AdminHealthPageLink|health page"
+msgstr ""
+
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
+msgid "Advanced"
+msgstr "GeliÅŸmiÅŸ"
+
+msgid "Advanced settings"
+msgstr "GeliÅŸmiÅŸ ayarlar"
+
+msgid "All"
+msgstr "Tümü"
+
+msgid "All changes are committed"
+msgstr ""
+
+msgid "Allows you to add and manage Kubernetes clusters."
+msgstr "Kubernetes kümelerini eklemeye ve yönetmenize olanak tanır."
+
+msgid "An error occurred previewing the blob"
+msgstr ""
+
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
+msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
+msgstr ""
+
+msgid "An error occurred while fetching markdown preview"
+msgstr "Markdown ön izlemesi yüklenirken hata oluştu"
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
+msgid "An error occurred while getting projects"
+msgstr "Projeler yüklenirken bir hata oluştu"
+
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
+msgid "An error occurred while loading filenames"
+msgstr "Dosya isimleri yüklenirken bir hata oluştu"
+
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
+msgid "An error occurred while rendering KaTeX"
+msgstr "KaTeX'i iÅŸlerken bir hata oluÅŸtu"
+
+msgid "An error occurred while rendering preview broadcast message"
+msgstr "Önizleme yayını iletisi oluşturulurken bir hata oluştu"
+
+msgid "An error occurred while retrieving calendar activity"
+msgstr ""
+
+msgid "An error occurred while retrieving diff"
+msgstr "Değişiklikler yüklenirken bir hata oluştu"
+
+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 validating username"
+msgstr "Kullanıcı adı doğrulanırken bir hata oluştu"
+
+msgid "An error occurred. Please try again."
+msgstr "Bir hata oluştu. Lütfen tekrar deneyin."
+
+msgid "Appearance"
+msgstr "Görünüm"
+
+msgid "Applications"
+msgstr "Uygulamalar"
+
+msgid "Apr"
+msgstr "Nis"
+
+msgid "April"
+msgstr "Nisan"
+
+msgid "Archived project! Repository is read-only"
+msgstr "Arşivlenmiş proje! Sadece okuma yapılabilir"
+
+msgid "Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
+msgid "Are you sure you want to reset registration token?"
+msgstr ""
+
+msgid "Are you sure you want to reset the health check token?"
+msgstr ""
+
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
+msgid "Are you sure?"
+msgstr "Emin misiniz?"
+
+msgid "Artifacts"
+msgstr ""
+
+msgid "Assign custom color like #FF0000"
+msgstr "#FF0000 gibi özel renk ata"
+
+msgid "Assign labels"
+msgstr "Etiket tanımla"
+
+msgid "Assign milestone"
+msgstr ""
+
+msgid "Assign to"
+msgstr "Ata"
+
+msgid "Assignee"
+msgstr ""
+
+msgid "Attach a file by drag &amp; drop or %{upload_link}"
+msgstr "Sürükleyip bırakarak bir dosya ekle veya %{upload_link}"
+
+msgid "Aug"
+msgstr "AÄŸustos"
+
+msgid "August"
+msgstr "AÄŸustos"
+
+msgid "Authentication Log"
+msgstr "Kimlik Doğrulama Günlüğü"
+
+msgid "Author"
+msgstr "Yazar"
+
+msgid "Authors: %{authors}"
+msgstr "Yazarlar: %{authors}"
+
+msgid "Auto DevOps enabled"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and a %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Auto DevOps (Beta)"
+msgstr ""
+
+msgid "AutoDevOps|Auto DevOps documentation"
+msgstr ""
+
+msgid "AutoDevOps|Enable in settings"
+msgstr ""
+
+msgid "AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
+msgstr ""
+
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Available"
+msgstr "Kullanılabilir"
+
+msgid "Avatar will be removed. Are you sure?"
+msgstr "Avatar kaldırılacak. Emin misiniz?"
+
+msgid "Average per day: %{average}"
+msgstr ""
+
+msgid "Begin with the selected commit"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Downgrade"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Branch <strong>%{branch_name}</strong> 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 is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
+msgid "BranchSwitcherPlaceholder|Search branches"
+msgstr ""
+
+msgid "BranchSwitcherTitle|Switch branch"
+msgstr ""
+
+msgid "Branches"
+msgstr ""
+
+msgid "Branches|Cant find HEAD commit for this branch"
+msgstr ""
+
+msgid "Branches|Compare"
+msgstr ""
+
+msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
+msgstr ""
+
+msgid "Branches|Delete branch"
+msgstr ""
+
+msgid "Branches|Delete merged branches"
+msgstr ""
+
+msgid "Branches|Delete protected branch"
+msgstr ""
+
+msgid "Branches|Delete protected branch '%{branch_name}'?"
+msgstr ""
+
+msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "Branches|Filter by branch name"
+msgstr ""
+
+msgid "Branches|Merged into %{default_branch}"
+msgstr ""
+
+msgid "Branches|New branch"
+msgstr ""
+
+msgid "Branches|No branches to show"
+msgstr ""
+
+msgid "Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered."
+msgstr ""
+
+msgid "Branches|Only a project master or owner can delete a protected branch"
+msgstr ""
+
+msgid "Branches|Protected branches can be managed in %{project_settings_link}"
+msgstr ""
+
+msgid "Branches|Sort by"
+msgstr ""
+
+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 ""
+
+msgid "Branches|This branch hasn’t been merged into %{default_branch}."
+msgstr ""
+
+msgid "Branches|To avoid data loss, consider merging this branch before deleting it."
+msgstr ""
+
+msgid "Branches|To confirm, type %{branch_name_confirmation}:"
+msgstr ""
+
+msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
+msgstr ""
+
+msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
+msgstr ""
+
+msgid "Branches|diverged from upstream"
+msgstr ""
+
+msgid "Branches|merged"
+msgstr ""
+
+msgid "Branches|project settings"
+msgstr ""
+
+msgid "Branches|protected"
+msgstr ""
+
+msgid "Browse Directory"
+msgstr ""
+
+msgid "Browse File"
+msgstr ""
+
+msgid "Browse Files"
+msgstr ""
+
+msgid "Browse files"
+msgstr ""
+
+msgid "ByAuthor|by"
+msgstr ""
+
+msgid "CI / CD"
+msgstr ""
+
+msgid "CI/CD configuration"
+msgstr ""
+
+msgid "CICD|Jobs"
+msgstr ""
+
+msgid "Cancel"
+msgstr ""
+
+msgid "Cancel edit"
+msgstr ""
+
+msgid "Cannot modify managed Kubernetes cluster"
+msgstr ""
+
+msgid "Change Weight"
+msgstr ""
+
+msgid "ChangeTypeActionLabel|Pick into branch"
+msgstr ""
+
+msgid "ChangeTypeActionLabel|Revert in branch"
+msgstr ""
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr ""
+
+msgid "ChangeTypeAction|Revert"
+msgstr ""
+
+msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
+msgstr ""
+
+msgid "Changelog"
+msgstr ""
+
+msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision."
+msgstr ""
+
+msgid "Charts"
+msgstr ""
+
+msgid "Chat"
+msgstr ""
+
+msgid "Check interval"
+msgstr ""
+
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
+msgid "Cherry-pick this commit"
+msgstr ""
+
+msgid "Cherry-pick this merge request"
+msgstr ""
+
+msgid "Choose File ..."
+msgstr ""
+
+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 ""
+
+msgid "Choose file..."
+msgstr ""
+
+msgid "Choose which groups you wish to synchronize to this secondary node."
+msgstr ""
+
+msgid "Choose which shards you wish to synchronize to this secondary node."
+msgstr ""
+
+msgid "CiStatusLabel|canceled"
+msgstr ""
+
+msgid "CiStatusLabel|created"
+msgstr ""
+
+msgid "CiStatusLabel|failed"
+msgstr ""
+
+msgid "CiStatusLabel|manual action"
+msgstr ""
+
+msgid "CiStatusLabel|passed"
+msgstr ""
+
+msgid "CiStatusLabel|passed with warnings"
+msgstr ""
+
+msgid "CiStatusLabel|pending"
+msgstr ""
+
+msgid "CiStatusLabel|skipped"
+msgstr ""
+
+msgid "CiStatusLabel|waiting for manual action"
+msgstr ""
+
+msgid "CiStatusText|blocked"
+msgstr ""
+
+msgid "CiStatusText|canceled"
+msgstr ""
+
+msgid "CiStatusText|created"
+msgstr ""
+
+msgid "CiStatusText|failed"
+msgstr ""
+
+msgid "CiStatusText|manual"
+msgstr ""
+
+msgid "CiStatusText|passed"
+msgstr ""
+
+msgid "CiStatusText|pending"
+msgstr ""
+
+msgid "CiStatusText|skipped"
+msgstr ""
+
+msgid "CiStatus|running"
+msgstr ""
+
+msgid "CiVariables|Input variable key"
+msgstr ""
+
+msgid "CiVariables|Input variable value"
+msgstr ""
+
+msgid "CiVariables|Remove variable row"
+msgstr ""
+
+msgid "CiVariable|* (All environments)"
+msgstr ""
+
+msgid "CiVariable|All environments"
+msgstr ""
+
+msgid "CiVariable|Create wildcard"
+msgstr ""
+
+msgid "CiVariable|Error occured while saving variables"
+msgstr ""
+
+msgid "CiVariable|New environment"
+msgstr ""
+
+msgid "CiVariable|Protected"
+msgstr ""
+
+msgid "CiVariable|Search environments"
+msgstr ""
+
+msgid "CiVariable|Toggle protected"
+msgstr ""
+
+msgid "CiVariable|Validation failed"
+msgstr ""
+
+msgid "CircuitBreakerApiLink|circuitbreaker api"
+msgstr ""
+
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
+msgid "Click to expand text"
+msgstr ""
+
+msgid "Clone repository"
+msgstr ""
+
+msgid "Close"
+msgstr ""
+
+msgid "Closed"
+msgstr ""
+
+msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Add Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|Are you sure you want to remove this Kubernetes cluster's integration? This will not delete your actual Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Choose which of your project's environments will use this Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Control how your Kubernetes cluster integrates with GitLab"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Kubernetes cluster name"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
+msgstr ""
+
+msgid "ClusterIntegration|Create Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Create Kubernetes cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create a new Kubernetes cluster on Google Kubernetes Engine right from GitLab"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment scope"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Integration"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
+msgid "ClusterIntegration|Google Cloud Platform project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Google Kubernetes Engine project"
+msgstr ""
+
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgstr ""
+
+msgid "ClusterIntegration|Integration status"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster details"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is disabled for this project."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project. Disabling this integration will not affect your Kubernetes cluster, it will only temporarily turn off GitLab's connection to it."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster is being created on Google Kubernetes Engine..."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster name"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine. Refresh the page to see Kubernetes cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about environments"
+msgstr ""
+
+msgid "ClusterIntegration|Machine type"
+msgstr ""
+
+msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
+msgstr ""
+
+msgid "ClusterIntegration|Manage"
+msgstr ""
+
+msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
+msgstr ""
+
+msgid "ClusterIntegration|More information"
+msgstr ""
+
+msgid "ClusterIntegration|Multiple Kubernetes clusters are available in GitLab Enterprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
+msgid "ClusterIntegration|Number of nodes"
+msgstr ""
+
+msgid "ClusterIntegration|Please enter access information for your Kubernetes cluster. If you need help, you can read our %{link_to_help_page} on Kubernetes"
+msgstr ""
+
+msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace (optional, unique)"
+msgstr ""
+
+msgid "ClusterIntegration|Prometheus"
+msgstr ""
+
+msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration."
+msgstr ""
+
+msgid "ClusterIntegration|Remove Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Remove integration"
+msgstr ""
+
+msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
+msgstr ""
+
+msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|See machine types"
+msgstr ""
+
+msgid "ClusterIntegration|See your projects"
+msgstr ""
+
+msgid "ClusterIntegration|See zones"
+msgstr ""
+
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong on our end."
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
+msgid "ClusterIntegration|Toggle Kubernetes Cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Toggle Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Token"
+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 ""
+
+msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
+msgstr ""
+
+msgid "ClusterIntegration|Zone"
+msgstr ""
+
+msgid "ClusterIntegration|access to Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|check the pricing here"
+msgstr ""
+
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
+msgid "ClusterIntegration|help page"
+msgstr ""
+
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
+msgid "ClusterIntegration|meets the requirements"
+msgstr ""
+
+msgid "ClusterIntegration|properly configured"
+msgstr ""
+
+msgid "Collapse"
+msgstr ""
+
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
+msgid "Comments"
+msgstr ""
+
+msgid "Commit"
+msgid_plural "Commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Commit Message"
+msgstr ""
+
+msgid "Commit duration in minutes for last 30 commits"
+msgstr ""
+
+msgid "Commit message"
+msgstr ""
+
+msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
+msgstr ""
+
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
+msgid "CommitBoxTitle|Commit"
+msgstr ""
+
+msgid "CommitMessage|Add %{file_name}"
+msgstr ""
+
+msgid "Commits"
+msgstr ""
+
+msgid "Commits feed"
+msgstr ""
+
+msgid "Commits per day hour (UTC)"
+msgstr ""
+
+msgid "Commits per day of month"
+msgstr ""
+
+msgid "Commits per weekday"
+msgstr ""
+
+msgid "Commits|An error occurred while fetching merge requests data."
+msgstr ""
+
+msgid "Commits|Commit: %{commitText}"
+msgstr ""
+
+msgid "Commits|History"
+msgstr ""
+
+msgid "Commits|No related merge requests found"
+msgstr ""
+
+msgid "Committed by"
+msgstr ""
+
+msgid "Compare"
+msgstr ""
+
+msgid "Compare Git revisions"
+msgstr ""
+
+msgid "Compare Revisions"
+msgstr ""
+
+msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
+msgstr ""
+
+msgid "CompareBranches|Compare"
+msgstr ""
+
+msgid "CompareBranches|Source"
+msgstr ""
+
+msgid "CompareBranches|Target"
+msgstr ""
+
+msgid "CompareBranches|There isn't anything to compare."
+msgstr ""
+
+msgid "Confidentiality"
+msgstr ""
+
+msgid "Container Registry"
+msgstr ""
+
+msgid "ContainerRegistry|Created"
+msgstr ""
+
+msgid "ContainerRegistry|First log in to GitLab&rsquo;s Container Registry using your GitLab username and password. If you have %{link_2fa} you need to use a %{link_token}:"
+msgstr ""
+
+msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
+msgstr ""
+
+msgid "ContainerRegistry|How to use the Container Registry"
+msgstr ""
+
+msgid "ContainerRegistry|Learn more about"
+msgstr ""
+
+msgid "ContainerRegistry|No tags in Container Registry for this container image."
+msgstr ""
+
+msgid "ContainerRegistry|Once you log in, you&rsquo;re free to create and upload a container image using the common %{build} and %{push} commands"
+msgstr ""
+
+msgid "ContainerRegistry|Remove repository"
+msgstr ""
+
+msgid "ContainerRegistry|Remove tag"
+msgstr ""
+
+msgid "ContainerRegistry|Size"
+msgstr ""
+
+msgid "ContainerRegistry|Tag"
+msgstr ""
+
+msgid "ContainerRegistry|Tag ID"
+msgstr ""
+
+msgid "ContainerRegistry|Use different image names"
+msgstr ""
+
+msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
+msgstr ""
+
+msgid "Contribution guide"
+msgstr ""
+
+msgid "Contributors"
+msgstr ""
+
+msgid "ContributorsPage|%{startDate} – %{endDate}"
+msgstr ""
+
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
+msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
+msgstr ""
+
+msgid "Control the maximum concurrency of repository backfill for this secondary node"
+msgstr ""
+
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
+msgid "Copy URL to clipboard"
+msgstr ""
+
+msgid "Copy branch name to clipboard"
+msgstr ""
+
+msgid "Copy command to clipboard"
+msgstr ""
+
+msgid "Copy commit SHA to clipboard"
+msgstr ""
+
+msgid "Copy reference to clipboard"
+msgstr ""
+
+msgid "Create"
+msgstr ""
+
+msgid "Create New Directory"
+msgstr ""
+
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
+msgid "Create a personal access token on your account to pull or push via %{protocol}."
+msgstr ""
+
+msgid "Create branch"
+msgstr ""
+
+msgid "Create directory"
+msgstr ""
+
+msgid "Create empty bare repository"
+msgstr ""
+
+msgid "Create epic"
+msgstr ""
+
+msgid "Create file"
+msgstr ""
+
+msgid "Create lists from labels. Issues with that label appear in that list."
+msgstr ""
+
+msgid "Create merge request"
+msgstr ""
+
+msgid "Create merge request and branch"
+msgstr ""
+
+msgid "Create new branch"
+msgstr ""
+
+msgid "Create new directory"
+msgstr ""
+
+msgid "Create new file"
+msgstr ""
+
+msgid "Create new label"
+msgstr ""
+
+msgid "Create new..."
+msgstr ""
+
+msgid "CreateNewFork|Fork"
+msgstr ""
+
+msgid "CreateTag|Tag"
+msgstr ""
+
+msgid "CreateTokenToCloneLink|create a personal access token"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
+msgid "Creating epic"
+msgstr ""
+
+msgid "Cron Timezone"
+msgstr ""
+
+msgid "Cron syntax"
+msgstr ""
+
+msgid "Current node"
+msgstr ""
+
+msgid "Custom notification events"
+msgstr ""
+
+msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}."
+msgstr ""
+
+msgid "Cycle Analytics"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Code"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Issue"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Plan"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Production"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Review"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Staging"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Test"
+msgstr ""
+
+msgid "DashboardProjects|All"
+msgstr ""
+
+msgid "DashboardProjects|Personal"
+msgstr ""
+
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
+msgid "Default classification label"
+msgstr ""
+
+msgid "Define a custom pattern with cron syntax"
+msgstr ""
+
+msgid "Delete"
+msgstr ""
+
+msgid "Deploy"
+msgid_plural "Deploys"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Deploy Keys"
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
+msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
+msgstr ""
+
+msgid "Details"
+msgstr ""
+
+msgid "Diffs|No file name available"
+msgstr ""
+
+msgid "Directory name"
+msgstr ""
+
+msgid "Disable"
+msgstr ""
+
+msgid "Discard draft"
+msgstr ""
+
+msgid "Discover GitLab Geo."
+msgstr ""
+
+msgid "Dismiss Cycle Analytics introduction box"
+msgstr ""
+
+msgid "Dismiss Merge Request promotion"
+msgstr ""
+
+msgid "Don't show again"
+msgstr ""
+
+msgid "Download"
+msgstr ""
+
+msgid "Download tar"
+msgstr ""
+
+msgid "Download tar.bz2"
+msgstr ""
+
+msgid "Download tar.gz"
+msgstr ""
+
+msgid "Download zip"
+msgstr ""
+
+msgid "DownloadArtifacts|Download"
+msgstr ""
+
+msgid "DownloadCommit|Email Patches"
+msgstr ""
+
+msgid "DownloadCommit|Plain Diff"
+msgstr ""
+
+msgid "DownloadSource|Download"
+msgstr ""
+
+msgid "Due date"
+msgstr ""
+
+msgid "Edit"
+msgstr ""
+
+msgid "Edit Pipeline Schedule %{id}"
+msgstr ""
+
+msgid "Edit files in the editor and commit changes here"
+msgstr ""
+
+msgid "Emails"
+msgstr ""
+
+msgid "Enable"
+msgstr ""
+
+msgid "Enable Auto DevOps"
+msgstr ""
+
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics Roadmap"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error fetching contributors data."
+msgstr ""
+
+msgid "Error fetching labels."
+msgstr ""
+
+msgid "Error fetching network graph."
+msgstr ""
+
+msgid "Error fetching refs"
+msgstr ""
+
+msgid "Error fetching usage ping data."
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "Error saving label update."
+msgstr ""
+
+msgid "Error updating status for all todos."
+msgstr ""
+
+msgid "Error updating todo status."
+msgstr ""
+
+msgid "EventFilterBy|Filter by all"
+msgstr ""
+
+msgid "EventFilterBy|Filter by comments"
+msgstr ""
+
+msgid "EventFilterBy|Filter by issue events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by merge events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by push events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by team"
+msgstr ""
+
+msgid "Every day (at 4:00am)"
+msgstr ""
+
+msgid "Every month (on the 1st at 4:00am)"
+msgstr ""
+
+msgid "Every week (Sundays at 4:00am)"
+msgstr ""
+
+msgid "Expand"
+msgstr ""
+
+msgid "Explore projects"
+msgstr ""
+
+msgid "Explore public groups"
+msgstr ""
+
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
+msgid "Failed to change the owner"
+msgstr ""
+
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
+msgid "Failed to remove the pipeline schedule"
+msgstr ""
+
+msgid "Failed to update issues, please try again."
+msgstr ""
+
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
+msgid "Fields on this page are now uneditable, you can configure"
+msgstr ""
+
+msgid "File name"
+msgstr ""
+
+msgid "Files"
+msgstr ""
+
+msgid "Files (%{human_size})"
+msgstr ""
+
+msgid "Filter by commit message"
+msgstr ""
+
+msgid "Find by path"
+msgstr ""
+
+msgid "Find file"
+msgstr ""
+
+msgid "FirstPushedBy|First"
+msgstr ""
+
+msgid "FirstPushedBy|pushed by"
+msgstr ""
+
+msgid "Fork"
+msgid_plural "Forks"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ForkedFromProjectPath|Forked from"
+msgstr ""
+
+msgid "ForkedFromProjectPath|Forked from %{project_name} (deleted)"
+msgstr ""
+
+msgid "Format"
+msgstr ""
+
+msgid "From issue creation until deploy to production"
+msgstr ""
+
+msgid "From merge request merge until deploy to production"
+msgstr ""
+
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Generate a default set of labels"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodes|Database replication lag:"
+msgstr ""
+
+msgid "GeoNodes|Disabling a node stops the sync process. Are you sure?"
+msgstr ""
+
+msgid "GeoNodes|Does not match the primary storage configuration"
+msgstr ""
+
+msgid "GeoNodes|Failed"
+msgstr ""
+
+msgid "GeoNodes|Full"
+msgstr ""
+
+msgid "GeoNodes|GitLab version does not match the primary node version"
+msgstr ""
+
+msgid "GeoNodes|GitLab version:"
+msgstr ""
+
+msgid "GeoNodes|Health status:"
+msgstr ""
+
+msgid "GeoNodes|Last event ID processed by cursor:"
+msgstr ""
+
+msgid "GeoNodes|Last event ID seen from primary:"
+msgstr ""
+
+msgid "GeoNodes|Loading nodes"
+msgstr ""
+
+msgid "GeoNodes|Local Attachments:"
+msgstr ""
+
+msgid "GeoNodes|Local LFS objects:"
+msgstr ""
+
+msgid "GeoNodes|Local job artifacts:"
+msgstr ""
+
+msgid "GeoNodes|New node"
+msgstr ""
+
+msgid "GeoNodes|Out of sync"
+msgstr ""
+
+msgid "GeoNodes|Replication slot WAL:"
+msgstr ""
+
+msgid "GeoNodes|Replication slots:"
+msgstr ""
+
+msgid "GeoNodes|Repositories:"
+msgstr ""
+
+msgid "GeoNodes|Selective"
+msgstr ""
+
+msgid "GeoNodes|Storage config:"
+msgstr ""
+
+msgid "GeoNodes|Sync settings:"
+msgstr ""
+
+msgid "GeoNodes|Synced"
+msgstr ""
+
+msgid "GeoNodes|Unused slots"
+msgstr ""
+
+msgid "GeoNodes|Used slots"
+msgstr ""
+
+msgid "GeoNodes|Wikis:"
+msgstr ""
+
+msgid "GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS."
+msgstr ""
+
+msgid "Geo|All projects"
+msgstr ""
+
+msgid "Geo|File sync capacity"
+msgstr ""
+
+msgid "Geo|Groups to synchronize"
+msgstr ""
+
+msgid "Geo|Projects in certain groups"
+msgstr ""
+
+msgid "Geo|Projects in certain storage shards"
+msgstr ""
+
+msgid "Geo|Repository sync capacity"
+msgstr ""
+
+msgid "Geo|Select groups to replicate."
+msgstr ""
+
+msgid "Geo|Shards to synchronize"
+msgstr ""
+
+msgid "Git revision"
+msgstr ""
+
+msgid "Git storage health information has been reset"
+msgstr ""
+
+msgid "Git version"
+msgstr ""
+
+msgid "GitLab Runner section"
+msgstr ""
+
+msgid "Gitaly Servers"
+msgstr ""
+
+msgid "Go to your fork"
+msgstr ""
+
+msgid "GoToYourFork|Fork"
+msgstr ""
+
+msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
+msgstr ""
+
+msgid "Got it!"
+msgstr ""
+
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
+msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
+msgstr ""
+
+msgid "GroupSettings|Share with group lock"
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
+msgstr ""
+
+msgid "GroupSettings|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 ""
+
+msgid "GroupSettings|cannot be disabled when the parent group \"Share with group lock\" is enabled, except by the owner of the parent group"
+msgstr ""
+
+msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name}"
+msgstr ""
+
+msgid "GroupsEmptyState|A group is a collection of several projects."
+msgstr ""
+
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+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 ""
+
+msgid "GroupsTree|Are you sure you want to leave the \"${group.fullName}\" group?"
+msgstr ""
+
+msgid "GroupsTree|Create a project in this group."
+msgstr ""
+
+msgid "GroupsTree|Create a subgroup in this group."
+msgstr ""
+
+msgid "GroupsTree|Edit group"
+msgstr ""
+
+msgid "GroupsTree|Failed to leave the group. Please make sure you are not the only owner."
+msgstr ""
+
+msgid "GroupsTree|Filter by name..."
+msgstr ""
+
+msgid "GroupsTree|Leave this group"
+msgstr ""
+
+msgid "GroupsTree|Loading groups"
+msgstr ""
+
+msgid "GroupsTree|Sorry, no groups matched your search"
+msgstr ""
+
+msgid "GroupsTree|Sorry, no groups or projects matched your search"
+msgstr ""
+
+msgid "Have your users email"
+msgstr ""
+
+msgid "Health Check"
+msgstr ""
+
+msgid "Health information can be retrieved from the following endpoints. More information is available"
+msgstr ""
+
+msgid "HealthCheck|Access token is"
+msgstr ""
+
+msgid "HealthCheck|Healthy"
+msgstr ""
+
+msgid "HealthCheck|No Health Problems Detected"
+msgstr ""
+
+msgid "HealthCheck|Unhealthy"
+msgstr ""
+
+msgid "Hide value"
+msgid_plural "Hide values"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "History"
+msgstr ""
+
+msgid "Housekeeping successfully started"
+msgstr ""
+
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
+msgid "Import repository"
+msgstr ""
+
+msgid "Improve Issue boards with GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
+msgid "Install a Runner compatible with GitLab CI"
+msgstr ""
+
+msgid "Instance"
+msgid_plural "Instances"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Instance does not support multiple Kubernetes clusters"
+msgstr ""
+
+msgid "Interested parties can even contribute by pushing commits if they want to."
+msgstr ""
+
+msgid "Internal - The group and any internal projects can be viewed by any logged in user."
+msgstr ""
+
+msgid "Internal - The project can be accessed by any logged in user."
+msgstr ""
+
+msgid "Interval Pattern"
+msgstr ""
+
+msgid "Introducing Cycle Analytics"
+msgstr ""
+
+msgid "Issue board focus mode"
+msgstr ""
+
+msgid "Issue events"
+msgstr ""
+
+msgid "IssueBoards|Board"
+msgstr ""
+
+msgid "IssueBoards|Boards"
+msgstr ""
+
+msgid "Issues"
+msgstr ""
+
+msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
+msgstr ""
+
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jobs"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
+msgid "Kubernetes"
+msgstr ""
+
+msgid "Kubernetes Cluster"
+msgstr ""
+
+msgid "Kubernetes cluster creation time exceeds timeout; %{timeout}"
+msgstr ""
+
+msgid "Kubernetes cluster integration was not removed."
+msgstr ""
+
+msgid "Kubernetes cluster integration was successfully removed."
+msgstr ""
+
+msgid "Kubernetes cluster was successfully updated."
+msgstr ""
+
+msgid "Kubernetes configured"
+msgstr ""
+
+msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
+msgstr ""
+
+msgid "LFSStatus|Disabled"
+msgstr ""
+
+msgid "LFSStatus|Enabled"
+msgstr ""
+
+msgid "Labels"
+msgstr ""
+
+msgid "Labels can be applied to issues and merge requests to categorize them."
+msgstr ""
+
+msgid "Last %d day"
+msgid_plural "Last %d days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Last Pipeline"
+msgstr ""
+
+msgid "Last commit"
+msgstr ""
+
+msgid "Last edited %{date}"
+msgstr ""
+
+msgid "Last edited by %{name}"
+msgstr ""
+
+msgid "Last update"
+msgstr ""
+
+msgid "Last updated"
+msgstr ""
+
+msgid "LastPushEvent|You pushed to"
+msgstr ""
+
+msgid "LastPushEvent|at"
+msgstr ""
+
+msgid "Learn more"
+msgstr ""
+
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
+msgid "Learn more in the"
+msgstr ""
+
+msgid "Learn more in the|pipeline schedules documentation"
+msgstr ""
+
+msgid "Leave"
+msgstr ""
+
+msgid "Leave group"
+msgstr ""
+
+msgid "Leave project"
+msgstr ""
+
+msgid "License"
+msgstr ""
+
+msgid "List"
+msgstr ""
+
+msgid "Loading the GitLab IDE..."
+msgstr ""
+
+msgid "Lock"
+msgstr ""
+
+msgid "Lock %{issuableDisplayName}"
+msgstr ""
+
+msgid "Lock not found"
+msgstr ""
+
+msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
+msgstr ""
+
+msgid "Locked"
+msgstr ""
+
+msgid "Locked Files"
+msgstr ""
+
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
+msgid "Login"
+msgstr ""
+
+msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
+msgstr ""
+
+msgid "Manage labels"
+msgstr ""
+
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
+msgid "Mark done"
+msgstr ""
+
+msgid "Maximum git storage failures"
+msgstr ""
+
+msgid "May"
+msgstr ""
+
+msgid "Median"
+msgstr ""
+
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
+msgid "Merge events"
+msgstr ""
+
+msgid "Merge request"
+msgstr ""
+
+msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
+msgstr ""
+
+msgid "MergeRequest|Approved"
+msgstr ""
+
+msgid "Merged"
+msgstr ""
+
+msgid "Messages"
+msgstr ""
+
+msgid "Milestone"
+msgstr ""
+
+msgid "Milestones|Delete milestone"
+msgstr ""
+
+msgid "Milestones|Delete milestone %{milestoneTitle}?"
+msgstr ""
+
+msgid "Milestones|Failed to delete milestone %{milestoneTitle}"
+msgstr ""
+
+msgid "Milestones|Milestone %{milestoneTitle} was not found"
+msgstr ""
+
+msgid "MissingSSHKeyWarningLink|add an SSH key"
+msgstr ""
+
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
+msgid "Monitoring"
+msgstr ""
+
+msgid "More information"
+msgstr ""
+
+msgid "More information is available|here"
+msgstr ""
+
+msgid "Move"
+msgstr ""
+
+msgid "Move issue"
+msgstr ""
+
+msgid "Multiple issue boards"
+msgstr ""
+
+msgid "Name new label"
+msgstr ""
+
+msgid "New Issue"
+msgid_plural "New Issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "New Kubernetes Cluster"
+msgstr ""
+
+msgid "New Kubernetes cluster"
+msgstr ""
+
+msgid "New Pipeline Schedule"
+msgstr ""
+
+msgid "New branch"
+msgstr ""
+
+msgid "New branch unavailable"
+msgstr ""
+
+msgid "New directory"
+msgstr ""
+
+msgid "New epic"
+msgstr ""
+
+msgid "New file"
+msgstr ""
+
+msgid "New group"
+msgstr ""
+
+msgid "New issue"
+msgstr ""
+
+msgid "New label"
+msgstr ""
+
+msgid "New merge request"
+msgstr ""
+
+msgid "New project"
+msgstr ""
+
+msgid "New schedule"
+msgstr ""
+
+msgid "New snippet"
+msgstr ""
+
+msgid "New subgroup"
+msgstr ""
+
+msgid "New tag"
+msgstr ""
+
+msgid "No assignee"
+msgstr ""
+
+msgid "No changes"
+msgstr ""
+
+msgid "No connection could be made to a Gitaly Server, please check your logs!"
+msgstr ""
+
+msgid "No due date"
+msgstr ""
+
+msgid "No estimate or time spent"
+msgstr ""
+
+msgid "No file chosen"
+msgstr ""
+
+msgid "No repository"
+msgstr ""
+
+msgid "No schedules"
+msgstr ""
+
+msgid "None"
+msgstr ""
+
+msgid "Not allowed to merge"
+msgstr ""
+
+msgid "Not available"
+msgstr ""
+
+msgid "Not confidential"
+msgstr ""
+
+msgid "Not enough data"
+msgstr ""
+
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
+msgid "Notification events"
+msgstr ""
+
+msgid "NotificationEvent|Close issue"
+msgstr ""
+
+msgid "NotificationEvent|Close merge request"
+msgstr ""
+
+msgid "NotificationEvent|Failed pipeline"
+msgstr ""
+
+msgid "NotificationEvent|Merge merge request"
+msgstr ""
+
+msgid "NotificationEvent|New issue"
+msgstr ""
+
+msgid "NotificationEvent|New merge request"
+msgstr ""
+
+msgid "NotificationEvent|New note"
+msgstr ""
+
+msgid "NotificationEvent|Reassign issue"
+msgstr ""
+
+msgid "NotificationEvent|Reassign merge request"
+msgstr ""
+
+msgid "NotificationEvent|Reopen issue"
+msgstr ""
+
+msgid "NotificationEvent|Successful pipeline"
+msgstr ""
+
+msgid "NotificationLevel|Custom"
+msgstr ""
+
+msgid "NotificationLevel|Disabled"
+msgstr ""
+
+msgid "NotificationLevel|Global"
+msgstr ""
+
+msgid "NotificationLevel|On mention"
+msgstr ""
+
+msgid "NotificationLevel|Participate"
+msgstr ""
+
+msgid "NotificationLevel|Watch"
+msgstr ""
+
+msgid "Notifications"
+msgstr ""
+
+msgid "Notifications off"
+msgstr ""
+
+msgid "Notifications on"
+msgstr ""
+
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
+msgid "Number of access attempts"
+msgstr ""
+
+msgid "OK"
+msgstr ""
+
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
+msgid "OfSearchInADropdown|Filter"
+msgstr ""
+
+msgid "Only project members can comment."
+msgstr ""
+
+msgid "Open"
+msgstr ""
+
+msgid "Opened"
+msgstr ""
+
+msgid "OpenedNDaysAgo|Opened"
+msgstr ""
+
+msgid "Opens in a new window"
+msgstr ""
+
+msgid "Options"
+msgstr ""
+
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
+msgid "Overview"
+msgstr ""
+
+msgid "Owner"
+msgstr ""
+
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
+msgid "Password"
+msgstr ""
+
+msgid "Pipeline"
+msgstr ""
+
+msgid "Pipeline Health"
+msgstr ""
+
+msgid "Pipeline Schedule"
+msgstr ""
+
+msgid "Pipeline Schedules"
+msgstr ""
+
+msgid "Pipeline quota"
+msgstr ""
+
+msgid "PipelineCharts|Failed:"
+msgstr ""
+
+msgid "PipelineCharts|Overall statistics"
+msgstr ""
+
+msgid "PipelineCharts|Success ratio:"
+msgstr ""
+
+msgid "PipelineCharts|Successful:"
+msgstr ""
+
+msgid "PipelineCharts|Total:"
+msgstr ""
+
+msgid "PipelineSchedules|Activated"
+msgstr ""
+
+msgid "PipelineSchedules|Active"
+msgstr ""
+
+msgid "PipelineSchedules|All"
+msgstr ""
+
+msgid "PipelineSchedules|Inactive"
+msgstr ""
+
+msgid "PipelineSchedules|Next Run"
+msgstr ""
+
+msgid "PipelineSchedules|None"
+msgstr ""
+
+msgid "PipelineSchedules|Provide a short description for this pipeline"
+msgstr ""
+
+msgid "PipelineSchedules|Take ownership"
+msgstr ""
+
+msgid "PipelineSchedules|Target"
+msgstr ""
+
+msgid "PipelineSchedules|Variables"
+msgstr ""
+
+msgid "PipelineSheduleIntervalPattern|Custom"
+msgstr ""
+
+msgid "Pipelines"
+msgstr ""
+
+msgid "Pipelines charts"
+msgstr ""
+
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
+msgid "Pipelines|Build with confidence"
+msgstr ""
+
+msgid "Pipelines|Get started with Pipelines"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|all"
+msgstr ""
+
+msgid "Pipeline|success"
+msgstr ""
+
+msgid "Pipeline|with stage"
+msgstr ""
+
+msgid "Pipeline|with stages"
+msgstr ""
+
+msgid "Play"
+msgstr ""
+
+msgid "Please <a href=%{link_to_billing} target=\"_blank\" rel=\"noopener noreferrer\">enable billing for one of your projects to be able to create a Kubernetes cluster</a>, then try again."
+msgstr ""
+
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
+msgid "Preferences"
+msgstr ""
+
+msgid "Primary"
+msgstr ""
+
+msgid "Private - Project access must be granted explicitly to each user."
+msgstr ""
+
+msgid "Private - The group and its projects can only be viewed by members."
+msgstr ""
+
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
+msgid "Profile"
+msgstr ""
+
+msgid "Profiles|Account scheduled for removal."
+msgstr ""
+
+msgid "Profiles|Delete Account"
+msgstr ""
+
+msgid "Profiles|Delete account"
+msgstr ""
+
+msgid "Profiles|Delete your account?"
+msgstr ""
+
+msgid "Profiles|Deleting an account has the following effects:"
+msgstr ""
+
+msgid "Profiles|Invalid password"
+msgstr ""
+
+msgid "Profiles|Invalid username"
+msgstr ""
+
+msgid "Profiles|Type your %{confirmationValue} to confirm:"
+msgstr ""
+
+msgid "Profiles|You don't have access to delete this user."
+msgstr ""
+
+msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
+msgstr ""
+
+msgid "Profiles|Your account is currently an owner in these groups:"
+msgstr ""
+
+msgid "Profiles|your account"
+msgstr ""
+
+msgid "Programming languages used in this repository"
+msgstr ""
+
+msgid "Project '%{project_name}' is in the process of being deleted."
+msgstr ""
+
+msgid "Project '%{project_name}' queued for deletion."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully created."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully updated."
+msgstr ""
+
+msgid "Project access must be granted explicitly to each user."
+msgstr ""
+
+msgid "Project avatar"
+msgstr ""
+
+msgid "Project avatar in repository: %{link}"
+msgstr ""
+
+msgid "Project cache successfully reset."
+msgstr ""
+
+msgid "Project details"
+msgstr ""
+
+msgid "Project export could not be deleted."
+msgstr ""
+
+msgid "Project export has been deleted."
+msgstr ""
+
+msgid "Project export link has expired. Please generate a new export from your project settings."
+msgstr ""
+
+msgid "Project export started. A download link will be sent by email."
+msgstr ""
+
+msgid "ProjectActivityRSS|Subscribe"
+msgstr ""
+
+msgid "ProjectCreationLevel|Allowed to create projects"
+msgstr ""
+
+msgid "ProjectCreationLevel|Default project creation protection"
+msgstr ""
+
+msgid "ProjectCreationLevel|Developers + Masters"
+msgstr ""
+
+msgid "ProjectCreationLevel|Masters"
+msgstr ""
+
+msgid "ProjectCreationLevel|No one"
+msgstr ""
+
+msgid "ProjectFeature|Disabled"
+msgstr ""
+
+msgid "ProjectFeature|Everyone with access"
+msgstr ""
+
+msgid "ProjectFeature|Only team members"
+msgstr ""
+
+msgid "ProjectFileTree|Name"
+msgstr ""
+
+msgid "ProjectLastActivity|Never"
+msgstr ""
+
+msgid "ProjectLifecycle|Stage"
+msgstr ""
+
+msgid "ProjectNetworkGraph|Graph"
+msgstr ""
+
+msgid "ProjectSettings|Contact an admin to change this setting."
+msgstr ""
+
+msgid "ProjectSettings|Only signed commits can be pushed to this repository."
+msgstr ""
+
+msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
+msgstr ""
+
+msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
+msgstr ""
+
+msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
+msgstr ""
+
+msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
+msgstr ""
+
+msgid "Projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Frequently visited"
+msgstr ""
+
+msgid "ProjectsDropdown|Loading projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Projects you visit often will appear here"
+msgstr ""
+
+msgid "ProjectsDropdown|Search your projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Something went wrong on our end."
+msgstr ""
+
+msgid "ProjectsDropdown|Sorry, no projects matched your search"
+msgstr ""
+
+msgid "ProjectsDropdown|This feature requires browser localStorage support"
+msgstr ""
+
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
+msgid "PrometheusService|Time-series monitoring service"
+msgstr ""
+
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
+msgid "Protip:"
+msgstr ""
+
+msgid "Public - The group and any public projects can be viewed without any authentication."
+msgstr ""
+
+msgid "Public - The project can be accessed without any authentication."
+msgstr ""
+
+msgid "Push Rules"
+msgstr ""
+
+msgid "Push events"
+msgstr ""
+
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
+msgid "PushRule|Committer restriction"
+msgstr ""
+
+msgid "Quick actions can be used in the issues description and comment boxes."
+msgstr ""
+
+msgid "Read more"
+msgstr ""
+
+msgid "Readme"
+msgstr ""
+
+msgid "RefSwitcher|Branches"
+msgstr ""
+
+msgid "RefSwitcher|Tags"
+msgstr ""
+
+msgid "Reference:"
+msgstr ""
+
+msgid "Register / Sign In"
+msgstr ""
+
+msgid "Registry"
+msgstr ""
+
+msgid "Related Commits"
+msgstr ""
+
+msgid "Related Deployed Jobs"
+msgstr ""
+
+msgid "Related Issues"
+msgstr ""
+
+msgid "Related Jobs"
+msgstr ""
+
+msgid "Related Merge Requests"
+msgstr ""
+
+msgid "Related Merged Requests"
+msgstr ""
+
+msgid "Remind later"
+msgstr ""
+
+msgid "Remove"
+msgstr ""
+
+msgid "Remove avatar"
+msgstr ""
+
+msgid "Remove project"
+msgstr ""
+
+msgid "Repair authentication"
+msgstr ""
+
+msgid "Repository"
+msgstr ""
+
+msgid "Repository has no locks."
+msgstr ""
+
+msgid "Request Access"
+msgstr ""
+
+msgid "Reset git storage health information"
+msgstr ""
+
+msgid "Reset health check access token"
+msgstr ""
+
+msgid "Reset runners registration token"
+msgstr ""
+
+msgid "Resolve discussion"
+msgstr ""
+
+msgid "Reveal value"
+msgid_plural "Reveal values"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Revert this commit"
+msgstr ""
+
+msgid "Revert this merge request"
+msgstr ""
+
+msgid "Roadmap"
+msgstr ""
+
+msgid "SSH Keys"
+msgstr ""
+
+msgid "Save changes"
+msgstr ""
+
+msgid "Save pipeline schedule"
+msgstr ""
+
+msgid "Save variables"
+msgstr ""
+
+msgid "Schedule a new pipeline"
+msgstr ""
+
+msgid "Schedules"
+msgstr ""
+
+msgid "Scheduling Pipelines"
+msgstr ""
+
+msgid "Scoped issue boards"
+msgstr ""
+
+msgid "Search branches and tags"
+msgstr ""
+
+msgid "Search milestones"
+msgstr ""
+
+msgid "Search project"
+msgstr ""
+
+msgid "Search users"
+msgstr ""
+
+msgid "Seconds before reseting failure information"
+msgstr ""
+
+msgid "Seconds to wait for a storage access attempt"
+msgstr ""
+
+msgid "Secret variables"
+msgstr ""
+
+msgid "Security report"
+msgstr ""
+
+msgid "Select Archive Format"
+msgstr ""
+
+msgid "Select a timezone"
+msgstr ""
+
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
+msgid "Select assignee"
+msgstr ""
+
+msgid "Select branch/tag"
+msgstr ""
+
+msgid "Select target branch"
+msgstr ""
+
+msgid "Selective synchronization"
+msgstr ""
+
+msgid "Send email"
+msgstr ""
+
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
+msgid "Server version"
+msgstr ""
+
+msgid "Service Templates"
+msgstr ""
+
+msgid "Service URL"
+msgstr ""
+
+msgid "Set a password on your account to pull or push via %{protocol}."
+msgstr ""
+
+msgid "Set up CI/CD"
+msgstr ""
+
+msgid "Set up Koding"
+msgstr ""
+
+msgid "SetPasswordToCloneLink|set a password"
+msgstr ""
+
+msgid "Settings"
+msgstr ""
+
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
+msgstr ""
+
+msgid "Show command"
+msgstr ""
+
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
+msgid "Showing %d event"
+msgid_plural "Showing %d events"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
+msgid "Snippets"
+msgstr ""
+
+msgid "Something went wrong on our end"
+msgstr ""
+
+msgid "Something went wrong on our end."
+msgstr ""
+
+msgid "Something went wrong trying to change the confidentiality of this issue"
+msgstr ""
+
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr ""
+
+msgid "Something went wrong when toggling the button"
+msgstr ""
+
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
+msgid "Something went wrong while fetching the projects."
+msgstr ""
+
+msgid "Something went wrong while fetching the registry list."
+msgstr ""
+
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
+msgid "Something went wrong. Please try again."
+msgstr ""
+
+msgid "Sort by"
+msgstr ""
+
+msgid "SortOptions|Access level, ascending"
+msgstr ""
+
+msgid "SortOptions|Access level, descending"
+msgstr ""
+
+msgid "SortOptions|Created date"
+msgstr ""
+
+msgid "SortOptions|Due date"
+msgstr ""
+
+msgid "SortOptions|Due later"
+msgstr ""
+
+msgid "SortOptions|Due soon"
+msgstr ""
+
+msgid "SortOptions|Label priority"
+msgstr ""
+
+msgid "SortOptions|Largest group"
+msgstr ""
+
+msgid "SortOptions|Largest repository"
+msgstr ""
+
+msgid "SortOptions|Last created"
+msgstr ""
+
+msgid "SortOptions|Last joined"
+msgstr ""
+
+msgid "SortOptions|Last updated"
+msgstr ""
+
+msgid "SortOptions|Least popular"
+msgstr ""
+
+msgid "SortOptions|Less weight"
+msgstr ""
+
+msgid "SortOptions|Milestone"
+msgstr ""
+
+msgid "SortOptions|Milestone due later"
+msgstr ""
+
+msgid "SortOptions|Milestone due soon"
+msgstr ""
+
+msgid "SortOptions|More weight"
+msgstr ""
+
+msgid "SortOptions|Most popular"
+msgstr ""
+
+msgid "SortOptions|Name"
+msgstr ""
+
+msgid "SortOptions|Name, ascending"
+msgstr ""
+
+msgid "SortOptions|Name, descending"
+msgstr ""
+
+msgid "SortOptions|Oldest created"
+msgstr ""
+
+msgid "SortOptions|Oldest joined"
+msgstr ""
+
+msgid "SortOptions|Oldest sign in"
+msgstr ""
+
+msgid "SortOptions|Oldest updated"
+msgstr ""
+
+msgid "SortOptions|Popularity"
+msgstr ""
+
+msgid "SortOptions|Priority"
+msgstr ""
+
+msgid "SortOptions|Recent sign in"
+msgstr ""
+
+msgid "SortOptions|Start later"
+msgstr ""
+
+msgid "SortOptions|Start soon"
+msgstr ""
+
+msgid "SortOptions|Weight"
+msgstr ""
+
+msgid "Source"
+msgstr ""
+
+msgid "Source (branch or tag)"
+msgstr ""
+
+msgid "Source code"
+msgstr ""
+
+msgid "Source is not available"
+msgstr ""
+
+msgid "Spam Logs"
+msgstr ""
+
+msgid "Specify the following URL during the Runner setup:"
+msgstr ""
+
+msgid "StarProject|Star"
+msgstr ""
+
+msgid "Starred projects"
+msgstr ""
+
+msgid "Start a %{new_merge_request} with these changes"
+msgstr ""
+
+msgid "Start the Runner!"
+msgstr ""
+
+msgid "Stopped"
+msgstr ""
+
+msgid "Storage"
+msgstr ""
+
+msgid "Subgroups"
+msgstr ""
+
+msgid "Switch branch/tag"
+msgstr ""
+
+msgid "System Hooks"
+msgstr ""
+
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Tags"
+msgstr ""
+
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+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 ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
+msgid "Target Branch"
+msgstr ""
+
+msgid "Team"
+msgstr ""
+
+msgid "Thanks! Don't show me this again"
+msgstr ""
+
+msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
+msgstr ""
+
+msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
+msgstr ""
+
+msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project."
+msgstr ""
+
+msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
+msgstr ""
+
+msgid "The collection of events added to the data gathered for that stage."
+msgstr ""
+
+msgid "The fork relationship has been removed."
+msgstr ""
+
+msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
+msgstr ""
+
+msgid "The maximum file size allowed is 200KB."
+msgstr ""
+
+msgid "The number of attempts GitLab will make to access a storage."
+msgstr ""
+
+msgid "The number of failures of after which GitLab will completely prevent access to the storage. The number of failures can be reset in the admin interface: %{link_to_health_page} or using the %{api_documentation_link}."
+msgstr ""
+
+msgid "The phase of the development lifecycle."
+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 ""
+
+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 ""
+
+msgid "The project can be accessed without any authentication."
+msgstr ""
+
+msgid "The repository for this project does not exist."
+msgstr ""
+
+msgid "The repository for this project is empty"
+msgstr ""
+
+msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
+msgstr ""
+
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
+msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
+msgstr ""
+
+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 ""
+
+msgid "The time in seconds GitLab will keep failure information. When no failures occur during this time, information about the mount is reset."
+msgstr ""
+
+msgid "The time in seconds GitLab will try to access storage. After this time a timeout error will be raised."
+msgstr ""
+
+msgid "The time in seconds between storage checks. When a previous check did complete yet, GitLab will skip a check."
+msgstr ""
+
+msgid "The time taken by each data entry gathered by that stage."
+msgstr ""
+
+msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
+msgstr ""
+
+msgid "There are no issues to show"
+msgstr ""
+
+msgid "There are no merge requests to show"
+msgstr ""
+
+msgid "There are problems accessing Git storage: "
+msgstr ""
+
+msgid "There was an error loading users activity calendar."
+msgstr ""
+
+msgid "There was an error saving your notification settings."
+msgstr ""
+
+msgid "There was an error subscribing to this label."
+msgstr ""
+
+msgid "There was an error when reseting email token."
+msgstr ""
+
+msgid "There was an error when subscribing to this label."
+msgstr ""
+
+msgid "There was an error when unsubscribing from this label."
+msgstr ""
+
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
+msgid "This directory"
+msgstr ""
+
+msgid "This is a confidential issue."
+msgstr ""
+
+msgid "This is the author's first Merge Request to this project."
+msgstr ""
+
+msgid "This issue is confidential"
+msgstr ""
+
+msgid "This issue is confidential and locked."
+msgstr ""
+
+msgid "This issue is locked."
+msgstr ""
+
+msgid "This job depends on a user to trigger its process. Often they are used to deploy code to production environments"
+msgstr ""
+
+msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
+msgstr ""
+
+msgid "This job has not been triggered yet"
+msgstr ""
+
+msgid "This job has not started yet"
+msgstr ""
+
+msgid "This job is in pending state and is waiting to be picked by a runner"
+msgstr ""
+
+msgid "This job requires a manual action"
+msgstr ""
+
+msgid "This means you can not push code until you create an empty repository or import existing one."
+msgstr ""
+
+msgid "This merge request is locked."
+msgstr ""
+
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
+msgid "This project"
+msgstr ""
+
+msgid "This repository"
+msgstr ""
+
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
+msgid "Time before an issue gets scheduled"
+msgstr ""
+
+msgid "Time before an issue starts implementation"
+msgstr ""
+
+msgid "Time between merge request creation and merge/close"
+msgstr ""
+
+msgid "Time tracking"
+msgstr ""
+
+msgid "Time until first merge request"
+msgstr ""
+
+msgid "TimeTrackingEstimated|Est"
+msgstr ""
+
+msgid "TimeTracking|Estimated:"
+msgstr ""
+
+msgid "TimeTracking|Spent"
+msgstr ""
+
+msgid "Timeago|%s days ago"
+msgstr ""
+
+msgid "Timeago|%s days remaining"
+msgstr ""
+
+msgid "Timeago|%s hours remaining"
+msgstr ""
+
+msgid "Timeago|%s minutes ago"
+msgstr ""
+
+msgid "Timeago|%s minutes remaining"
+msgstr ""
+
+msgid "Timeago|%s months ago"
+msgstr ""
+
+msgid "Timeago|%s months remaining"
+msgstr ""
+
+msgid "Timeago|%s seconds remaining"
+msgstr ""
+
+msgid "Timeago|%s weeks ago"
+msgstr ""
+
+msgid "Timeago|%s weeks remaining"
+msgstr ""
+
+msgid "Timeago|%s years ago"
+msgstr ""
+
+msgid "Timeago|%s years remaining"
+msgstr ""
+
+msgid "Timeago|1 day remaining"
+msgstr ""
+
+msgid "Timeago|1 hour remaining"
+msgstr ""
+
+msgid "Timeago|1 minute remaining"
+msgstr ""
+
+msgid "Timeago|1 month remaining"
+msgstr ""
+
+msgid "Timeago|1 week remaining"
+msgstr ""
+
+msgid "Timeago|1 year remaining"
+msgstr ""
+
+msgid "Timeago|Past due"
+msgstr ""
+
+msgid "Timeago|a day ago"
+msgstr ""
+
+msgid "Timeago|a month ago"
+msgstr ""
+
+msgid "Timeago|a week ago"
+msgstr ""
+
+msgid "Timeago|a year ago"
+msgstr ""
+
+msgid "Timeago|about %s hours ago"
+msgstr ""
+
+msgid "Timeago|about a minute ago"
+msgstr ""
+
+msgid "Timeago|about an hour ago"
+msgstr ""
+
+msgid "Timeago|in %s days"
+msgstr ""
+
+msgid "Timeago|in %s hours"
+msgstr ""
+
+msgid "Timeago|in %s minutes"
+msgstr ""
+
+msgid "Timeago|in %s months"
+msgstr ""
+
+msgid "Timeago|in %s seconds"
+msgstr ""
+
+msgid "Timeago|in %s weeks"
+msgstr ""
+
+msgid "Timeago|in %s years"
+msgstr ""
+
+msgid "Timeago|in 1 day"
+msgstr ""
+
+msgid "Timeago|in 1 hour"
+msgstr ""
+
+msgid "Timeago|in 1 minute"
+msgstr ""
+
+msgid "Timeago|in 1 month"
+msgstr ""
+
+msgid "Timeago|in 1 week"
+msgstr ""
+
+msgid "Timeago|in 1 year"
+msgstr ""
+
+msgid "Timeago|in a while"
+msgstr ""
+
+msgid "Timeago|less than a minute ago"
+msgstr ""
+
+msgid "Time|hr"
+msgid_plural "Time|hrs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Time|min"
+msgid_plural "Time|mins"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Time|s"
+msgstr ""
+
+msgid "Tip:"
+msgstr ""
+
+msgid "Title"
+msgstr ""
+
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
+msgid "Todo"
+msgstr ""
+
+msgid "Toggle sidebar"
+msgstr ""
+
+msgid "ToggleButton|Toggle Status: OFF"
+msgstr ""
+
+msgid "ToggleButton|Toggle Status: ON"
+msgstr ""
+
+msgid "Total Time"
+msgstr ""
+
+msgid "Total test time for all commits/merges"
+msgstr ""
+
+msgid "Total: %{total}"
+msgstr ""
+
+msgid "Track activity with Contribution Analytics."
+msgstr ""
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Track time with quick actions"
+msgstr ""
+
+msgid "Trigger this manual action"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
+msgid "Unable to reset project cache."
+msgstr ""
+
+msgid "Unknown"
+msgstr ""
+
+msgid "Unlock"
+msgstr ""
+
+msgid "Unlock this %{issuableDisplayName}? <strong>Everyone</strong> will be able to comment."
+msgstr ""
+
+msgid "Unlocked"
+msgstr ""
+
+msgid "Unresolve discussion"
+msgstr ""
+
+msgid "Unstar"
+msgstr ""
+
+msgid "Up to date"
+msgstr ""
+
+msgid "Upgrade your plan to activate Advanced Global Search."
+msgstr ""
+
+msgid "Upgrade your plan to activate Contribution Analytics."
+msgstr ""
+
+msgid "Upgrade your plan to activate Group Webhooks."
+msgstr ""
+
+msgid "Upgrade your plan to activate Issue weight."
+msgstr ""
+
+msgid "Upgrade your plan to improve Issue boards."
+msgstr ""
+
+msgid "Upload New File"
+msgstr ""
+
+msgid "Upload file"
+msgstr ""
+
+msgid "Upload new avatar"
+msgstr ""
+
+msgid "UploadLink|click to upload"
+msgstr ""
+
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
+msgid "Use the following registration token during setup:"
+msgstr ""
+
+msgid "Use your global notification setting"
+msgstr ""
+
+msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
+msgstr ""
+
+msgid "View epics list"
+msgstr ""
+
+msgid "View file @ "
+msgstr ""
+
+msgid "View labels"
+msgstr ""
+
+msgid "View open merge request"
+msgstr ""
+
+msgid "View replaced file @ "
+msgstr ""
+
+msgid "VisibilityLevel|Internal"
+msgstr ""
+
+msgid "VisibilityLevel|Private"
+msgstr ""
+
+msgid "VisibilityLevel|Public"
+msgstr ""
+
+msgid "VisibilityLevel|Unknown"
+msgstr ""
+
+msgid "Want to see the data? Please ask an administrator for access."
+msgstr ""
+
+msgid "We could not verify that one of your projects on GCP has billing enabled. Please try again."
+msgstr ""
+
+msgid "We don't have enough data to show this stage."
+msgstr ""
+
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
+msgid "Web IDE"
+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 ""
+
+msgid "Weight"
+msgstr ""
+
+msgid "Wiki"
+msgstr ""
+
+msgid "WikiClone|Clone your wiki"
+msgstr ""
+
+msgid "WikiClone|Git Access"
+msgstr ""
+
+msgid "WikiClone|Install Gollum"
+msgstr ""
+
+msgid "WikiClone|It is recommended to install %{markdown} so that GFM features render locally:"
+msgstr ""
+
+msgid "WikiClone|Start Gollum and edit locally"
+msgstr ""
+
+msgid "WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title."
+msgstr ""
+
+msgid "WikiEdit|There is already a page with the same title in that path."
+msgstr ""
+
+msgid "WikiEmptyPageError|You are not allowed to create wiki pages"
+msgstr ""
+
+msgid "WikiHistoricalPage|This is an old version of this page."
+msgstr ""
+
+msgid "WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}."
+msgstr ""
+
+msgid "WikiHistoricalPage|history"
+msgstr ""
+
+msgid "WikiHistoricalPage|most recent version"
+msgstr ""
+
+msgid "WikiMarkdownDocs|More examples are in the %{docs_link}"
+msgstr ""
+
+msgid "WikiMarkdownDocs|documentation"
+msgstr ""
+
+msgid "WikiMarkdownTip|To link to a (new) page, simply type %{link_example}"
+msgstr ""
+
+msgid "WikiNewPagePlaceholder|how-to-setup"
+msgstr ""
+
+msgid "WikiNewPageTip|Tip: You can specify the full path for the new file. We will automatically create any missing directories."
+msgstr ""
+
+msgid "WikiNewPageTitle|New Wiki Page"
+msgstr ""
+
+msgid "WikiPageConfirmDelete|Are you sure you want to delete this page?"
+msgstr ""
+
+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 ""
+
+msgid "WikiPageCreate|Create %{page_title}"
+msgstr ""
+
+msgid "WikiPageEdit|Update %{page_title}"
+msgstr ""
+
+msgid "WikiPage|Page slug"
+msgstr ""
+
+msgid "WikiPage|Write your content or drag files here..."
+msgstr ""
+
+msgid "Wiki|Create Page"
+msgstr ""
+
+msgid "Wiki|Create page"
+msgstr ""
+
+msgid "Wiki|Edit Page"
+msgstr ""
+
+msgid "Wiki|Empty page"
+msgstr ""
+
+msgid "Wiki|More Pages"
+msgstr ""
+
+msgid "Wiki|New page"
+msgstr ""
+
+msgid "Wiki|Page history"
+msgstr ""
+
+msgid "Wiki|Page version"
+msgstr ""
+
+msgid "Wiki|Pages"
+msgstr ""
+
+msgid "Wiki|Wiki Pages"
+msgstr ""
+
+msgid "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 ""
+
+msgid "Withdraw Access Request"
+msgstr ""
+
+msgid "Write a commit message..."
+msgstr ""
+
+msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You can also create a project from the command line."
+msgstr ""
+
+msgid "You can also star a label to make it a priority label."
+msgstr ""
+
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
+msgstr ""
+
+msgid "You can move around the graph by using the arrow keys."
+msgstr ""
+
+msgid "You can only add files when you are on a branch"
+msgstr ""
+
+msgid "You can only edit files when you are on a branch"
+msgstr ""
+
+msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
+msgstr ""
+
+msgid "You cannot write to this read-only GitLab instance."
+msgstr ""
+
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
+msgid "You have reached your project limit"
+msgstr ""
+
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
+msgid "You must sign in to star a project"
+msgstr ""
+
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
+msgid "You need permission."
+msgstr ""
+
+msgid "You will not get any notifications via email"
+msgstr ""
+
+msgid "You will only receive notifications for the events you choose"
+msgstr ""
+
+msgid "You will only receive notifications for threads you have participated in"
+msgstr ""
+
+msgid "You will receive notifications for any activity"
+msgstr ""
+
+msgid "You will receive notifications only for comments in which you were @mentioned"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
+msgid "You'll need to use different branch names to get a valid comparison."
+msgstr ""
+
+msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
+msgstr ""
+
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
+msgid "Your comment will not be visible to the public."
+msgstr ""
+
+msgid "Your groups"
+msgstr ""
+
+msgid "Your name"
+msgstr ""
+
+msgid "Your projects"
+msgstr ""
+
+msgid "assign yourself"
+msgstr ""
+
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
+msgid "ciReport|Code quality"
+msgstr ""
+
+msgid "ciReport|DAST detected no alerts by analyzing the review app"
+msgstr ""
+
+msgid "ciReport|Failed to load %{reportName} report"
+msgstr ""
+
+msgid "ciReport|Fixed:"
+msgstr ""
+
+msgid "ciReport|Instances"
+msgstr ""
+
+msgid "ciReport|Learn more about whitelisting"
+msgstr ""
+
+msgid "ciReport|Loading %{reportName} report"
+msgstr ""
+
+msgid "ciReport|No changes to code quality"
+msgstr ""
+
+msgid "ciReport|No changes to performance metrics"
+msgstr ""
+
+msgid "ciReport|Performance metrics"
+msgstr ""
+
+msgid "ciReport|SAST"
+msgstr ""
+
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
+msgid "ciReport|SAST detected no security vulnerabilities"
+msgstr ""
+
+msgid "ciReport|SAST:container no vulnerabilities were found"
+msgstr ""
+
+msgid "ciReport|Show complete code vulnerabilities report"
+msgstr ""
+
+msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
+msgstr ""
+
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
+msgid "confidentiality|You are going to turn off the confidentiality. This means <strong>everyone</strong> will be able to see and leave a comment on this issue."
+msgstr ""
+
+msgid "confidentiality|You are going to turn on the confidentiality. This means that only team members with <strong>at least Reporter access</strong> are able to see and leave comments on the issue."
+msgstr ""
+
+msgid "day"
+msgid_plural "days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
+msgstr ""
+
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
+msgid "merge request"
+msgid_plural "merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
+msgid "mrWidget|Cancel automatic merge"
+msgstr ""
+
+msgid "mrWidget|Check out branch"
+msgstr ""
+
+msgid "mrWidget|Checking ability to merge automatically"
+msgstr ""
+
+msgid "mrWidget|Cherry-pick"
+msgstr ""
+
+msgid "mrWidget|Cherry-pick this merge request in a new merge request"
+msgstr ""
+
+msgid "mrWidget|Closed"
+msgstr ""
+
+msgid "mrWidget|Closed by"
+msgstr ""
+
+msgid "mrWidget|Closes"
+msgstr ""
+
+msgid "mrWidget|Did not close"
+msgstr ""
+
+msgid "mrWidget|Email patches"
+msgstr ""
+
+msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
+msgstr ""
+
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
+msgid "mrWidget|Mentions"
+msgstr ""
+
+msgid "mrWidget|Merge"
+msgstr ""
+
+msgid "mrWidget|Merge failed."
+msgstr ""
+
+msgid "mrWidget|Merge locally"
+msgstr ""
+
+msgid "mrWidget|Merged by"
+msgstr ""
+
+msgid "mrWidget|Plain diff"
+msgstr ""
+
+msgid "mrWidget|Refresh"
+msgstr ""
+
+msgid "mrWidget|Refresh now"
+msgstr ""
+
+msgid "mrWidget|Refreshing now"
+msgstr ""
+
+msgid "mrWidget|Remove Source Branch"
+msgstr ""
+
+msgid "mrWidget|Remove source branch"
+msgstr ""
+
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
+msgid "mrWidget|Request to merge"
+msgstr ""
+
+msgid "mrWidget|Resolve conflicts"
+msgstr ""
+
+msgid "mrWidget|Revert"
+msgstr ""
+
+msgid "mrWidget|Revert this merge request in a new merge request"
+msgstr ""
+
+msgid "mrWidget|Set by"
+msgstr ""
+
+msgid "mrWidget|The changes were merged into"
+msgstr ""
+
+msgid "mrWidget|The changes were not merged into"
+msgstr ""
+
+msgid "mrWidget|The changes will be merged into"
+msgstr ""
+
+msgid "mrWidget|The source branch has been removed"
+msgstr ""
+
+msgid "mrWidget|The source branch is being removed"
+msgstr ""
+
+msgid "mrWidget|The source branch will be removed"
+msgstr ""
+
+msgid "mrWidget|The source branch will not be removed"
+msgstr ""
+
+msgid "mrWidget|There are merge conflicts"
+msgstr ""
+
+msgid "mrWidget|This merge request failed to be merged automatically"
+msgstr ""
+
+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 ""
+
+msgid "mrWidget|You can merge this merge request manually using the"
+msgstr ""
+
+msgid "mrWidget|You can remove source branch now"
+msgstr ""
+
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
+msgid "mrWidget|command line"
+msgstr ""
+
+msgid "mrWidget|into"
+msgstr ""
+
+msgid "mrWidget|to be merged automatically when the pipeline succeeds"
+msgstr ""
+
+msgid "new merge request"
+msgstr ""
+
+msgid "notification emails"
+msgstr ""
+
+msgid "or"
+msgstr ""
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "password"
+msgstr ""
+
+msgid "personal access token"
+msgstr ""
+
+msgid "remove due date"
+msgstr ""
+
+msgid "source"
+msgstr ""
+
+msgid "spendCommand|%{slash_command} will update the sum of the time spent."
+msgstr ""
+
+msgid "to help your contributors communicate effectively!"
+msgstr ""
+
+msgid "username"
+msgstr ""
+
+msgid "uses Kubernetes clusters to deploy your code!"
+msgstr ""
+
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index f775a511780..44dbbe8141b 100644
--- a/locale/uk/gitlab.po
+++ b/locale/uk/gitlab.po
@@ -2,15 +2,15 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 06:15-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:20-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Ukrainian\n"
"Language: uk_UA\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: gitlab-ee\n"
"X-Crowdin-Language: uk\n"
@@ -24,36 +24,45 @@ msgid_plural "%d commits"
msgstr[0] "%d коміт"
msgstr[1] "%d коміта"
msgstr[2] "%d комітів"
+msgstr[3] "%d комітів"
msgid "%d commit behind"
msgid_plural "%d commits behind"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%d коміт позаду"
+msgstr[1] "%d коміта позаду"
+msgstr[2] "%d комітів позаду"
+msgstr[3] "%d комітів позаду"
msgid "%d issue"
msgid_plural "%d issues"
msgstr[0] "%d проблема"
msgstr[1] "%d проблеми"
msgstr[2] "%d проблем"
+msgstr[3] "%d проблем"
msgid "%d layer"
msgid_plural "%d layers"
msgstr[0] "%d шар"
msgstr[1] "%d шари"
msgstr[2] "%d шарів"
+msgstr[3] "%d шарів"
msgid "%d merge request"
msgid_plural "%d merge requests"
msgstr[0] "%d запит на злиттÑ"
msgstr[1] "%d запита на злиттÑ"
msgstr[2] "%d запитів на злиттÑ"
+msgstr[3] "%d запитів на злиттÑ"
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s доданий коміт був виключений Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ із швидкодією."
msgstr[1] "%s доданих коміта були виключені Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ із швидкодією."
msgstr[2] "%s доданих комітів були виключені Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ із швидкодією."
+msgstr[3] "%s доданих комітів були виключені Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ із швидкодією."
+
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr "%{actionText} Ñ– %{openOrClose} %{noteable}"
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} закомітив %{commit_timeago}"
@@ -63,6 +72,10 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} учаÑтник"
msgstr[1] "%{count} учаÑтника"
msgstr[2] "%{count} учаÑтників"
+msgstr[3] "%{count} учаÑтників"
+
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr "%{lock_path} заблоковано кориÑтувачем GitLab %{lock_user_id}"
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr "на %{number_commits_behind} комітів позаду %{default_branch}, на %{number_commits_ahead} комітів попереду"
@@ -73,11 +86,15 @@ msgstr "%{number_of_failures} від %{maximum_failures} невдач. GitLab н
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "%{number_of_failures} від %{maximum_failures} невдач. GitLab автоматично не повторюватиме Ñпробу. Скиньте інформацію Ñховища при уÑуненні проблеми."
+msgid "%{openOrClose} %{noteable}"
+msgstr "%{openOrClose} %{noteable}"
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}: Ñпроба невдалого доÑтупу до Ñховища на хоÑÑ‚Ñ–:"
msgstr[1] "%{storage_name}: %{failed_attempts} невдалі Ñпроби доÑтупу до Ñховища:"
msgstr[2] "%{storage_name}: %{failed_attempts} невдалих Ñпроб доÑтупу до Ñховища:"
+msgstr[3] "%{storage_name}: %{failed_attempts} невдалих Ñпроб доÑтупу до Ñховища:"
msgid "%{text} is available"
msgstr "%{text} доÑтупний"
@@ -96,6 +113,7 @@ msgid_plural "%d pipelines"
msgstr[0] "1 конвеєр"
msgstr[1] "%d конвеєра"
msgstr[2] "%d конвеєрів"
+msgstr[3] "%d конвеєрів"
msgid "1st contribution!"
msgstr "Перший внеÑок!"
@@ -139,9 +157,15 @@ msgstr "Додати керівництво Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr "Додайте групові веб-гуки та GitLab Enterprise Edition."
+msgid "Add Kubernetes cluster"
+msgstr "Додати Kubernetes-клаÑтер"
+
msgid "Add License"
msgstr "Додати ліцензію"
+msgid "Add Readme"
+msgstr "Додати інÑтрукцію"
+
msgid "Add new directory"
msgstr "Додати новий каталог"
@@ -160,12 +184,45 @@ msgstr "Зупинити завданнÑ"
msgid "AdminArea|Stopping jobs failed"
msgstr "Зупинка завдань пройшла невдало"
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
-msgstr ""
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
+msgstr "Зараз ви зупинете вÑÑ– завданнÑ. Це обірве уÑÑ– запущені завданнÑ."
msgid "AdminHealthPageLink|health page"
msgstr "Ñторінка ÑтатуÑу"
+msgid "AdminProjects|Delete"
+msgstr "Видалити"
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr "Видалити проект %{projectName}?"
+
+msgid "AdminProjects|Delete project"
+msgstr "Видалити проект"
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr "Вкажіть домен, Ñкий буде викориÑтовуватиÑÑ Ð² проекті за замовчуваннÑм Ð´Ð»Ñ Ñтадій Auto Review Apps Ñ– Auto Deploy."
+
+msgid "AdminUsers|Block user"
+msgstr "Заблоквати кориÑтувача"
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr "Видалити кориÑтувача %{username} та його внеÑки?"
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr "Видалити кориÑтувача %{username}?"
+
+msgid "AdminUsers|Delete user"
+msgstr "Видалити кориÑтувача"
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr "Видалити кориÑтувача Ñ– його внеÑки"
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr "Ð”Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ð²ÐµÐ´Ñ–Ñ‚ÑŒ %{projectName}"
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr "Ð”Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ð²ÐµÐ´Ñ–Ñ‚ÑŒ %{username}"
+
msgid "Advanced"
msgstr "Розширений"
@@ -176,13 +233,13 @@ msgid "All"
msgstr "Ð’ÑÑ–"
msgid "All changes are committed"
-msgstr ""
+msgstr "Ð’ÑÑ– зміни закомічені"
msgid "Allows you to add and manage Kubernetes clusters."
-msgstr ""
+msgstr "ДозволÑÑ” додавати та керувати клаÑтерами Kubernetes."
msgid "An error occurred previewing the blob"
-msgstr ""
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½ÑŒÐ¾Ð³Ð¾ переглÑду об'єкта"
msgid "An error occurred when toggling the notification subscription"
msgstr "Виникла помилка під Ñ‡Ð°Ñ Ð·Ð¼Ñ–Ð½Ð¸ підпиÑки на ÑповіщеннÑ"
@@ -190,36 +247,72 @@ msgstr "Виникла помилка під Ñ‡Ð°Ñ Ð·Ð¼Ñ–Ð½Ð¸ підпиÑки
msgid "An error occurred when updating the issue weight"
msgstr "Збій під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð²Ð°Ð³Ð¸ проблеми"
+msgid "An error occurred while adding approver"
+msgstr "Помилка при додаванні учаÑника Ð´Ð»Ñ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ"
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
msgid "An error occurred while fetching markdown preview"
-msgstr ""
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при попередньому переглÑді markdown"
msgid "An error occurred while fetching sidebar data"
msgstr "Виникла помилка під Ñ‡Ð°Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… Ð´Ð»Ñ Ð±Ñ–Ñ‡Ð½Ð¾Ñ— панелі"
+msgid "An error occurred while fetching the pipeline."
+msgstr "Помилка при отриманні данних конвеєра."
+
msgid "An error occurred while getting projects"
-msgstr ""
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при отриманні проектів"
+
+msgid "An error occurred while importing project"
+msgstr "Помилка при імпорті проекту"
+
+msgid "An error occurred while initializing path locks"
+msgstr "Помилка при ініціалізації Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð²Ð¸Ñ… шлÑхів"
+
+msgid "An error occurred while loading commits"
+msgstr "Помилка при завантажені комітів"
+
+msgid "An error occurred while loading diff"
+msgstr "Помилка при завантаженні разниці (diff)"
msgid "An error occurred while loading filenames"
-msgstr ""
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при завантаженні файлів"
+
+msgid "An error occurred while loading the file"
+msgstr "Помилка при завантаженні файлу"
+
+msgid "An error occurred while making the request."
+msgstr "Помилка при Ñтворенні запиту."
+
+msgid "An error occurred while removing approver"
+msgstr "Помилка при видаленні учаÑника Ð´Ð»Ñ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ"
msgid "An error occurred while rendering KaTeX"
-msgstr ""
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при рендерингу KaTeX"
msgid "An error occurred while rendering preview broadcast message"
msgstr ""
msgid "An error occurred while retrieving calendar activity"
-msgstr ""
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при отриманні ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ð¾ÑÑ‚Ñ–"
msgid "An error occurred while retrieving diff"
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при отриманні різниці"
+
+msgid "An error occurred while saving LDAP override status. Please try again."
msgstr ""
-msgid "An error occurred while validating username"
+msgid "An error occurred while saving assignees"
msgstr ""
+msgid "An error occurred while validating username"
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ імені кориÑтувача"
+
msgid "An error occurred. Please try again."
msgstr "СталаÑÑŒ помилка. Спробуйте ще раз."
@@ -241,15 +334,15 @@ msgstr "Заархівований проект! Репозиторій доÑÑ‚
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Ви впевнені, що хочете видалити цей розклад Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð°?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "Ви впевнені, що бажаєте ÑкаÑувати ваші зміни?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "Ви впевнені, що бажаєте Ñкинути реєÑтраційний токен?"
msgid "Are you sure you want to reset the health check token?"
msgstr "Ви впевнені, що хочете Ñкинути цей ключ перевірки працездатноÑÑ‚Ñ–?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr "Ви впевнені, що хочете розблокувати %{path_lock_path}?"
+
msgid "Are you sure?"
msgstr "Ви впевнені?"
@@ -289,11 +382,14 @@ msgstr "Ðвтор"
msgid "Authors: %{authors}"
msgstr "Ðвтори: %{authors}"
+msgid "Auto DevOps enabled"
+msgstr "Auto DevOps увімкнено"
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
-msgstr ""
+msgstr "Ð”Ð»Ñ ÐºÐ¾Ñ€ÐµÐºÑ‚Ð½Ð¾Ñ— роботи Auto Review Apps та Auto Deploy необхіден %{kubernetes}."
msgid "Auto Review Apps and Auto Deploy need a domain name and a %{kubernetes} to work correctly."
-msgstr ""
+msgstr "Ð”Ð»Ñ ÐºÐ¾Ñ€ÐµÐºÑ‚Ð½Ð¾Ñ— роботи Auto Review Apps та Auto Deploy необхідно вказати доменне Ñ–Ð¼â€™Ñ Ñ‚Ð° %{kubernetes}."
msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
msgstr "Ð”Ð»Ñ ÐºÐ¾Ñ€ÐµÐºÑ‚Ð½Ð¾Ñ— роботи Auto Review Apps та Auto Deploy необхідно вказати доменне ім’Ñ."
@@ -313,8 +409,14 @@ msgstr "AutoDevOps буде автоматично збирати, теÑтувÐ
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ в %{link_to_documentation}"
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
-msgstr "Ви можете активувати %{link_to_settings} Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr "Ви можете автоматично збирати й теÑтувати ваш заÑтоÑунок, Ñкщо %{link_to_auto_devops_settings} Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту. Ви також можете його автоматично розгортати, Ñкщо %{link_to_add_kubernetes_cluster}."
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr "додати Kubernetes-клаÑтер"
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr "Увімкнути Auto DevOps (Beta)"
msgid "Available"
msgstr "ДоÑтупний"
@@ -325,6 +427,9 @@ msgstr "Ðватар буде видалено. Ви впевнені?"
msgid "Average per day: %{average}"
msgstr "Ð’ Ñередньому за день: %{average}"
+msgid "Begin with the selected commit"
+msgstr "Почати із виділеного коміту"
+
msgid "Billing"
msgstr "Білінг"
@@ -379,14 +484,12 @@ msgstr "ОплачуєтьÑÑ Ñ‰Ð¾Ñ€Ñ–Ñ‡Ð½Ð¾ %{price_per_year}"
msgid "BillingPlans|per user"
msgstr "за кориÑтувача"
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "Гілка"
-msgstr[1] "Гілки"
-msgstr[2] "Гілок"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] "Гілка (%{branch_count})"
+msgstr[1] "Гілки (%{branch_count})"
+msgstr[2] "Гілок (%{branch_count})"
+msgstr[3] "Гілок (%{branch_count})"
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "Гілка <strong>%{branch_name}</strong> Ñтворена. Ð”Ð»Ñ Ð½Ð°Ñтройки автоматичного Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð²Ð¸Ð±ÐµÑ€Ñ–Ñ‚ÑŒ GitLab CI Yaml-шаблон Ñ– закомітьте зміни. %{link_to_autodeploy_doc}"
@@ -491,7 +594,7 @@ msgid "Branches|project settings"
msgstr "ÐалаштуваннÑÑ… проекту"
msgid "Branches|protected"
-msgstr "захищені"
+msgstr "захищена"
msgid "Browse Directory"
msgstr "ПереглÑнути каталог"
@@ -524,7 +627,7 @@ msgid "Cancel edit"
msgstr "Відмінити правку"
msgid "Cannot modify managed Kubernetes cluster"
-msgstr ""
+msgstr "Ðеможливо змінити керований клаÑтер Kubernetes"
msgid "Change Weight"
msgstr "Вага зміни"
@@ -542,7 +645,7 @@ msgid "ChangeTypeAction|Revert"
msgstr "Ðнулювати коміт"
msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
-msgstr ""
+msgstr "Це Ñтворить новий коміт, щоб анулювати Ñ–Ñнуючі зміни."
msgid "Changelog"
msgstr "СпиÑок змін"
@@ -575,16 +678,16 @@ msgid "Choose File ..."
msgstr "Виберіть файл ..."
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 "Виберіть гілку чи тег (напр. %{master}) або введіть коміт (напр. %{sha}) Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду змін або Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на злиттÑ."
msgid "Choose file..."
msgstr "Виберіть файл..."
msgid "Choose which groups you wish to synchronize to this secondary node."
-msgstr ""
+msgstr "Виберіть групи Ð´Ð»Ñ Ñинхронізації на цей вторинний вузол."
msgid "Choose which shards you wish to synchronize to this secondary node."
-msgstr ""
+msgstr "Виберіть Ñегменти Ð´Ð»Ñ Ñинхронізації на цей вторинний вузол."
msgid "CiStatusLabel|canceled"
msgstr "ÑкаÑовано"
@@ -647,7 +750,7 @@ msgid "CiVariables|Input variable value"
msgstr "Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð²Ñ…Ñ–Ð´Ð½Ð¾Ñ— змінної"
msgid "CiVariables|Remove variable row"
-msgstr ""
+msgstr "Видалити Ñ€Ñдок змінних"
msgid "CiVariable|* (All environments)"
msgstr "* (Ð’ÑÑ– Ñередовища)"
@@ -656,10 +759,10 @@ msgid "CiVariable|All environments"
msgstr "Ð’ÑÑ– Ñередовища"
msgid "CiVariable|Create wildcard"
-msgstr ""
+msgstr "Створити шаблон"
msgid "CiVariable|Error occured while saving variables"
-msgstr ""
+msgstr "Помилка при збереженні змінних"
msgid "CiVariable|New environment"
msgstr "Ðове Ñередовище"
@@ -668,10 +771,10 @@ msgid "CiVariable|Protected"
msgstr "Захищений"
msgid "CiVariable|Search environments"
-msgstr ""
+msgstr "Пошук Ñередовищ"
msgid "CiVariable|Toggle protected"
-msgstr ""
+msgstr "Ввімкнути/вимкнути захиÑÑ‚"
msgid "CiVariable|Validation failed"
msgstr "Перевірка невдала"
@@ -679,6 +782,9 @@ msgstr "Перевірка невдала"
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr "circuitbreaker api"
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr "ÐатиÑніть кнопку нижче, щоб розпочати Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð²ÑтановленнÑ, перейшовши на Ñторінку Kubernetes"
+
msgid "Click to expand text"
msgstr "ÐатиÑніть, щоб розгорнути текÑÑ‚"
@@ -733,6 +839,9 @@ msgstr "Скопіювати URL API"
msgid "ClusterIntegration|Copy CA Certificate"
msgstr "Скопіювати Ñертифікат центру Ñертифікації"
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr "Копіювати IP-адреÑу Ingress в буфер обміну"
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr "Скопіювати Ñ–Ð¼â€™Ñ Kubernetes-клаÑтера"
@@ -781,6 +890,9 @@ msgstr "Helm Tiller"
msgid "ClusterIntegration|Ingress"
msgstr "Ingress"
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr "Ingress IP-адреÑа"
+
msgid "ClusterIntegration|Install"
msgstr "Ð’Ñтановити"
@@ -791,7 +903,7 @@ msgid "ClusterIntegration|Installing"
msgstr "Ð’ÑтановленнÑ"
msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr ""
+msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ ÐºÐ»Ð°Ñтерної автоматизації Kubernetes"
msgid "ClusterIntegration|Integration status"
msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ—"
@@ -812,29 +924,26 @@ msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this pro
msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Ñ–Ð· Kubernetes-клаÑтером увімкнена Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту."
msgid "ClusterIntegration|Kubernetes cluster integration is enabled for this project. Disabling this integration will not affect your Kubernetes cluster, it will only temporarily turn off GitLab's connection to it."
-msgstr ""
+msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Ñ–Ð· Kubernetes-клаÑтером увімкнена Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту. Ð’Ð¸Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ñ†Ñ–Ñ”Ñ— інтеграції не вплине на клаÑтер, а лише тимчаÑово перерве Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· GitLab."
msgid "ClusterIntegration|Kubernetes cluster is being created on Google Kubernetes Engine..."
-msgstr ""
+msgstr "Kubernetes-клаÑтер ÑтворюєтьÑÑ Ð½Ð° Google Kubernetes Engine..."
msgid "ClusterIntegration|Kubernetes cluster name"
msgstr "Ð†Ð¼â€™Ñ Kubernetes-клаÑтера"
msgid "ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine. Refresh the page to see Kubernetes cluster's details"
-msgstr ""
+msgstr "Kubernetes-клаÑтер був уÑпішно Ñтворений на Google Kubernetes Engine. Оновіть Ñторінку, щоб побачити параметри клаÑтера"
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
-msgstr ""
+msgstr "Kubernetes-клаÑтери дозволÑÑŽÑ‚ÑŒ вам викориÑтовувати Review Apps, розгортати ваші заÑтоÑунки, запуÑкати конвеєри Ñ– багато іншого проÑтим ÑпоÑобом. %{link_to_help_page}"
msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
+msgstr "Kubernetes-клаÑтери можуть бути викориÑтані Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð·Ð°ÑтоÑунків Ñ– викориÑÑ‚Ð°Ð½Ð½Ñ Review Apps Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту"
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про %{link_to_documentation}"
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Kubernetes"
-
msgid "ClusterIntegration|Learn more about environments"
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Ñередовища"
@@ -842,19 +951,19 @@ msgid "ClusterIntegration|Machine type"
msgstr "Тип машини"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
-msgstr ""
+msgstr "ВпевнітьÑÑ, що ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð·Ð°Ð´Ð¾Ð²Ñ–Ð»ÑŒÐ½ÑÑ” %{link_to_requirements} Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Kubernetes-клаÑтерів"
msgid "ClusterIntegration|Manage"
msgstr "УправліннÑ"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
-msgstr ""
+msgstr "Керуйте вашим Kubernetes-клаÑтером за допомогою %{link_gke}"
msgid "ClusterIntegration|More information"
msgstr "Додаткова інформаціÑ"
msgid "ClusterIntegration|Multiple Kubernetes clusters are available in GitLab Enterprise Edition Premium and Ultimate"
-msgstr ""
+msgstr "Декілька Kubernetes-клаÑтерів доÑтупні в GitLab Enterprise Edition Premium та Ultimate"
msgid "ClusterIntegration|Note:"
msgstr "Примітка:"
@@ -863,7 +972,7 @@ msgid "ClusterIntegration|Number of nodes"
msgstr "КількіÑÑ‚ÑŒ вузлів"
msgid "ClusterIntegration|Please enter access information for your Kubernetes cluster. If you need help, you can read our %{link_to_help_page} on Kubernetes"
-msgstr ""
+msgstr "Введіть інформацію про доÑтуп до Ñвого Kubernetes-клаÑтера. Якщо вам потрібна допомога, ви можете прочитати наші %{link_to_help_page} про Kubernetes"
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr "Будь-лаÑка впевнітьÑÑ, що ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Google задовольнÑÑ” наÑтупним вимогам:"
@@ -881,7 +990,7 @@ msgid "ClusterIntegration|Prometheus"
msgstr "Prometheus"
msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration."
-msgstr ""
+msgstr "ПереглÑньте нашу %{link_to_help_page} про інтеграцію із Kubernetes."
msgid "ClusterIntegration|Remove Kubernetes cluster integration"
msgstr "Відалити інтеграцію із Kubernetes-клаÑтером"
@@ -890,7 +999,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 ""
+msgstr "Видалити конфігурацію Kubernetes-клаÑтера Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту. Це не призведе до Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñамого клаÑтера."
msgid "ClusterIntegration|Request to begin installing failed"
msgstr "Запит про початок вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ðµ виконано"
@@ -899,7 +1008,7 @@ msgid "ClusterIntegration|Save changes"
msgstr "Зберегти зміни"
msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
-msgstr ""
+msgstr "ПереглÑнути та редагувати параметри вашого Kubernetes-клаÑтера"
msgid "ClusterIntegration|See machine types"
msgstr "ПереглÑнути типи машин"
@@ -920,13 +1029,13 @@ msgid "ClusterIntegration|Something went wrong on our end."
msgstr "ЩоÑÑŒ пішло не так з нашого боку."
msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster on Google Kubernetes Engine"
-msgstr ""
+msgstr "Помилка при Ñтворенні вашого Kubernetes-клаÑтера на Google Kubernetes Engine"
msgid "ClusterIntegration|Something went wrong while installing %{title}"
msgstr "Під Ñ‡Ð°Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ %{title} ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°"
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
-msgstr ""
+msgstr "Цей обліковий Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð¾Ð²Ð¸Ð½ÐµÐ½ мати наÑтупні права Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Kubernetes-клаÑтера в %{link_to_container_project}"
msgid "ClusterIntegration|Toggle Kubernetes Cluster"
msgstr "Увімкнути/вимкнути Kubernetes-клаÑтер"
@@ -938,7 +1047,7 @@ msgid "ClusterIntegration|Token"
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 ""
+msgstr "За допомогою підключеного до цього проекту Kubernetes-клаÑтера, ви можете викориÑтовувати Review Apps, розгортати ваші проекти, запуÑкати конвеєри збірки тощо."
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
msgstr "Ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð¾Ð²Ð¸Ð½ÐµÐ½ мати %{link_to_kubernetes_engine}"
@@ -950,7 +1059,7 @@ msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr "доÑтуп до Google Kubernetes Engine"
msgid "ClusterIntegration|check the pricing here"
-msgstr ""
+msgstr "переглÑнути ціни тут"
msgid "ClusterIntegration|documentation"
msgstr "документації"
@@ -970,6 +1079,12 @@ msgstr "правильно налаштований"
msgid "Collapse"
msgstr "Згорнути"
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "Коментарі"
@@ -978,6 +1093,14 @@ msgid_plural "Commits"
msgstr[0] "Коміт"
msgstr[1] "Коміта"
msgstr[2] "Комітів"
+msgstr[3] "Комітів"
+
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] "Коміт (%{commit_count})"
+msgstr[1] "Коміта (%{commit_count})"
+msgstr[2] "Комітів (%{commit_count})"
+msgstr[3] "Комітів (%{commit_count})"
msgid "Commit Message"
msgstr "Коміт-повідомелннÑ"
@@ -989,7 +1112,10 @@ msgid "Commit message"
msgstr "Коміт-повідомленнÑ"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
-msgstr ""
+msgstr "СтатиÑтика комітів Ð´Ð»Ñ %{ref} %{start_time} - %{end_time}"
+
+msgid "Commit to %{branchName} branch"
+msgstr "Закомітити в гілку %{branchName}"
msgid "CommitBoxTitle|Commit"
msgstr "Коміт"
@@ -1004,16 +1130,16 @@ msgid "Commits feed"
msgstr "Канал комітів"
msgid "Commits per day hour (UTC)"
-msgstr ""
+msgstr "Комітів по годинам Ð´Ð½Ñ (за Грінвічем)"
msgid "Commits per day of month"
-msgstr ""
+msgstr "Комітів по днÑм міÑÑцÑ"
msgid "Commits per weekday"
-msgstr ""
+msgstr "Комітів по днÑм тижнÑ"
msgid "Commits|An error occurred while fetching merge requests data."
-msgstr ""
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… запиту на злиттÑ."
msgid "Commits|Commit: %{commitText}"
msgstr "Коміт: %{commitText}"
@@ -1022,7 +1148,7 @@ msgid "Commits|History"
msgstr "ІÑторіÑ"
msgid "Commits|No related merge requests found"
-msgstr ""
+msgstr "Ðе знайдено пов'Ñзаних запитів на злиттÑ"
msgid "Committed by"
msgstr "Коміт від"
@@ -1031,13 +1157,13 @@ msgid "Compare"
msgstr "ПорівнÑти"
msgid "Compare Git revisions"
-msgstr ""
+msgstr "ПорівнÑти Git-редакції"
msgid "Compare Revisions"
msgstr "ПорівнÑÐ½Ð½Ñ Ñ€ÐµÐ´Ð°ÐºÑ†Ñ–Ð¹"
msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
-msgstr ""
+msgstr "%{source_branch} і %{target_branch} однакові."
msgid "CompareBranches|Compare"
msgstr "ПорівнÑти"
@@ -1046,7 +1172,7 @@ msgid "CompareBranches|Source"
msgstr "Джерело"
msgid "CompareBranches|Target"
-msgstr ""
+msgstr "Ціль"
msgid "CompareBranches|There isn't anything to compare."
msgstr ""
@@ -1103,7 +1229,7 @@ msgid "Contribution guide"
msgstr "ІнÑÑ‚Ñ€ÑƒÐºÑ†Ñ–Ñ Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників"
msgid "Contributors"
-msgstr "Контриб’ютори"
+msgstr "УчаÑники"
msgid "ContributorsPage|%{startDate} – %{endDate}"
msgstr "%{startDate} – %{endDate}"
@@ -1132,11 +1258,14 @@ msgstr "Скопіювати URL в буфер обміну"
msgid "Copy branch name to clipboard"
msgstr "Скопіювати назву гілки в буфер обміну"
+msgid "Copy command to clipboard"
+msgstr "Скопіювати команду в буфер обміну"
+
msgid "Copy commit SHA to clipboard"
msgstr "Скопіювати ідентифікатор в буфер обміну"
msgid "Copy reference to clipboard"
-msgstr ""
+msgstr "Скопіювати поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð² буфер обміну"
msgid "Create"
msgstr "Створити"
@@ -1144,9 +1273,18 @@ msgstr "Створити"
msgid "Create New Directory"
msgstr "Створити новий каталог"
+msgid "Create a new branch"
+msgstr "Створити нову гілку"
+
+msgid "Create a new branch and merge request"
+msgstr "Створити нову гілку Ñ– запит на злиттÑ"
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Створіть токен доÑтупу Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ аккаунта, щоб відправлÑти та отримувати через %{protocol}."
+msgid "Create branch"
+msgstr "Створити гілку"
+
msgid "Create directory"
msgstr "Створити каталог"
@@ -1160,11 +1298,14 @@ msgid "Create file"
msgstr "Створити файл"
msgid "Create lists from labels. Issues with that label appear in that list."
-msgstr ""
+msgstr "Створити ÑпиÑок на оÑтнові міток. Ð’ ньому будуть проблеми з такими мітками."
msgid "Create merge request"
msgstr "Створити запит на злиттÑ"
+msgid "Create merge request and branch"
+msgstr "Створити запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° гілку"
+
msgid "Create new branch"
msgstr "Створити нову гілку"
@@ -1189,6 +1330,12 @@ msgstr "Тег"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Створити токен Ð´Ð»Ñ Ð¾ÑобиÑтого доÑтупу"
+msgid "Creates a new branch from %{branchName}"
+msgstr "Створює нову гілку із %{branchName}"
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr "Створює нову гілку із %{branchName} Ñ– перенаправлÑÑ” Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ запиту на злиттÑ"
+
msgid "Creating epic"
msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐµÐ¿Ñ–ÐºÑƒ"
@@ -1243,6 +1390,9 @@ msgstr "груд."
msgid "December"
msgstr "грудень"
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Визначте влаÑний шаблон за допомогою ÑинтакÑиÑу cron"
@@ -1254,6 +1404,7 @@ msgid_plural "Deploys"
msgstr[0] "РозгортаннÑ"
msgstr[1] "РозгортаннÑ"
msgstr[2] "Розгортань"
+msgstr[3] "Розгортань"
msgid "Deploy Keys"
msgstr "Ключі Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ"
@@ -1268,7 +1419,7 @@ msgid "Details"
msgstr "Деталі"
msgid "Diffs|No file name available"
-msgstr ""
+msgstr "Ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ не доÑтупне"
msgid "Directory name"
msgstr "Ім'Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ñƒ"
@@ -1276,11 +1427,11 @@ msgstr "Ім'Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ñƒ"
msgid "Disable"
msgstr "Вимкнути"
-msgid "Discard changes"
-msgstr "СкаÑувати зміни"
+msgid "Discard draft"
+msgstr "Видалити чернетку"
msgid "Discover GitLab Geo."
-msgstr ""
+msgstr "Відкрийте GitLab Geo."
msgid "Dismiss Cycle Analytics introduction box"
msgstr "Відмінити блок вÑтупу до Ðналитики Циклу"
@@ -1310,7 +1461,7 @@ msgid "DownloadArtifacts|Download"
msgstr "Завантажити"
msgid "DownloadCommit|Email Patches"
-msgstr "Email-патчи"
+msgstr "Email-патчі"
msgid "DownloadCommit|Plain Diff"
msgstr "ПроÑте порівнÑÐ½Ð½Ñ (diff)"
@@ -1336,6 +1487,9 @@ msgstr "ÐдреÑи електронної пошти"
msgid "Enable"
msgstr "Увімкнути"
+msgid "Enable Auto DevOps"
+msgstr "Увімкнути Auto DevOps"
+
msgid "Environments|An error occurred while fetching the environments."
msgstr "Виникла помилка при завантаженні Ñередовищ."
@@ -1390,14 +1544,23 @@ msgstr "Епік буде видалено! Ви впевнені?"
msgid "Epics"
msgstr "Епіки"
+msgid "Epics Roadmap"
+msgstr "План-графік епіків"
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr "Епіки дозволÑÑŽÑ‚ÑŒ керувати вашим портфелем проектів ефективніше та з меншими зуÑиллÑми"
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr "Помилка при Ñтворенні епіку"
msgid "Error fetching contributors data."
-msgstr ""
+msgstr "Помилка Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… учаÑників."
msgid "Error fetching labels."
msgstr "Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¼Ñ–Ñ‚Ð¾Ðº."
@@ -1415,7 +1578,7 @@ msgid "Error occurred when toggling the notification subscription"
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´Ð¿Ð¸Ñки на ÑповіщеннÑ"
msgid "Error saving label update."
-msgstr ""
+msgstr "Помилка при збереженні мітки."
msgid "Error updating status for all todos."
msgstr "Помилка Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑтатуÑу Ð´Ð»Ñ Ð²ÑÑ–Ñ… задач."
@@ -1459,12 +1622,36 @@ msgstr "ОглÑд проектів"
msgid "Explore public groups"
msgstr "ПереглÑнути публічні групи"
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr "Ðевдалі ЗавданнÑ"
+
msgid "Failed to change the owner"
msgstr "Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ влаÑника"
+msgid "Failed to remove issue from board, please try again."
+msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ проблему з дошки, будь лаÑка, Ñпробуйте ще раз."
+
msgid "Failed to remove the pipeline schedule"
msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ розклад конвеєра"
+msgid "Failed to update issues, please try again."
+msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ проблеми. Будь лаÑка, Ñпробуйте ще раз."
+
msgid "Feb"
msgstr "лют."
@@ -1472,7 +1659,7 @@ msgid "February"
msgstr "лютий"
msgid "Fields on this page are now uneditable, you can configure"
-msgstr ""
+msgstr "ÐŸÐ¾Ð»Ñ Ð½Ð° цій Ñторінці зараз недоÑтупні Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ, ви можете налаштувати"
msgid "File name"
msgstr "Ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ"
@@ -1480,6 +1667,9 @@ msgstr "Ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ"
msgid "Files"
msgstr "Файли"
+msgid "Files (%{human_size})"
+msgstr "Файли (%{human_size})"
+
msgid "Filter by commit message"
msgstr "Фільтрувати за коміт-повідомленнÑм"
@@ -1500,6 +1690,7 @@ msgid_plural "Forks"
msgstr[0] "Форк"
msgstr[1] "Форки"
msgstr[2] "Форків"
+msgstr[3] "Форків"
msgid "ForkedFromProjectPath|Forked from"
msgstr "Форк від"
@@ -1516,11 +1707,14 @@ msgstr "З моменту ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð¸ до розгорÑ
msgid "From merge request merge until deploy to production"
msgstr "Від Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð½Ð° production"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr "GPG ключі"
msgid "Generate a default set of labels"
-msgstr ""
+msgstr "Створити Ñтандартний набір міткок"
msgid "Geo Nodes"
msgstr "Гео-Вузли"
@@ -1532,13 +1726,13 @@ msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an
msgstr "Вузол працює повільно, перевантажений або тільки що відновивÑÑ Ð¿Ñ–ÑÐ»Ñ Ð·Ð±Ð¾ÑŽ."
msgid "GeoNodes|Database replication lag:"
-msgstr ""
+msgstr "Затримка реплікації бази даних:"
msgid "GeoNodes|Disabling a node stops the sync process. Are you sure?"
-msgstr ""
+msgstr "Ð’Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð²ÑƒÐ·Ð»Ð° зупинÑÑ” Ð¿Ñ€Ð¾Ñ†ÐµÑ Ñинхронізації. Ви впевнені?"
msgid "GeoNodes|Does not match the primary storage configuration"
-msgstr ""
+msgstr "Ðе відповідає оÑновній конфігурації Ñховища"
msgid "GeoNodes|Failed"
msgstr "Ðевдало"
@@ -1547,85 +1741,85 @@ msgid "GeoNodes|Full"
msgstr "Повний"
msgid "GeoNodes|GitLab version does not match the primary node version"
-msgstr ""
+msgstr "ВерÑÑ–Ñ GitLab не відповідає верÑÑ–Ñ— оÑновного вузла"
msgid "GeoNodes|GitLab version:"
-msgstr ""
+msgstr "ВерÑÑ–Ñ GitLab:"
msgid "GeoNodes|Health status:"
-msgstr ""
+msgstr "Стан працездатноÑÑ‚Ñ–:"
msgid "GeoNodes|Last event ID processed by cursor:"
-msgstr ""
+msgstr "Ідентифікатор оÑтанньої події, обробленої курÑором:"
msgid "GeoNodes|Last event ID seen from primary:"
-msgstr ""
+msgstr "Ідентифікатор оÑтанньої події видимої із оÑновного:"
msgid "GeoNodes|Loading nodes"
-msgstr ""
+msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²ÑƒÐ·Ð»Ñ–Ð²"
msgid "GeoNodes|Local Attachments:"
-msgstr ""
+msgstr "Локальні Ð²ÐºÐ»Ð°Ð´ÐµÐ½Ð½Ñ (attachments):"
msgid "GeoNodes|Local LFS objects:"
-msgstr ""
+msgstr "Локальні LFS-об’єкти:"
msgid "GeoNodes|Local job artifacts:"
-msgstr ""
+msgstr "Ðртефакти локальних завдань:"
msgid "GeoNodes|New node"
-msgstr ""
+msgstr "Ðовий вузол"
msgid "GeoNodes|Out of sync"
-msgstr ""
+msgstr "РозÑинхронізовані"
msgid "GeoNodes|Replication slot WAL:"
-msgstr ""
+msgstr "Слот реплікації WAL:"
msgid "GeoNodes|Replication slots:"
-msgstr ""
+msgstr "Слоти реплікації:"
msgid "GeoNodes|Repositories:"
-msgstr ""
+msgstr "Репозиторії:"
msgid "GeoNodes|Selective"
-msgstr ""
+msgstr "Вибіркові"
msgid "GeoNodes|Storage config:"
-msgstr ""
+msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ñховища:"
msgid "GeoNodes|Sync settings:"
-msgstr ""
+msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñинхронізації:"
msgid "GeoNodes|Synced"
-msgstr ""
+msgstr "Синхронізовано"
msgid "GeoNodes|Unused slots"
-msgstr ""
+msgstr "ÐевикориÑтані Ñлоти"
msgid "GeoNodes|Used slots"
-msgstr ""
+msgstr "ВикориÑтані Ñлоти"
msgid "GeoNodes|Wikis:"
-msgstr ""
+msgstr "Wiki:"
msgid "GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS."
-msgstr ""
+msgstr "Ви налаштували Geo-вузли через незахищене HTTP-з’єднаннÑ. Ми рекомендуємо викориÑтовувати HTTPS."
msgid "Geo|All projects"
-msgstr ""
+msgstr "Ð’ÑÑ– проекти"
msgid "Geo|File sync capacity"
msgstr "ПропуÑкна здатніÑÑ‚ÑŒ Ñинхронізації файлів"
msgid "Geo|Groups to synchronize"
-msgstr ""
+msgstr "Групи Ð´Ð»Ñ Ñинхронізації"
msgid "Geo|Projects in certain groups"
-msgstr ""
+msgstr "Проекти в певних групах"
msgid "Geo|Projects in certain storage shards"
-msgstr ""
+msgstr "Проекти в певних Ñегментах Ñховищ"
msgid "Geo|Repository sync capacity"
msgstr "ПропуÑкна здатніÑÑ‚ÑŒ Ñинхронізації репозиторіїв"
@@ -1634,22 +1828,22 @@ msgid "Geo|Select groups to replicate."
msgstr "Виберіть групи Ð´Ð»Ñ Ñ€ÐµÐ¿Ð»Ñ–ÐºÐ°Ñ†Ñ–Ñ—."
msgid "Geo|Shards to synchronize"
-msgstr ""
+msgstr "Сегменти Ð´Ð»Ñ Ñинхронізації"
msgid "Git revision"
-msgstr ""
+msgstr "Git-редакціÑ"
msgid "Git storage health information has been reset"
msgstr "Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Git була Ñкинута"
msgid "Git version"
-msgstr ""
+msgstr "Git-верÑÑ–Ñ"
msgid "GitLab Runner section"
msgstr "Розділ GitLab Runner"
msgid "Gitaly Servers"
-msgstr ""
+msgstr "Сервери Gitaly"
msgid "Go to your fork"
msgstr "Перейти до вашого форку"
@@ -1661,7 +1855,25 @@ msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab ad
msgstr "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ Google не %{link_to_documentation}. ПопроÑÑ–Ñ‚ÑŒ Ñвого адмініÑтратора GitLab, Ñкщо ви хочете ÑкориÑтатиÑÑ Ñ†Ð¸Ð¼ ÑервіÑом."
msgid "Got it!"
-msgstr ""
+msgstr "Зрозуміло!"
+
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr "Епіки дозволють вам керувати портфоліо ваших проектів більш ефективно Ñ– з меншими зуÑиллÑми"
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr "Від %{dateWord}"
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð»Ð°Ð½Ñƒ-графіку"
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr "Проблема при завантаженні епіків"
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr "Ð”Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду плану-графіку додайте заплановані дати початку та Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð´Ð¾ одного з ваших епіків у цій групі або Ñ—Ñ— підгрупах. ВідображаютьÑÑ Ð»Ð¸ÑˆÐµ епіки за попередні та наÑтупні 3 міÑÑці: від %{startDate} до %{endDate}."
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr "До %{dateWord}"
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr "Заборонити Ñпільний доÑтуп до проекту в рамках %{group} з іншими групами"
@@ -1700,7 +1912,7 @@ msgid "GroupsEmptyState|You can manage your group member’s permissions and acc
msgstr "Ви можете керувати правами доÑтупу членів групи мати доÑтуп до кожного проекту в ній."
msgid "GroupsTree|Are you sure you want to leave the \"${group.fullName}\" group?"
-msgstr ""
+msgstr "Ви впевнені, що хочете залишити групу \"${group.fullName}\"?"
msgid "GroupsTree|Create a project in this group."
msgstr "Створити проект у групі."
@@ -1752,9 +1964,10 @@ msgstr "Ðездоровий"
msgid "Hide value"
msgid_plural "Hide values"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "Сховати значеннÑ"
+msgstr[1] "Сховати значеннÑ"
+msgstr[2] "Сховати значень"
+msgstr[3] "Сховати значень"
msgid "History"
msgstr "ІÑторіÑ"
@@ -1762,6 +1975,9 @@ msgstr "ІÑторіÑ"
msgid "Housekeeping successfully started"
msgstr "ÐžÑ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ ÑƒÑпішно розпочато"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr "Якщо у Ð²Ð°Ñ ÑƒÐ¶Ðµ Ñ” файли, ви можете відправити Ñ—Ñ… за допомогою %{link_to_cli} нижче."
+
msgid "Import repository"
msgstr "Імпорт репозиторію"
@@ -1774,6 +1990,9 @@ msgstr "Покращити ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð°Ð¼Ð¸ з можл
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr "Покращити пошук за допомогою розширеного глобального пошук в верÑÑ–Ñ— GitLab Enterprise Edition."
+msgid "Install Runner on Kubernetes"
+msgstr "Ð’Ñтановити Runner на Kubernetes"
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "Ð’Ñтановіть Runner, ÑуміÑний з GitLab CI"
@@ -1782,12 +2001,13 @@ msgid_plural "Instances"
msgstr[0] "ІнÑтанÑ"
msgstr[1] "IнÑтанÑи"
msgstr[2] "ІнÑтанÑів"
+msgstr[3] "ІнÑтанÑів"
msgid "Instance does not support multiple Kubernetes clusters"
-msgstr ""
+msgstr "Цей інÑÑ‚Ð°Ð½Ñ Ð½Ðµ підтримує декілька Kubernetes-клаÑтерів"
msgid "Interested parties can even contribute by pushing commits if they want to."
-msgstr ""
+msgstr "Зацікавлені Ñторони за бажаннÑм можуть навіть робити внеÑки шлÑхом Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð²."
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
msgstr "Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ â€” будь-Ñкий автентифікований кориÑтувач має доÑтуп до цієї групи та уÑÑ–Ñ… Ñ—Ñ— внутрішніх проектів."
@@ -1817,7 +2037,7 @@ msgid "Issues"
msgstr "Проблеми"
msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
-msgstr ""
+msgstr "Проблеми можуть бути помилками, завданнÑми чи ідеÑми Ð´Ð»Ñ Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ. Крім того, проблеми доÑтупні Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ та фільтруваннÑ."
msgid "Jan"
msgstr "Ñіч."
@@ -1825,6 +2045,9 @@ msgstr "Ñіч."
msgid "January"
msgstr "Ñічень"
+msgid "Jobs"
+msgstr "ЗавданнÑ"
+
msgid "Jul"
msgstr "лип."
@@ -1844,16 +2067,19 @@ msgid "Kubernetes Cluster"
msgstr "КлаÑтер Kubernetes"
msgid "Kubernetes cluster creation time exceeds timeout; %{timeout}"
-msgstr ""
+msgstr "ÐŸÐµÑ€ÐµÐ²Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð»Ñ–Ð¼Ñ–Ñ‚Ñƒ чаÑу при Ñтворенні Kubernetes-клаÑтера; %{timeout}"
msgid "Kubernetes cluster integration was not removed."
-msgstr ""
+msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Ñ–Ð· Kubernetes-клаÑтером не була видалена."
msgid "Kubernetes cluster integration was successfully removed."
-msgstr ""
+msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Ñ–Ð· Kubernetes-клаÑтером була уÑпішно видалена."
msgid "Kubernetes cluster was successfully updated."
-msgstr ""
+msgstr "Kubernetes-клаÑтер уÑпішно оновлено."
+
+msgid "Kubernetes configured"
+msgstr "Kubernetes налаштовано"
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1875,6 +2101,7 @@ msgid_plural "Last %d days"
msgstr[0] "ОÑтанній %d день"
msgstr[1] "ОÑтанніх %d дні"
msgstr[2] "ОÑтанніх %d днів"
+msgstr[3] "ОÑтанніх %d днів"
msgid "Last Pipeline"
msgstr "ОÑтанній Конвеєр"
@@ -1903,6 +2130,12 @@ msgstr "в"
msgid "Learn more"
msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ"
+msgid "Learn more about Kubernetes"
+msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Kubernetes"
+
+msgid "Learn more about protected branches"
+msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про захищені гілки"
+
msgid "Learn more in the"
msgstr "ДізнайтеÑÑŒ більше"
@@ -1921,6 +2154,9 @@ msgstr "Залишити проект"
msgid "License"
msgstr "ЛіцензіÑ"
+msgid "List"
+msgstr "СпиÑок"
+
msgid "Loading the GitLab IDE..."
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ IDE GitLab..."
@@ -1930,8 +2166,11 @@ msgstr "БлокуваннÑ"
msgid "Lock %{issuableDisplayName}"
msgstr "Заблокувати %{issuableDisplayName}"
+msgid "Lock not found"
+msgstr "Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ знайдено"
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
-msgstr ""
+msgstr "Заблокувати цю %{issuableDisplayName}? Лише <strong>члени проекту</strong> зможуть коментувати."
msgid "Locked"
msgstr "Заблоковано"
@@ -1939,11 +2178,14 @@ msgstr "Заблоковано"
msgid "Locked Files"
msgstr "Заблоковані файли"
+msgid "Locks give the ability to lock specific file or folder."
+msgstr "Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð¾Ð¶Ðµ бути заÑтоÑоване до конкретного файлу або директорії."
+
msgid "Login"
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 "Зробіть кожного учаÑника команди більш продуктивним незалежно від його міÑцезнаходженнÑ. GitLab Geo Ñтворює копії \"тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\" вашого GitLab Ñервера, щоб Ñкоротити Ñ‡Ð°Ñ Ð´Ð»Ñ ÐºÐ»Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ– Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÐºÐ¾Ð´Ñƒ з великих репозиторіїв."
msgid "Manage labels"
msgstr "Керувати мітками"
@@ -1955,7 +2197,7 @@ msgid "March"
msgstr "березень"
msgid "Mark done"
-msgstr ""
+msgstr "Позначити виконаним"
msgid "Maximum git storage failures"
msgstr "МакÑимальна кількіÑÑ‚ÑŒ невдач в Ñховищі даних git"
@@ -1969,9 +2211,6 @@ msgstr "Медіана"
msgid "Members"
msgstr "КориÑтувачі"
-msgid "Merge Request"
-msgstr "Запит на злиттÑ"
-
msgid "Merge Requests"
msgstr "Запити на злиттÑ"
@@ -1984,8 +2223,11 @@ msgstr "Запит на злиттÑ"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr "Затверджено"
+
msgid "Merged"
-msgstr ""
+msgstr "Злиті"
msgid "Messages"
msgstr "ПовідомленнÑ"
@@ -2008,9 +2250,18 @@ msgstr "Етап %{milestoneTitle} не знайдено"
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "не додаÑте SSH ключ"
+msgid "Modal|Cancel"
+msgstr "СкаÑувати"
+
+msgid "Modal|Close"
+msgstr "Закрити"
+
msgid "Monitoring"
msgstr "Моніторинг"
+msgid "More information"
+msgstr "Детальніше"
+
msgid "More information is available|here"
msgstr "тут"
@@ -2024,19 +2275,20 @@ msgid "Multiple issue boards"
msgstr "Кілька дошок обговореннÑ"
msgid "Name new label"
-msgstr ""
+msgstr "Ðазвіть нову мітку"
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] "Ðова проблема"
msgstr[1] "Ðові проблеми"
msgstr[2] "Ðових проблем"
+msgstr[3] "Ðових проблем"
msgid "New Kubernetes Cluster"
-msgstr ""
+msgstr "Ðовий Kubernetes-клаÑтер"
msgid "New Kubernetes cluster"
-msgstr ""
+msgstr "Ðовий Kubernetes-клаÑтер"
msgid "New Pipeline Schedule"
msgstr "Ðовий розклад Конвеєра"
@@ -2093,10 +2345,10 @@ msgid "No connection could be made to a Gitaly Server, please check your logs!"
msgstr ""
msgid "No due date"
-msgstr "Ðемає запланованої дати завершеннÑ"
+msgstr "Ðемає"
msgid "No estimate or time spent"
-msgstr ""
+msgstr "Ðемає запланованого або витраченого чаÑу"
msgid "No file chosen"
msgstr "Файл не вибрано"
@@ -2107,14 +2359,11 @@ msgstr "Ðемає репозиторію"
msgid "No schedules"
msgstr "немає Розкладів"
-msgid "No time spent"
-msgstr "Ðемає витраченого чаÑу"
-
msgid "None"
-msgstr "Жоден"
+msgstr "Ðемає"
msgid "Not allowed to merge"
-msgstr ""
+msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð½Ðµ допуÑкаєтьÑÑ"
msgid "Not available"
msgstr "ÐедоÑтупний"
@@ -2125,6 +2374,9 @@ msgstr "Ðе конфіденційно"
msgid "Not enough data"
msgstr "ÐедоÑтатньо даних"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr "Майте на увазі, що гілка master захищена автоматично. %{link_to_protected_branches}"
+
msgid "Notification events"
msgstr "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ події"
@@ -2227,6 +2479,9 @@ msgstr "ВідкриваєтьÑÑ Ñƒ новому вікні"
msgid "Options"
msgstr "Параметри"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr "Ð’ іншому разі рекомендуєтьÑÑ Ð¿Ð¾Ñ‡Ð°Ñ‚Ð¸ з одного з наведених нижче варіантів."
+
msgid "Overview"
msgstr "ОглÑд"
@@ -2330,7 +2585,25 @@ msgid "Pipelines|Build with confidence"
msgstr ""
msgid "Pipelines|Get started with Pipelines"
-msgstr ""
+msgstr "Початок роботи з Конвеєрами"
+
+msgid "Pipeline|Retry pipeline"
+msgstr "ПерезапуÑтити конвеєр"
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr "ПерезапуÑтити конвеєр #%{pipelineId}?"
+
+msgid "Pipeline|Stop pipeline"
+msgstr "Зупинити конвеєр"
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr "Зупинити конвеєр #%{pipelineId}?"
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr "Зараз ви перезапуÑтите конвеєр %{pipelineId}."
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr "Зараз ви зупинете конвеєр %{pipelineId}."
msgid "Pipeline|all"
msgstr "вÑÑ–"
@@ -2357,7 +2630,7 @@ msgid "Preferences"
msgstr "ÐалаштуваннÑ"
msgid "Primary"
-msgstr ""
+msgstr "Головний"
msgid "Private - Project access must be granted explicitly to each user."
msgstr "Приватний — доÑтуп до проекту повинен надаватиÑÑ ÐºÐ¾Ð¶Ð½Ð¾Ð¼Ñƒ кориÑтувачеві."
@@ -2365,6 +2638,9 @@ msgstr "Приватний — доÑтуп до проекту повинен Ð
msgid "Private - The group and its projects can only be viewed by members."
msgstr "Приватна — цю групу та Ñ—Ñ— проекти можуть бачити тільки Ñ—Ñ— кориÑтувачі."
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr "Профіль"
@@ -2405,7 +2681,7 @@ msgid "Profiles|your account"
msgstr "ваш обліковий запиÑ"
msgid "Programming languages used in this repository"
-msgstr ""
+msgstr "Мови програмуваннÑ, що викориÑтовуєтьÑÑ Ð² цьому репозиторії"
msgid "Project '%{project_name}' is in the process of being deleted."
msgstr "Проект '%{project_name}' перебуває в процеÑÑ– видаленнÑ."
@@ -2426,7 +2702,7 @@ msgid "Project avatar"
msgstr "Ðватар проекту"
msgid "Project avatar in repository: %{link}"
-msgstr ""
+msgstr "Ðватар проекту в репозиторії: %{link}"
msgid "Project cache successfully reset."
msgstr "Кеш проекту уÑпішно Ñкинуто."
@@ -2450,13 +2726,13 @@ msgid "ProjectActivityRSS|Subscribe"
msgstr "ПідпиÑатиÑÑ"
msgid "ProjectCreationLevel|Allowed to create projects"
-msgstr ""
+msgstr "Дозволено Ñтворювати проекти"
msgid "ProjectCreationLevel|Default project creation protection"
msgstr ""
msgid "ProjectCreationLevel|Developers + Masters"
-msgstr ""
+msgstr "Розробники + Керівники"
msgid "ProjectCreationLevel|Masters"
msgstr "Керівники"
@@ -2527,12 +2803,30 @@ msgstr "Ðа жаль, по вашоу запиту проектів не зна
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Ð¦Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±ÑƒÑ” підтримки localStorage вашим браузером"
+msgid "PrometheusService|Active"
+msgstr "Ðктивний"
+
+msgid "PrometheusService|Auto configuration"
+msgstr "Ðвтоматична конфігураціÑ"
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr "Ðвтоматично розгортайте та налаштовуйте Prometheus на ваші клаÑтери Ð´Ð»Ñ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ñƒ Ñередовищ проекту"
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr "За замовчуваннÑм, Prometheus запуÑкаєтьÑÑ Ð·Ð° адреÑою ‘http://localhost:9090’. Ðе рекомендуєтьÑÑ Ð·Ð¼Ñ–Ð½ÑŽÐ²Ð°Ñ‚Ð¸ цю адреÑу Ñ– порт, бо це може призвеÑти до конфлікту з іншими ÑервіÑами запущеними на GitLab Ñервері."
msgid "PrometheusService|Finding and configuring metrics..."
msgstr "Пошук та Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼ÐµÑ‚Ñ€Ð¸Ðº..."
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr "Ð’Ñтановити Prometheus на клаÑтери"
+
+msgid "PrometheusService|Manage clusters"
+msgstr "Ð£Ð¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ ÐºÐ»Ð°Ñтерами"
+
+msgid "PrometheusService|Manual configuration"
+msgstr "Ручні налаштуваннÑ"
+
msgid "PrometheusService|Metrics"
msgstr "Метрики"
@@ -2554,8 +2848,17 @@ msgstr "Жодні метрики не відÑлідковуютьÑÑ. ДлÑ
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr "Базова адреÑа Prometheus API, наприклад http://prometheus.example.com/"
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr "Prometheus автоматично налаштований на ваших клаÑтерах"
+
msgid "PrometheusService|Time-series monitoring service"
-msgstr ""
+msgstr "Ð¡ÐµÑ€Ð²Ñ–Ñ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ñƒ чаÑових Ñ€Ñдів"
+
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr "Ð”Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ÑÑ‚Ñ– ручного налаштуваннÑ, видаліть Prometheus із ваших клаÑтерів"
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr "Ð”Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ÑÑ‚Ñ– вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Prometheus на ваші клаÑтери, деактивуйте ручні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð¸Ð¶Ñ‡Ðµ"
msgid "PrometheusService|View environments"
msgstr "ПереглÑд Ñередовищ"
@@ -2575,11 +2878,17 @@ msgstr "Правила відправленнÑ"
msgid "Push events"
msgstr "Події Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ (push)"
+msgid "Push project from command line"
+msgstr "Виконати push проекту за допомогою командного Ñ€Ñдка"
+
+msgid "Push to create a project"
+msgstr "ÐатиÑніть, щоб Ñтворити проект"
+
msgid "PushRule|Committer restriction"
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ‚ÐµÑ€Ð°"
msgid "Quick actions can be used in the issues description and comment boxes."
-msgstr ""
+msgstr "Швидкі дії можна викориÑтовувати в опиÑах проблем Ñ– коментарÑÑ…."
msgid "Read more"
msgstr "Докладніше"
@@ -2594,7 +2903,7 @@ msgid "RefSwitcher|Tags"
msgstr "Теги"
msgid "Reference:"
-msgstr ""
+msgstr "ПоÑиланнÑ:"
msgid "Register / Sign In"
msgstr "ЗареєÑтруватиÑÑ / Увійти"
@@ -2633,11 +2942,14 @@ msgid "Remove project"
msgstr "Видалити проект"
msgid "Repair authentication"
-msgstr ""
+msgstr "Відновити аутентифікацію"
msgid "Repository"
msgstr "Репозиторій"
+msgid "Repository has no locks."
+msgstr "Репозиторій не має блокувань."
+
msgid "Request Access"
msgstr "Запит доÑтупу"
@@ -2650,11 +2962,15 @@ msgstr "Оновити токен доÑтупу Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ прÐ
msgid "Reset runners registration token"
msgstr "Скинути реєÑтраційний токен runner-ів"
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "Показати значеннÑ"
+msgstr[1] "Показати значеннÑ"
+msgstr[2] "Показати значень"
+msgstr[3] "Показати значень"
msgid "Revert this commit"
msgstr "Ðнулювати цей коміт"
@@ -2662,6 +2978,9 @@ msgstr "Ðнулювати цей коміт"
msgid "Revert this merge request"
msgstr "Ðнулювати цей запит на злиттÑ"
+msgid "Roadmap"
+msgstr "План-графік"
+
msgid "SSH Keys"
msgstr "Ключі SSH"
@@ -2672,7 +2991,7 @@ msgid "Save pipeline schedule"
msgstr "Зберегти розклад конвеєра"
msgid "Save variables"
-msgstr ""
+msgstr "Зберегти змінні"
msgid "Schedule a new pipeline"
msgstr "Розклад нового конвеєра"
@@ -2693,7 +3012,7 @@ msgid "Search milestones"
msgstr "Пошук етапів"
msgid "Search project"
-msgstr ""
+msgstr "Пошук в проекті"
msgid "Search users"
msgstr "Пошук кориÑтувачів"
@@ -2705,7 +3024,10 @@ msgid "Seconds to wait for a storage access attempt"
msgstr "КількіÑÑ‚ÑŒ Ñекунд Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ´ повторною Ñпробою доÑтупу до Ñховища даних"
msgid "Secret variables"
-msgstr ""
+msgstr "Секретні змінні"
+
+msgid "Security report"
+msgstr "Звіт по безпеці"
msgid "Select Archive Format"
msgstr "Виберіть формат архіву"
@@ -2713,6 +3035,9 @@ msgstr "Виберіть формат архіву"
msgid "Select a timezone"
msgstr "Вибрати чаÑовий поÑÑ"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr "Виберіть Ñ–Ñнуючий клаÑтер Kubernetes або Ñтворіть новий"
+
msgid "Select assignee"
msgstr "Виберіть виконавцÑ"
@@ -2723,7 +3048,10 @@ msgid "Select target branch"
msgstr "Вибір цільової гілки"
msgid "Selective synchronization"
-msgstr ""
+msgstr "Вибіркова ÑинхронізаціÑ"
+
+msgid "Send email"
+msgstr "ÐадіÑлати лиÑта"
msgid "Sep"
msgstr "вер."
@@ -2735,7 +3063,10 @@ msgid "Server version"
msgstr "ВерÑÑ–Ñ Ñервера"
msgid "Service Templates"
-msgstr "Ð¡ÐµÑ€Ð²Ñ–Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñ–Ð²"
+msgstr "Шаблони ÑервіÑів"
+
+msgid "Service URL"
+msgstr "Ð¡ÐµÑ€Ð²Ñ–Ñ URL"
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Ð’Ñтановіть пароль Ð´Ð»Ñ Ñвого облікового запиÑу, щоб мати можливіÑÑ‚ÑŒ відправлÑти та отримувати через %{protocol}."
@@ -2746,24 +3077,27 @@ msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ CI/CD"
msgid "Set up Koding"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Koding"
-msgid "Set up auto deploy"
-msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ розгортаннÑ"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "вÑтановити пароль"
msgid "Settings"
msgstr "ÐалаштуваннÑ"
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
-msgstr ""
+msgstr "Скинути хвилини в конвеєрі"
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr "Показати команду"
+
msgid "Show parent pages"
msgstr "Показати батьківÑькі Ñторінки"
@@ -2775,6 +3109,7 @@ msgid_plural "Showing %d events"
msgstr[0] "Показано %d подію"
msgstr[1] "Показано %d події"
msgstr[2] "Показано %d подій"
+msgstr[3] "Показано %d подій"
msgid "Sidebar|Change weight"
msgstr "Змінити вагу"
@@ -2792,29 +3127,41 @@ msgid "Snippets"
msgstr "Сніпети"
msgid "Something went wrong on our end"
-msgstr ""
+msgstr "ЩоÑÑŒ пішло не так з нашого боку"
msgid "Something went wrong on our end."
msgstr "ЩоÑÑŒ пішло не так з нашого боку"
msgid "Something went wrong trying to change the confidentiality of this issue"
-msgstr ""
+msgstr "Помилка при зміні конфіденційноÑÑ‚Ñ– цієї проблеми"
msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr "ЩоÑÑŒ пішло не так, при Ñпробі зміни Ñтану Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ${this.issuableDisplayName}"
msgid "Something went wrong when toggling the button"
+msgstr "Помилка при перемиканні кнопки"
+
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
msgstr ""
+msgid "Something went wrong while fetching SAST."
+msgstr "Помилка при отриманні SAST."
+
msgid "Something went wrong while fetching the projects."
msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð²"
msgid "Something went wrong while fetching the registry list."
msgstr "ЩоÑÑŒ пішло не так при отриманні ÑпиÑку із реєÑтру."
-msgid "Something went wrong. Please try again."
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
msgstr ""
+msgid "Something went wrong. Please try again."
+msgstr "ЩоÑÑŒ пішло не так. Будь лаÑка Ñпробуйте ще раз."
+
msgid "Sort by"
msgstr "Сортувати за"
@@ -2917,6 +3264,9 @@ msgstr "Вага"
msgid "Source"
msgstr "Джерело"
+msgid "Source (branch or tag)"
+msgstr "Джерело (гілка або тег)"
+
msgid "Source code"
msgstr "Код"
@@ -2945,7 +3295,7 @@ msgid "Stopped"
msgstr "Зупинено"
msgid "Storage"
-msgstr ""
+msgstr "Сховище"
msgid "Subgroups"
msgstr "Підгрупи"
@@ -2956,11 +3306,12 @@ msgstr "Перейти в гілку/тег"
msgid "System Hooks"
msgstr "СиÑтемні гуки"
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "Тег"
-msgstr[1] "Теги"
-msgstr[2] "Тегів"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] "Тег (%{tag_count})"
+msgstr[1] "Тега (%{tag_count})"
+msgstr[2] "Тегів (%{tag_count})"
+msgstr[3] "Тегів (%{tag_count})"
msgid "Tags"
msgstr "Теги"
@@ -3065,7 +3416,7 @@ msgid "The issue stage shows the time it takes from creating an issue to assigni
msgstr "Ð¡Ñ‚Ð°Ð´Ñ–Ñ \"Проблема\" показує, Ñкільки чаÑу потрібно від ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð¸ до Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ñ—Ñ— до ÑкогоÑÑŒ етапу, або Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð¸ на дошку. Почніть Ñтворювати проблеми, щоб переглÑдати дані Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— Ñтадії."
msgid "The maximum file size allowed is 200KB."
-msgstr ""
+msgstr "МакÑимальний розмір файлу — 200 Кб."
msgid "The number of attempts GitLab will make to access a storage."
msgstr "КількіÑÑ‚ÑŒ Ñпроб, Ñкі зробить GitLab Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу до Ñховища даних."
@@ -3091,9 +3442,15 @@ msgstr "ДоÑтуп до проекту можливий без будь-Ñко
msgid "The repository for this project does not exist."
msgstr "Репозиторій Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту не Ñ–Ñнує."
+msgid "The repository for this project is empty"
+msgstr "Репозиторій цього проекту порожній"
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "Ð¡Ñ‚Ð°Ð´Ñ–Ñ \"ЗатвердженнÑ\" показує Ñ‡Ð°Ñ Ð²Ñ–Ð´ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ про об'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ його виконаннÑ. Дані будуть автоматично додані піÑÐ»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÑˆÐ¾Ð³Ð¾ запиту на злиттÑ."
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr "План-графік показує Ñтан ваших епіків у чаÑÑ–"
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "Ð¡Ñ‚Ð°Ð´Ñ–Ñ \"Staging\" показує Ñ‡Ð°Ñ Ð¼Ñ–Ð¶ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° розгортаннÑм коду у production. Дані автоматично додаютьÑÑ Ð¿Ñ–ÑÐ»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ñƒ production вперше."
@@ -3116,31 +3473,31 @@ msgid "The value lying at the midpoint of a series of observed values. E.g., bet
msgstr "Середнє Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð² Ñ€Ñдку. Приклад: між 3, 5, 9, Ñередніми 5, між 3, 5, 7, 8, Ñередніми (5 + 7) / 2 = 6."
msgid "There are no issues to show"
-msgstr ""
+msgstr "Ðемає проблем Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ"
msgid "There are no merge requests to show"
-msgstr ""
+msgstr "Ðемає запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ"
msgid "There are problems accessing Git storage: "
msgstr "Є проблеми з доÑтупом до Ñховища git: "
msgid "There was an error loading users activity calendar."
-msgstr ""
+msgstr "Помилка при завантаженні ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ð¾ÑÑ‚Ñ– кориÑтувачів."
msgid "There was an error saving your notification settings."
-msgstr ""
+msgstr "Помилка при збереженні ваших налаштувань Ñповіщень."
msgid "There was an error subscribing to this label."
-msgstr ""
+msgstr "Помилка при підпиÑці на цю мітку."
msgid "There was an error when reseting email token."
-msgstr ""
+msgstr "Помилка при Ñкиданні токена електронної пошти."
msgid "There was an error when subscribing to this label."
-msgstr ""
+msgstr "Помилка при підпиÑці на цю мітку."
msgid "There was an error when unsubscribing from this label."
-msgstr ""
+msgstr "Помилка при відпиÑці від цієї мітки."
msgid "This board\\'s scope is reduced"
msgstr "ВидиміÑÑ‚ÑŒ цієї дошки обмежена"
@@ -3167,19 +3524,19 @@ msgid "This job depends on a user to trigger its process. Often they are used to
msgstr ""
msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
-msgstr ""
+msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð»ÐµÐ¶Ð¸Ñ‚ÑŒ від попередніх, Ñкі повинні завершитиÑÑ ÑƒÑпішно Ð´Ð»Ñ Ð¹Ð¾Ð³Ð¾ запуÑку"
msgid "This job has not been triggered yet"
-msgstr ""
+msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ñ‰Ðµ не було запущене"
msgid "This job has not started yet"
-msgstr ""
+msgstr "Ð¦Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ñ‰Ðµ не розпочалаÑÑ"
msgid "This job is in pending state and is waiting to be picked by a runner"
msgstr ""
msgid "This job requires a manual action"
-msgstr ""
+msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ð¸Ð¼Ð°Ð³Ð°Ñ” ручних дій"
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "Це означає, що ви не можете відправлÑти код, поки не Ñтворите порожній репозиторій або не імпортуєте Ñ–Ñнуючий."
@@ -3187,6 +3544,9 @@ msgstr "Це означає, що ви не можете відправлÑти
msgid "This merge request is locked."
msgstr "Цей запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr "Ð¦Ñ Ñторінка недоÑтупна, тому що ви не можете переглÑдати інформацію по кількох проектах."
+
msgid "This project"
msgstr "Цей проект"
@@ -3212,13 +3572,13 @@ msgid "Time until first merge request"
msgstr "Ð§Ð°Ñ Ð´Ð¾ першого запиту на злиттÑ"
msgid "TimeTrackingEstimated|Est"
-msgstr ""
+msgstr "Запланований чаÑ"
msgid "TimeTracking|Estimated:"
-msgstr ""
+msgstr "Запланований чаÑ:"
msgid "TimeTracking|Spent"
-msgstr ""
+msgstr "Витрачено"
msgid "Timeago|%s days ago"
msgstr "%s днів тому"
@@ -3348,19 +3708,27 @@ msgid_plural "Time|hrs"
msgstr[0] "година"
msgstr[1] "години"
msgstr[2] "годин"
+msgstr[3] "годин"
msgid "Time|min"
msgid_plural "Time|mins"
msgstr[0] "хвилина"
msgstr[1] "хвилини"
msgstr[2] "хвилин"
+msgstr[3] "хвилин"
msgid "Time|s"
msgstr "Ñекунд(а)"
+msgid "Tip:"
+msgstr "Порада:"
+
msgid "Title"
msgstr "Ðазва"
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr "Ð”Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду плану-графіку додайте заплановані дати початку та Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð´Ð¾ одного з ваших епіків у цій групі або Ñ—Ñ— підгрупах. ВідображаютьÑÑ Ð»Ð¸ÑˆÐµ епіки за попередні та наÑтупні 3 міÑÑці."
+
msgid "Todo"
msgstr "Задача"
@@ -3376,35 +3744,29 @@ msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¿ÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ñ‡Ð°: УВІМКÐЕÐО"
msgid "Total Time"
msgstr "Загальний чаÑ"
-msgid "Total issue time spent"
-msgstr "Загальний витрачений Ñ‡Ð°Ñ Ð½Ð° проблему"
-
msgid "Total test time for all commits/merges"
msgstr "Загальний чаÑ, щоб перевірити вÑÑ– коміти/злиттÑ"
+msgid "Total: %{total}"
+msgstr "Ð’Ñього: %{total}"
+
msgid "Track activity with Contribution Analytics."
msgstr "ВідÑтежувати активніÑÑ‚ÑŒ за допомогою Ðналітики учаÑників."
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr "ВідÑтежуйте групи проблем зі Ñпільною темою з різних проектів та етапів"
-msgid "Total: %{total}"
-msgstr ""
-
msgid "Track time with quick actions"
msgstr ""
msgid "Trigger this manual action"
-msgstr ""
+msgstr "ЗапуÑтити цю ручну дію"
msgid "Turn on Service Desk"
msgstr "Ввімкнути Service Desk"
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
-msgstr ""
+msgstr "Ðеможливо Ñкинуте кеш проекту."
msgid "Unknown"
msgstr "Ðевідомо"
@@ -3413,16 +3775,19 @@ msgid "Unlock"
msgstr "Розблокувати"
msgid "Unlock this %{issuableDisplayName}? <strong>Everyone</strong> will be able to comment."
-msgstr ""
+msgstr "Розблокувати %{issuableDisplayName}? <strong>Будь-хто</strong> зможе залишати коментарі."
msgid "Unlocked"
msgstr "Розблоковано"
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "Видалити із обраних"
msgid "Up to date"
-msgstr ""
+msgstr "Ðктуальний"
msgid "Upgrade your plan to activate Advanced Global Search."
msgstr "Перейдіть на вищий тарифний план щоб активувати Покращений Глобальний Пошук."
@@ -3446,7 +3811,7 @@ msgid "Upload file"
msgstr "Завантажити файл"
msgid "Upload new avatar"
-msgstr ""
+msgstr "Завантажити новий аватар"
msgid "UploadLink|click to upload"
msgstr "ÐатиÑніть, щоб завантажити"
@@ -3461,13 +3826,16 @@ msgid "Use your global notification setting"
msgstr "ВикориÑтовуютьÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ñ– Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½ÑŒ"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
-msgstr ""
+msgstr "Змінні заÑтоÑовуютьÑÑ Ð´Ð¾ Ñередовищ через runner. Вони можуть бути захищені, в такому випадку вони доÑтупні тільки Ð´Ð»Ñ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¸Ñ… гілок та тегів. Ви можете викориÑтовувати змінні Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð², Ñекретний ключів тощо."
+
+msgid "View epics list"
+msgstr "ПереглÑнути ÑпиÑок епіків"
msgid "View file @ "
msgstr "ПереглÑд файла @ "
msgid "View labels"
-msgstr ""
+msgstr "ПереглÑнути мітки"
msgid "View open merge request"
msgstr "ПереглÑд відкритих запитів на злиттÑ"
@@ -3499,6 +3867,9 @@ msgstr "Ми не маємо доÑтатньо даних Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Ми хочемо бути впевнені, що це ви, будь лаÑка, підтвердіть, що ви не робот."
+msgid "Web IDE"
+msgstr "Веб-IDE"
+
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 Ñкщо, наприклад, був відправлений новий код або Ñтворено нову проблему. Ви можете налаштувати його так, щоб він реагував на певні події (відправки коду, проблеми або запити на злиттÑ). Групові веб-гуки заÑтоÑовуютьÑÑ Ð´Ð¾ вÑÑ–Ñ… проектів в групі Ñ– дозволÑÑŽÑ‚ÑŒ вам Ñтандартизувати Ñ—Ñ… Ð´Ð»Ñ Ð²Ñієї вашої групи."
@@ -3524,7 +3895,7 @@ msgid "WikiClone|Start Gollum and edit locally"
msgstr "ЗапуÑÑ‚Ñ–Ñ‚ÑŒ Gollum Ñ– редагуйте локально"
msgid "WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title."
-msgstr ""
+msgstr "Порада: Ви можете переміÑтити цю Ñторінку, додавши шлÑÑ… до початку заголовка."
msgid "WikiEdit|There is already a page with the same title in that path."
msgstr ""
@@ -3619,6 +3990,9 @@ msgstr "З аналітикою учаÑників ви може вивчати
msgid "Withdraw Access Request"
msgstr "СкаÑувати запит доÑтупу"
+msgid "Write a commit message..."
+msgstr "Ðапишіть коміт-повідомленнÑ..."
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "Ви хочете видалити %{group_name}. Видалені групи ÐЕ МОЖÐРбуду відновити! Ви ÐБСОЛЮТÐО впевнені?"
@@ -3631,20 +4005,23 @@ msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ зв'Ñзок з форка Ð
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Ви збираєтеÑÑ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‚Ð¸ проект %{project_name_with_namespace} іншому влаÑнику. Ви ÐБСОЛЮТÐО впевнені?"
+msgid "You can also create a project from the command line."
+msgstr "Ви також можете Ñтворити проект із командного Ñ€Ñдка."
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
-msgstr ""
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
+msgstr "Ви можете легко вÑтановити Runner на клаÑтері Kubernetes. %{link_to_help_page}"
msgid "You can move around the graph by using the arrow keys."
-msgstr ""
+msgstr "Ви можете переÑуватиÑÑ Ð¿Ð¾ графіку за допомогою клавіш зі Ñтрілками."
msgid "You can only add files when you are on a branch"
msgstr "Ви можете додавати файли тільки коли перебуваєте в гілці"
msgid "You can only edit files when you are on a branch"
-msgstr ""
+msgstr "Ви можете редагувати файли, лише перебуваючи у ÑкійÑÑŒ гілці"
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
msgstr "Ви не можете запиÑувати на вторинні інÑтанÑи \"тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\" GitLab Geo. Будь лаÑка викориÑтовуйте %{link_to_primary_node}."
@@ -3652,12 +4029,24 @@ msgstr "Ви не можете запиÑувати на вторинні інÑ
msgid "You cannot write to this read-only GitLab instance."
msgstr "Ви не можете запиÑувати на цей \"тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\" інÑÑ‚Ð°Ð½Ñ GitLab."
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” необхідних прав доÑтупу, щоб перевизначити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñинхронізації LDAP-груп."
+
+msgid "You have no permissions"
+msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” прав доÑтупу"
+
msgid "You have reached your project limit"
msgstr "Ви доÑÑгли Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð² вашому проекті"
+msgid "You must have master access to force delete a lock"
+msgstr "У Ð²Ð°Ñ Ð¿Ð¾Ð²Ð¸Ð½ÐµÐ½ бути доÑтуп на рівні керівника, Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð¼ÑƒÑового Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ"
+
msgid "You must sign in to star a project"
msgstr "Ðеобхідно увійти, щоб оцінити проект"
+msgid "You need a different license to enable FileLocks feature"
+msgstr "Ð”Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ñ–Ñ— функції Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¤Ð°Ð¹Ð»Ñ–Ð² вам потрібна інша ліцензіÑ"
+
msgid "You need permission."
msgstr "Вам потрібен дозвіл"
@@ -3686,9 +4075,12 @@ msgid "You won't be able to pull or push project code via SSH until you add an S
msgstr "Ви не зможете відправлÑти та отримувати код проекту через SSH, поки не додаÑте в Ñвій профіль SSH ключ"
msgid "You'll need to use different branch names to get a valid comparison."
-msgstr ""
+msgstr "Вам необхідно викориÑтовувати різні імена гілок Ð´Ð»Ñ ÐºÐ¾Ñ€ÐµÐºÑ‚Ð½Ð¾Ð³Ð¾ порівнÑннÑ."
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
+msgstr "Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ ваш Kubernetes-клаÑтер вÑе ще доÑтупна Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° цій Ñторінці, але ми радимо вимкнути Ñ– повторно налаштувати"
+
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
msgstr ""
msgid "Your comment will not be visible to the public."
@@ -3716,13 +4108,13 @@ msgid "ciReport|Code quality"
msgstr "ЯкіÑÑ‚ÑŒ коду"
msgid "ciReport|DAST detected no alerts by analyzing the review app"
-msgstr ""
+msgstr "DAST не виÑвив попереджень при аналізі цього review app"
-msgid "ciReport|Failed to load ${type} report"
-msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð²Ñ–Ñ‚Ñƒ ${type} пройшло невдало"
+msgid "ciReport|Failed to load %{reportName} report"
+msgstr "Помилка при завантаженні звіту %{reportName}"
msgid "ciReport|Fixed:"
-msgstr ""
+msgstr "Виправлено:"
msgid "ciReport|Instances"
msgstr "ІнÑтанÑи"
@@ -3730,11 +4122,11 @@ msgstr "ІнÑтанÑи"
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
-msgstr ""
+msgid "ciReport|Loading %{reportName} report"
+msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð²Ñ–Ñ‚Ñƒ %{reportName}"
msgid "ciReport|No changes to code quality"
-msgstr ""
+msgstr "Ðемає змін у ÑкоÑÑ‚Ñ– коду"
msgid "ciReport|No changes to performance metrics"
msgstr ""
@@ -3745,41 +4137,88 @@ msgstr ""
msgid "ciReport|SAST"
msgstr "SAST"
+msgid "ciReport|SAST degraded on"
+msgstr "SAST погіршивÑÑ Ð½Ð°"
+
+msgid "ciReport|SAST detected"
+msgstr "SAST виÑвив"
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr "SAST не виÑвив нових вразливоÑтей"
+
msgid "ciReport|SAST detected no security vulnerabilities"
-msgstr ""
+msgstr "SAST не виÑвив жодних вразливоÑтей"
msgid "ciReport|SAST:container no vulnerabilities were found"
msgstr ""
msgid "ciReport|Show complete code vulnerabilities report"
-msgstr ""
+msgstr "Показати повний звіт про вразливоÑÑ‚Ñ– в коді"
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
-msgstr ""
+msgstr "Ðезатверджені вразливоÑÑ‚Ñ– (червоні) можуть бути відмічені Ñк затверджені. %{helpLink}"
+
+msgid "ciReport|no security vulnerabilities"
+msgstr "вразливоÑтей немає"
+
+msgid "command line instructions"
+msgstr "інÑтрукції Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¾Ð³Ð¾ Ñ€Ñдка"
msgid "commit"
msgstr "коміт"
msgid "confidentiality|You are going to turn off the confidentiality. This means <strong>everyone</strong> will be able to see and leave a comment on this issue."
-msgstr ""
+msgstr "ви вимикаєте конфіденційніÑÑ‚ÑŒ. Це означає, що <strong>будь-хто</strong> зможе бачити Ñ– залишати коментарі Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— проблеми."
msgid "confidentiality|You are going to turn on the confidentiality. This means that only team members with <strong>at least Reporter access</strong> are able to see and leave comments on the issue."
-msgstr ""
+msgstr "Ви вмикаєте конфіденційніÑÑ‚ÑŒ. Це означає що лише члени команди <strong>Ñ€Ñ–Ð²Ð½Ñ Ñ€ÐµÐ¿Ð¾Ñ€Ñ‚ÐµÑ€ або вище</strong> матимуть змогу бачити та залишати коментарі Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— проблеми."
msgid "day"
msgid_plural "days"
msgstr[0] "день"
msgstr[1] "дні"
msgstr[2] "днів"
+msgstr[3] "днів"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr "неправильний через наÑвніÑÑ‚ÑŒ блокувань на нижчих рівнÑÑ…"
+
+msgid "is invalid because there is upstream lock"
+msgstr "неправильний через наÑвніÑÑ‚ÑŒ блокувань на вищих рівнÑÑ…"
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr "заблоковано %{path_lock_user_name} %{created_at}"
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] "запит на злиттÑ"
msgstr[1] "запити на злиттÑ"
msgstr[2] "запитів на злиттÑ"
+msgstr[3] "запитів на злиттÑ"
+
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr "Будь лаÑка відновіть Ñ—Ñ— або викориÑтовуйте іншу %{missingBranchName} гілку"
+
+msgid "mrWidget|Add approval"
+msgstr "Додати затвердженнÑ"
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr "Під Ñ‡Ð°Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°."
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr "Затвердити"
+
+msgid "mrWidget|Approved by"
+msgstr ""
msgid "mrWidget|Cancel automatic merge"
msgstr "СкаÑувати автоматичне злиттÑ"
@@ -3788,34 +4227,37 @@ msgid "mrWidget|Check out branch"
msgstr ""
msgid "mrWidget|Checking ability to merge automatically"
-msgstr ""
+msgstr "перевірка можливоÑÑ‚Ñ– автоматичного злиттÑ"
msgid "mrWidget|Cherry-pick"
-msgstr ""
+msgstr "вибір (коміта)"
msgid "mrWidget|Cherry-pick this merge request in a new merge request"
msgstr ""
msgid "mrWidget|Closed"
-msgstr ""
+msgstr "Закриті"
msgid "mrWidget|Closed by"
-msgstr ""
+msgstr "Закритий"
msgid "mrWidget|Closes"
msgstr ""
msgid "mrWidget|Did not close"
-msgstr ""
+msgstr "Ðе закрив"
msgid "mrWidget|Email patches"
-msgstr ""
+msgstr "Email-патчі"
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
-msgstr ""
+msgstr "Якщо гілка %{branch} Ñ–Ñнує у вашому локальному репозиторії, то ви можете заÑтоÑувати цей запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð²Ñ€ÑƒÑ‡Ð½Ñƒ за допомогою"
+
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr "Якщо гілка %{missingBranchName} Ñ–Ñнує у вашому локальному репозиторії, то ви можете заÑтоÑувати цей запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð²Ñ€ÑƒÑ‡Ð½Ñƒ за допомогою командного Ñ€Ñдка"
msgid "mrWidget|Mentions"
-msgstr ""
+msgstr "Згадки"
msgid "mrWidget|Merge"
msgstr "ЗлиттÑ"
@@ -3824,13 +4266,13 @@ msgid "mrWidget|Merge failed."
msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ñ€Ð¾Ð¹ÑˆÐ»Ð¾ невдало."
msgid "mrWidget|Merge locally"
-msgstr ""
+msgstr "Злити локально"
msgid "mrWidget|Merged by"
-msgstr ""
+msgstr "Злито"
msgid "mrWidget|Plain diff"
-msgstr ""
+msgstr "ПроÑте порівнÑÐ½Ð½Ñ (diff)"
msgid "mrWidget|Refresh"
msgstr "Оновити"
@@ -3839,76 +4281,82 @@ msgid "mrWidget|Refresh now"
msgstr "Оновити зараз"
msgid "mrWidget|Refreshing now"
-msgstr ""
+msgstr "ВідбуваєтьÑÑ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ"
msgid "mrWidget|Remove Source Branch"
-msgstr ""
+msgstr "Видалити гілку-джерело"
msgid "mrWidget|Remove source branch"
-msgstr ""
+msgstr "Видалити гілку-джерело"
+
+msgid "mrWidget|Remove your approval"
+msgstr "Видалити ваше затвердженнÑ"
msgid "mrWidget|Request to merge"
-msgstr ""
+msgstr "Запит на злиттÑ"
msgid "mrWidget|Resolve conflicts"
-msgstr ""
+msgstr "Вирішити конфлікти"
msgid "mrWidget|Revert"
-msgstr ""
+msgstr "Ðнулювати"
msgid "mrWidget|Revert this merge request in a new merge request"
-msgstr ""
+msgstr "Ðнулювати цей запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð° допомогою нового запиту на злиттÑ"
msgid "mrWidget|Set by"
-msgstr ""
+msgstr "Ð’Ñтановлено"
msgid "mrWidget|The changes were merged into"
-msgstr ""
+msgstr "Зміни були злиті в"
msgid "mrWidget|The changes were not merged into"
-msgstr ""
+msgstr "Зміни не були злиті в"
msgid "mrWidget|The changes will be merged into"
-msgstr ""
+msgstr "Зміни будуть злиті в"
msgid "mrWidget|The source branch has been removed"
-msgstr ""
+msgstr "Гілку-джерело видалено"
msgid "mrWidget|The source branch is being removed"
-msgstr ""
+msgstr "Гілка-джерело в процеÑÑ– видаленнÑ"
msgid "mrWidget|The source branch will be removed"
-msgstr ""
+msgstr "Гілку-джерело буде видалено"
msgid "mrWidget|The source branch will not be removed"
-msgstr ""
+msgstr "Гілку-джерело не буде видалено"
msgid "mrWidget|There are merge conflicts"
-msgstr ""
+msgstr "Ñ–Ñнують конфлікти при злитті"
msgid "mrWidget|This merge request failed to be merged automatically"
msgstr "ВідбулаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при автоматичному злитті цього запиту"
msgid "mrWidget|This merge request is in the process of being merged"
-msgstr ""
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² процеÑÑ– виконаннÑ"
msgid "mrWidget|This project is archived, write access has been disabled"
-msgstr ""
+msgstr "Цей проект заархівований, доÑтуп до запиÑу було відключено"
msgid "mrWidget|You can merge this merge request manually using the"
-msgstr ""
+msgstr "Ви можете прийнÑти цей запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð²Ñ€ÑƒÑ‡Ð½Ñƒ за допомогою"
msgid "mrWidget|You can remove source branch now"
-msgstr ""
+msgstr "Тепер ви можете видалити гілку-джерело"
+
+msgid "mrWidget|branch does not exist."
+msgstr "гілка не Ñ–Ñнує."
msgid "mrWidget|command line"
-msgstr ""
+msgstr "командний Ñ€Ñдок"
msgid "mrWidget|into"
-msgstr ""
+msgstr "в"
msgid "mrWidget|to be merged automatically when the pipeline succeeds"
-msgstr ""
+msgstr "буде злито автоматично, коли конвеєр завершитьÑÑ ÑƒÑпішно"
msgid "new merge request"
msgstr "Ðовий запит на злиттÑ"
@@ -3924,6 +4372,7 @@ msgid_plural "parents"
msgstr[0] "батьківÑький об’єкт"
msgstr[1] "батьківÑькі об’єкти"
msgstr[2] "батьківÑький об’єктів"
+msgstr[3] "батьківÑький об’єктів"
msgid "password"
msgstr "пароль"
@@ -3947,5 +4396,8 @@ msgid "username"
msgstr "ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
msgid "uses Kubernetes clusters to deploy your code!"
+msgstr "викориÑтовує клаÑтери Kubernetes Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ ÐºÐ¾Ð´Ñƒ!"
+
+msgid "with %{additions} additions, %{deletions} deletions."
msgstr ""
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index 441f080596c..6a43a434cb8 100644
--- a/locale/zh_CN/gitlab.po
+++ b/locale/zh_CN/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 03:58-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:21-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@@ -43,6 +43,9 @@ msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "为æ高页é¢åŠ è½½é€Ÿåº¦åŠæ€§èƒ½ï¼Œå·²çœç•¥äº† %s 次æ交。"
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -50,6 +53,9 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} ä½å‚与者"
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr "%{number_commits_behind} 个è½åŽ %{default_branch} 分支的æ交, %{number_commits_ahead} 早超å‰çš„æ交"
@@ -59,6 +65,9 @@ msgstr "已失败 %{number_of_failures} 次/最多å…许失败失败 %{maximum_f
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "已失败 %{number_of_failures} 次/最多å…许失败 %{maximum_failures} 次,GitLab ä¸ä¼šç»§ç»­è‡ªåŠ¨é‡è¯•ã€‚请在问题解决åŽé‡ç½®å­˜å‚¨å¥åº·ä¿¡æ¯ã€‚"
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}:已 %{failed_attempts} 次å°è¯•è®¿é—®å­˜å‚¨å¤±è´¥ï¼š"
@@ -121,9 +130,15 @@ msgstr "添加贡献指å—"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr "添加组Webhookså’ŒGitLabä¼ä¸šç‰ˆã€‚"
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "添加许å¯è¯"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "添加目录"
@@ -142,12 +157,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr "å¥åº·é¡µé¢"
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -172,6 +220,12 @@ msgstr "切æ¢é€šçŸ¥è®¢é˜…æ—¶å‘生错误"
msgid "An error occurred when updating the issue weight"
msgstr "更新议题æƒé‡æ—¶å‘生错误"
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -181,12 +235,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr "获å–侧边æ æ•°æ®æ—¶å‘生错误"
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -199,6 +277,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -223,15 +307,15 @@ msgstr "项目已归档ï¼å­˜å‚¨åº“为åªè¯»çŠ¶æ€"
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "确定è¦åˆ é™¤æ­¤æµæ°´çº¿è®¡åˆ’å—?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "确定è¦æ”¾å¼ƒä¿®æ”¹å—?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "确定è¦é‡ç½®æ³¨å†Œä»¤ç‰Œå—?"
msgid "Are you sure you want to reset the health check token?"
msgstr "确定è¦é‡ç½®å¥åº·æ£€æŸ¥ä»¤ç‰Œå—?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "确定å—?"
@@ -271,6 +355,9 @@ msgstr "作者"
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -295,8 +382,14 @@ msgstr "将根æ®é¢„定义的 CI/CD é…置自动构建ã€æµ‹è¯•å’Œéƒ¨ç½²åº”用ç¨
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "想了解更多请访问 %{link_to_documentation}"
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
-msgstr "您å¯ä»¥ä¸ºæ­¤é¡¹ç›®æ¿€æ´» %{link_to_settings}。"
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr ""
msgid "Available"
msgstr "å¯ç”¨çš„"
@@ -307,6 +400,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr "è´¦å•"
@@ -361,12 +457,9 @@ msgstr "æ¯å¹´æ”¯ä»˜ %{price_per_year}"
msgid "BillingPlans|per user"
msgstr "æ¯ç”¨æˆ·"
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "分支"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "已创建分支 <strong>%{branch_name}</strong> 。如需设置自动部署, 请选择åˆé€‚çš„ GitLab CI Yaml 模æ¿å¹¶æ交更改。%{link_to_autodeploy_doc}"
@@ -659,6 +752,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr "断路器 API"
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -713,6 +809,9 @@ msgstr "å¤åˆ¶API地å€"
msgid "ClusterIntegration|Copy CA Certificate"
msgstr "å¤åˆ¶CAè¯ä¹¦"
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -761,6 +860,9 @@ msgstr "Helm Tiller"
msgid "ClusterIntegration|Ingress"
msgstr "å…¥å£"
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr "安装"
@@ -812,9 +914,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "了解详细%{link_to_documentation}"
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -950,6 +1049,12 @@ msgstr "正确é…ç½®"
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "评论"
@@ -957,6 +1062,10 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "æ交"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+
msgid "Commit Message"
msgstr "æ交消æ¯"
@@ -969,6 +1078,9 @@ msgstr "æ交信æ¯"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "æ交"
@@ -1110,6 +1222,9 @@ msgstr "å¤åˆ¶ URL 到剪贴æ¿"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "å¤åˆ¶æ交 SHA 的值到剪贴æ¿"
@@ -1122,9 +1237,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "创建新目录"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "在å¸æˆ·ä¸Šåˆ›å»ºä¸ªäººè®¿é—®ä»¤ç‰Œï¼Œä»¥é€šè¿‡ %{protocol} æ¥æ‹‰å–或推é€ã€‚"
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "创建目录"
@@ -1143,6 +1267,9 @@ msgstr ""
msgid "Create merge request"
msgstr "创建åˆå¹¶è¯·æ±‚"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr "创建新分支"
@@ -1167,6 +1294,12 @@ msgstr "标签"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "创建个人访问令牌"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr "创建EPIC中"
@@ -1221,6 +1354,9 @@ msgstr "å二"
msgid "December"
msgstr "å二月"
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "使用 Cron 语法定义自定义模å¼"
@@ -1252,8 +1388,8 @@ msgstr "目录å称"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
-msgstr "放弃更改"
+msgid "Discard draft"
+msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
@@ -1312,6 +1448,9 @@ msgstr "电å­é‚®ä»¶"
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr "获å–环境时å‘生错误。"
@@ -1366,9 +1505,18 @@ msgstr "EPIC将被删除!是å¦ç¡®å®šï¼Ÿ"
msgid "Epics"
msgstr "EPIC"
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr "EPIC让你更有效率地管ç†ä½ çš„项目组åˆï¼Œè€Œä¸”ä¸è´¹å¹ç°ä¹‹åŠ›"
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr "创建EPIC时出错"
@@ -1435,12 +1583,36 @@ msgstr "查看项目"
msgid "Explore public groups"
msgstr "æœç´¢å…¬å…±ç¾¤ç»„"
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "无法å˜æ›´æ‰€æœ‰è€…"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "无法删除æµæ°´çº¿è®¡åˆ’"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr "二"
@@ -1456,6 +1628,9 @@ msgstr "文件å"
msgid "Files"
msgstr "文件"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "按æ交消æ¯è¿‡æ»¤"
@@ -1490,6 +1665,9 @@ msgstr "从创建议题到部署至生产环境"
msgid "From merge request merge until deploy to production"
msgstr "从åˆå¹¶è¯·æ±‚被åˆå¹¶åŽåˆ°éƒ¨ç½²è‡³ç”Ÿäº§çŽ¯å¢ƒ"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr "GPG 密钥"
@@ -1637,6 +1815,24 @@ msgstr "Google 身份验è¯ä¸æ˜¯%{link_to_documentation}。如果您想使用æ­
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr "ç¦æ­¢ä¸Žå…¶ä»–群组共享 %{group} 中的项目"
@@ -1734,6 +1930,9 @@ msgstr "历å²"
msgid "Housekeeping successfully started"
msgstr "已开始维护"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "导入存储库"
@@ -1746,12 +1945,15 @@ msgstr "å助改善GitLab ä¼ä¸šç‰ˆçš„议题管ç†ä¸Žæƒé‡ã€‚"
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr "å助改进GitLab ä¼ä¸šç‰ˆçš„æœç´¢å’Œé«˜çº§å…¨å±€æœç´¢ 。"
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "安装一个与 GitLab CI 兼容的 Runner"
msgid "Instance"
msgid_plural "Instances"
-msgstr[0] "例å­"
+msgstr[0] "实例"
msgid "Instance does not support multiple Kubernetes clusters"
msgstr ""
@@ -1795,6 +1997,9 @@ msgstr "一"
msgid "January"
msgstr "一月"
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr "七"
@@ -1825,6 +2030,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1871,6 +2079,12 @@ msgstr "于"
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "了解更多"
@@ -1889,6 +2103,9 @@ msgstr "退出项目"
msgid "License"
msgstr "许å¯åè®®"
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1898,6 +2115,9 @@ msgstr "é”定"
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1907,6 +2127,9 @@ msgstr "å·²é”定"
msgid "Locked Files"
msgstr "å·²é”定文件"
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr "登录"
@@ -1937,9 +2160,6 @@ msgstr "中ä½æ•°"
msgid "Members"
msgstr "æˆå‘˜"
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr "åˆå¹¶è¯·æ±‚"
@@ -1952,6 +2172,9 @@ msgstr "åˆå¹¶è¯·æ±‚"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1976,9 +2199,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "新建 SSH 公钥"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr "监控"
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr "帮助文档"
@@ -2073,9 +2305,6 @@ msgstr "没有存储库"
msgid "No schedules"
msgstr "没有计划"
-msgid "No time spent"
-msgstr "没有花费时间"
-
msgid "None"
msgstr "æ— "
@@ -2091,6 +2320,9 @@ msgstr ""
msgid "Not enough data"
msgstr "æ•°æ®ä¸è¶³"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "通知事件"
@@ -2193,6 +2425,9 @@ msgstr "打开一个新窗å£"
msgid "Options"
msgstr "æ“作"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr "概览"
@@ -2298,6 +2533,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "所有"
@@ -2331,6 +2584,9 @@ msgstr "ç§äºº - å¿…é¡»å‘æ¯ä¸ªç”¨æˆ·æ˜Žç¡®æŽˆäºˆé¡¹ç›®è®¿é—®æƒé™ã€‚"
msgid "Private - The group and its projects can only be viewed by members."
msgstr "ç§äºº - 群组åŠå…¶é¡¹ç›®åªèƒ½ç”±æˆå‘˜æŸ¥çœ‹ã€‚"
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr "用户信æ¯"
@@ -2493,12 +2749,30 @@ msgstr "对ä¸èµ·ï¼Œæ²¡æœ‰æœç´¢åˆ°ç¬¦åˆæ¡ä»¶çš„项目"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "此功能需è¦æµè§ˆå™¨æ”¯æŒ localStorage"
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr "默认情况下,Prometheus ä¾¦å¬ â€˜http://localhost:9090’。ä¸å»ºè®®æ›´æ”¹é»˜è®¤åœ°å€å’Œç«¯å£ï¼Œå› ä¸ºè¿™å¯èƒ½ä¼šå½±å“或冲çªåœ¨ GitLab æœåŠ¡å™¨ä¸Šè¿è¡Œçš„其他æœåŠ¡ã€‚"
msgid "PrometheusService|Finding and configuring metrics..."
msgstr "查找和é…置指标..."
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr "指标"
@@ -2520,9 +2794,18 @@ msgstr "没有监测指标。è¦å¼€å§‹ç›‘测,请部署到环境中。"
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr "Prometheus API 地å€ï¼Œä¾‹å¦‚ http://prometheus.example.com/"
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr "查看环境"
@@ -2541,6 +2824,12 @@ msgstr "推é€è§„则"
msgid "Push events"
msgstr "推é€äº‹ä»¶"
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr "æ交é™åˆ¶"
@@ -2604,6 +2893,9 @@ msgstr ""
msgid "Repository"
msgstr "存储库"
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "申请æƒé™"
@@ -2616,6 +2908,9 @@ msgstr "é‡ç½®å¥åº·æ£€æŸ¥è®¿é—®ä»¤ç‰Œ"
msgid "Reset runners registration token"
msgstr "é‡ç½® Runner 注册令牌"
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2626,6 +2921,9 @@ msgstr "还原此æ交"
msgid "Revert this merge request"
msgstr "还原此åˆå¹¶è¯·æ±‚"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr "SSH 密钥"
@@ -2671,12 +2969,18 @@ msgstr "等待存储访问å°è¯•æ—¶é—´(秒)"
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "选择下载格å¼"
msgid "Select a timezone"
msgstr "选择时区"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2689,6 +2993,9 @@ msgstr "选择目标分支"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr "ä¹"
@@ -2701,6 +3008,9 @@ msgstr ""
msgid "Service Templates"
msgstr "æœåŠ¡æ¨¡æ¿"
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "为账å·åˆ›å»ºä¸€ä¸ªç”¨äºŽæŽ¨é€æˆ–拉å–çš„ %{protocol} 密ç ã€‚"
@@ -2710,15 +3020,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "设置 Koding"
-msgid "Set up auto deploy"
-msgstr "设置自动部署"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "设置密ç "
msgid "Settings"
msgstr "设置"
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2728,6 +3038,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr "查看上级页é¢"
@@ -2748,7 +3061,7 @@ msgid "Sidebar|None"
msgstr "æ— "
msgid "Sidebar|Weight"
-msgstr "宽度"
+msgstr "æƒé‡"
msgid "Snippets"
msgstr "代ç ç‰‡æ®µ"
@@ -2768,12 +3081,24 @@ msgstr "è¯•å›¾æ”¹å˜ ${this.issuableDisplayName} çš„é”定状æ€æ—¶å‡ºé”™äº†"
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr "拉å–项目时å‘生错误。"
msgid "Something went wrong while fetching the registry list."
msgstr "拉å–注册表列表时å‘生错误。"
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2879,6 +3204,9 @@ msgstr "æƒé‡"
msgid "Source"
msgstr "æº"
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "æºä»£ç "
@@ -2918,9 +3246,9 @@ msgstr "切æ¢åˆ†æ”¯/标签"
msgid "System Hooks"
msgstr "系统钩å­"
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "标签"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
msgid "Tags"
msgstr "标签"
@@ -3051,9 +3379,15 @@ msgstr "该项目å…许任何人访问。"
msgid "The repository for this project does not exist."
msgstr "此项目的存储库ä¸å­˜åœ¨ã€‚"
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "评审阶段概述了从创建åˆå¹¶è¯·æ±‚到被åˆå¹¶çš„时间。当创建第一个åˆå¹¶è¯·æ±‚åŽï¼Œæ•°æ®å°†è‡ªåŠ¨æ·»åŠ åˆ°æ­¤å¤„。"
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "预å‘布阶段概述了从åˆå¹¶è¯·æ±‚被åˆå¹¶åˆ°éƒ¨ç½²è‡³ç”Ÿäº§çŽ¯å¢ƒçš„总时间。首次部署到生产环境åŽï¼Œæ•°æ®å°†è‡ªåŠ¨æ·»åŠ åˆ°æ­¤å¤„。"
@@ -3147,6 +3481,9 @@ msgstr "在创建一个空的存储库或导入现有存储库之å‰ï¼Œå°†æ— æ³•
msgid "This merge request is locked."
msgstr "æ­¤åˆå¹¶è¯·æ±‚å·²é”定。"
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3314,9 +3651,15 @@ msgstr[0] "分钟"
msgid "Time|s"
msgstr "秒"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr "标题"
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3332,21 +3675,18 @@ msgstr ""
msgid "Total Time"
msgstr "总时间"
-msgid "Total issue time spent"
-msgstr "议题花费时间总计"
-
msgid "Total test time for all commits/merges"
msgstr "所有æ交和åˆå¹¶çš„总测试时间"
+msgid "Total: %{total}"
+msgstr ""
+
msgid "Track activity with Contribution Analytics."
msgstr "跟踪活动与贡献的分æžã€‚"
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr "在项目和里程碑之间跟踪共享主题的议题组"
-msgid "Total: %{total}"
-msgstr ""
-
msgid "Track time with quick actions"
msgstr ""
@@ -3356,9 +3696,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr "打开æœåŠ¡å°"
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3374,6 +3711,9 @@ msgstr ""
msgid "Unlocked"
msgstr "已解é”"
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "å–消星标"
@@ -3419,6 +3759,9 @@ msgstr "使用全局通知设置"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr "æµè§ˆæ–‡ä»¶ @ "
@@ -3455,6 +3798,9 @@ msgstr "该阶段的数æ®ä¸è¶³ï¼Œæ— æ³•æ˜¾ç¤ºã€‚"
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "我们è¦ç¡®å®šä½ æ˜¯ä¸æ˜¯æœºå™¨äººã€‚"
+msgid "Web IDE"
+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 将适用于团队中的所有项目,并å…许您设置整个团队中的 Webhook 。"
@@ -3575,6 +3921,9 @@ msgstr "通过贡献分æžï¼Œæ‚¨å¯ä»¥åˆ†æžæ‚¨çš„组织åŠå…¶æˆå‘˜çš„议题ã€
msgid "Withdraw Access Request"
msgstr "å–消æƒé™ç”³è¯·"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "å³å°†åˆ é™¤ %{group_name}。已删除的群组无法æ¢å¤ï¼ç¡®å®šç»§ç»­å—?"
@@ -3587,10 +3936,13 @@ msgstr "å³å°†åˆ é™¤ä¸Žæºé¡¹ç›® %{forked_from_project} 的派生关系。确定
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "å³å°† %{project_name_with_namespace} 转移给å¦ä¸€ä¸ªæ‰€æœ‰è€…。确定继续å—?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3608,12 +3960,24 @@ msgstr "您ä¸èƒ½å†™å…¥åªè¯»çš„辅助 GitLab Geo 实例。请改用%{link_to_pr
msgid "You cannot write to this read-only GitLab instance."
msgstr "您ä¸èƒ½å†™å…¥è¿™ä¸ªåªè¯»çš„ GitLab 实例。"
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "您已达到项目数é‡é™åˆ¶"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "必须登录æ‰èƒ½å¯¹é¡¹ç›®åŠ æ˜Ÿæ ‡"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "需è¦ç›¸å…³çš„æƒé™ã€‚"
@@ -3647,6 +4011,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr "您的评论将ä¸ä¼šå…¬å¼€æ˜¾ç¤ºã€‚"
@@ -3674,7 +4041,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3686,7 +4053,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3701,6 +4068,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3713,6 +4089,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr "æ交"
@@ -3729,10 +4111,40 @@ msgstr[0] "天"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3766,6 +4178,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3799,6 +4214,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3853,6 +4271,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3899,3 +4320,6 @@ msgstr "用户å"
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index c79a46c93f7..0174e945bab 100644
--- a/locale/zh_HK/gitlab.po
+++ b/locale/zh_HK/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 03:58-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:22-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Traditional, Hong Kong\n"
"Language: zh_HK\n"
@@ -43,6 +43,9 @@ msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "為æ高é é¢åŠ è¼‰é€Ÿåº¦åŠæ€§èƒ½ï¼Œå·²çœç•¥äº† %s 次æ交。"
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -50,6 +53,9 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -59,6 +65,9 @@ msgstr "已失敗 %{number_of_failures} 次,最大失敗 %{maximum_failures} æ
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "已失敗 %{number_of_failures} 次,最大失敗 %{maximum_failures} 次,GitLabä¸æœƒé‡è©¦ã€‚當å•é¡Œè§£æ±ºæ™‚é‡ç½®å­˜å„²ä¿¡æ¯ã€‚"
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}:已訪å•æ­¤ä¸»æ©Ÿå¤±æ•— %{failed_attempts} 次"
@@ -121,9 +130,15 @@ msgstr "添加貢ç»æŒ‡å—"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "添加許å¯è­‰"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "添加新目錄"
@@ -142,12 +157,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr ""
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -172,6 +220,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -181,12 +235,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -199,6 +277,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -223,15 +307,15 @@ msgstr "歸檔項目ï¼å­˜å„²åº«ç‚ºåªè®€"
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "確定è¦åˆªé™¤æ­¤æµæ°´ç·šè¨ˆåŠƒå—Žï¼Ÿ"
-msgid "Are you sure you want to discard your changes?"
-msgstr "確定è¦æ”¾æ£„修改嗎?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "確定è¦é‡ç½®è¨»å†Šä»¤ç‰Œå—Žï¼Ÿ"
msgid "Are you sure you want to reset the health check token?"
msgstr "確定è¦é‡ç½®å¥åº·æª¢æŸ¥ä»¤ç‰Œå—Žï¼Ÿ"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "確定嗎?"
@@ -271,6 +355,9 @@ msgstr ""
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -295,7 +382,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
@@ -307,6 +400,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -361,12 +457,9 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "分支"
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "分支 <strong>%{branch_name}</strong> 已創建。如需設置自動部署, è«‹é¸æ“‡åˆé©çš„ GitLab CI Yaml 模æ¿ä½µæ交更改。%{link_to_autodeploy_doc}"
@@ -659,6 +752,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr ""
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -713,6 +809,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -761,6 +860,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -812,9 +914,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -950,6 +1049,12 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "è©•è«–"
@@ -957,6 +1062,10 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "æ交"
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+
msgid "Commit Message"
msgstr ""
@@ -969,6 +1078,9 @@ msgstr "æ交信æ¯"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "æ交"
@@ -1110,6 +1222,9 @@ msgstr "複製URL到剪貼æ¿"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "複製æ交 SHA 到剪貼æ¿"
@@ -1122,9 +1237,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "創建新目錄"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "在帳戶上創建個人訪å•ä»¤ç‰Œï¼Œä»¥é€šéŽ %{protocol} 來拉å–或推é€ã€‚"
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "創建目錄"
@@ -1143,6 +1267,9 @@ msgstr ""
msgid "Create merge request"
msgstr "創建åˆä½µè«‹æ±‚"
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr ""
@@ -1167,6 +1294,12 @@ msgstr "標籤"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "創建個人訪å•ä»¤ç‰Œ"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1221,6 +1354,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "使用 Cron 語法定義自定義模å¼"
@@ -1252,8 +1388,8 @@ msgstr "目錄å稱"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
-msgstr "放棄更改"
+msgid "Discard draft"
+msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
@@ -1312,6 +1448,9 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1366,9 +1505,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1435,12 +1583,36 @@ msgstr ""
msgid "Explore public groups"
msgstr ""
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "無法變更所有者"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "無法刪除æµæ°´ç·šè¨ˆåŠƒ"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1456,6 +1628,9 @@ msgstr ""
msgid "Files"
msgstr "文件"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "按æ交消æ¯éŽæ¿¾"
@@ -1490,6 +1665,9 @@ msgstr "從創建議題到部署到生產環境"
msgid "From merge request merge until deploy to production"
msgstr "從åˆä½µè«‹æ±‚çš„åˆä½µåˆ°éƒ¨ç½²è‡³ç”Ÿç”¢ç’°å¢ƒ"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr ""
@@ -1637,6 +1815,24 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
@@ -1734,6 +1930,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr "已開始維護"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "導入存儲庫"
@@ -1746,6 +1945,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "安è£å£¹å€‹èˆ‡ GitLab CI 兼容的 Runner"
@@ -1795,6 +1997,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1825,6 +2030,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1871,6 +2079,12 @@ msgstr "在"
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "了解更多"
@@ -1889,6 +2103,9 @@ msgstr "退出項目"
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1898,6 +2115,9 @@ msgstr ""
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1907,6 +2127,9 @@ msgstr ""
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr ""
@@ -1937,9 +2160,6 @@ msgstr "中ä½æ•¸"
msgid "Members"
msgstr ""
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr ""
@@ -1952,6 +2172,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1976,9 +2199,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "添加壹個 SSH 公鑰"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr ""
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr "幫助文檔"
@@ -2073,9 +2305,6 @@ msgstr "沒有存儲庫"
msgid "No schedules"
msgstr "沒有計劃"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr ""
@@ -2091,6 +2320,9 @@ msgstr ""
msgid "Not enough data"
msgstr "數據ä¸è¶³"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "通知事件"
@@ -2193,6 +2425,9 @@ msgstr ""
msgid "Options"
msgstr "æ“作"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr ""
@@ -2298,6 +2533,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "所有"
@@ -2331,6 +2584,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr ""
@@ -2493,12 +2749,30 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2520,9 +2794,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2541,6 +2824,12 @@ msgstr ""
msgid "Push events"
msgstr "推é€äº‹ä»¶ (push event) "
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2604,6 +2893,9 @@ msgstr ""
msgid "Repository"
msgstr "存儲庫"
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "申請權é™"
@@ -2616,6 +2908,9 @@ msgstr "é‡ç½®å¥åº·æª¢æŸ¥è¨ªå•ä»¤ç‰Œ"
msgid "Reset runners registration token"
msgstr "é‡ç½® Runner 註冊令牌"
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2626,6 +2921,9 @@ msgstr "還原此æ交"
msgid "Revert this merge request"
msgstr "還原此åˆä½µè«‹æ±‚"
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr ""
@@ -2671,12 +2969,18 @@ msgstr ""
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "é¸æ“‡ä¸‹è¼‰æ ¼å¼"
msgid "Select a timezone"
msgstr "é¸æ“‡æ™‚å€"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2689,6 +2993,9 @@ msgstr "é¸æ“‡ç›®æ¨™åˆ†æ”¯"
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2701,6 +3008,9 @@ msgstr ""
msgid "Service Templates"
msgstr ""
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "為賬號添加壹個用於推é€æˆ–拉å–çš„ %{protocol} 密碼。"
@@ -2710,15 +3020,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "設置 Koding"
-msgid "Set up auto deploy"
-msgstr "設置自動部署"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "設置密碼"
msgid "Settings"
msgstr ""
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2728,6 +3038,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr ""
@@ -2768,12 +3081,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr ""
msgid "Something went wrong while fetching the registry list."
msgstr ""
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2879,6 +3204,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "æºä»£ç¢¼"
@@ -2918,9 +3246,9 @@ msgstr "切æ›åˆ†æ”¯/標籤"
msgid "System Hooks"
msgstr ""
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "標籤"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
msgid "Tags"
msgstr "標籤"
@@ -3051,9 +3379,15 @@ msgstr "該項目å…許任何人訪å•ã€‚"
msgid "The repository for this project does not exist."
msgstr "此項目的存儲庫ä¸å­˜åœ¨ã€‚"
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "評審階段概述了從創建åˆä½µè«‹æ±‚到åˆä½µçš„時間。當創建第壹個åˆä½µè«‹æ±‚後,數據將自動添加到此處。"
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "é ç™¼å¸ƒéšŽæ®µæ¦‚述了åˆä½µè«‹æ±‚çš„åˆä½µåˆ°éƒ¨ç½²ä»£ç¢¼åˆ°ç”Ÿç”¢ç’°å¢ƒçš„總時間。當首次部署到生產環境後,數據將自動添加到此處。"
@@ -3147,6 +3481,9 @@ msgstr "在創建壹個空的存儲庫或導入ç¾æœ‰å­˜å„²åº«ä¹‹å‰ï¼Œæ‚¨å°‡ç„¡
msgid "This merge request is locked."
msgstr ""
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3314,9 +3651,15 @@ msgstr[0] "分é˜"
msgid "Time|s"
msgstr "秒"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3332,19 +3675,16 @@ msgstr ""
msgid "Total Time"
msgstr "總時間"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "所有æ交和åˆä½µçš„總測試時間"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3356,9 +3696,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3374,6 +3711,9 @@ msgstr ""
msgid "Unlocked"
msgstr ""
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "å–消星標"
@@ -3419,6 +3759,9 @@ msgstr "使用全局通知設置"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -3455,6 +3798,9 @@ msgstr "該階段的數據ä¸è¶³ï¼Œç„¡æ³•é¡¯ç¤ºã€‚"
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3575,6 +3921,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "å–消權é™ç”³è¯·"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "å³å°‡åˆªé™¤ %{group_name}。已刪除的群組無法æ¢å¾©ï¼ç¢ºå®šç¹¼çºŒå—Žï¼Ÿ"
@@ -3587,10 +3936,13 @@ msgstr "å³å°‡åˆªé™¤èˆ‡æºé …ç›® %{forked_from_project} 的派生關系。確定
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "å³å°‡ %{project_name_with_namespace} 轉義給å¦å£¹å€‹æ‰€æœ‰è€…。確定繼續嗎?"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3608,12 +3960,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr ""
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "您已é”到項目數é‡é™åˆ¶"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "必須登錄æ‰èƒ½å°é …目加星標"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "需è¦ç›¸é—œçš„權é™ã€‚"
@@ -3647,6 +4011,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -3674,7 +4041,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3686,7 +4053,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3701,6 +4068,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3713,6 +4089,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3729,10 +4111,40 @@ msgstr[0] "天"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3766,6 +4178,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3799,6 +4214,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3853,6 +4271,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3899,3 +4320,6 @@ msgstr ""
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index 635f5c6c449..025af6fa2d9 100644
--- a/locale/zh_TW/gitlab.po
+++ b/locale/zh_TW/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-07 11:38-0600\n"
-"PO-Revision-Date: 2018-02-12 03:58-0500\n"
+"POT-Creation-Date: 2018-03-02 13:39+0100\n"
+"PO-Revision-Date: 2018-03-05 03:23-0500\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Traditional\n"
"Language: zh_TW\n"
@@ -43,6 +43,9 @@ 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)。"
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -50,6 +53,9 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} åƒèˆ‡è€…"
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -59,6 +65,9 @@ msgstr "ç›®å‰å·²å¤±æ•— %{number_of_failures} 次。GitLab å…許在 %{maximum_f
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
msgstr "已失敗 %{number_of_failures} / %{maximum_failures} 次,GitLab å°‡ä¸å†è‡ªå‹•é‡è©¦ã€‚請在確èªå•é¡Œè§£æ±ºå¾Œæ‰‹å‹•é‡ç½®å„²å­˜ç©ºé–“資訊。"
+msgid "%{openOrClose} %{noteable}"
+msgstr ""
+
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}:已存å–此主機失敗 %{failed_attempts} 次"
@@ -121,9 +130,15 @@ msgstr "新增å”作指å—"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
+msgid "Add Kubernetes cluster"
+msgstr ""
+
msgid "Add License"
msgstr "新增授權æ¢æ¬¾"
+msgid "Add Readme"
+msgstr ""
+
msgid "Add new directory"
msgstr "新增目錄"
@@ -142,12 +157,45 @@ msgstr ""
msgid "AdminArea|Stopping jobs failed"
msgstr ""
-msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
+msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
msgid "AdminHealthPageLink|health page"
msgstr "系統狀態"
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminProjects|Delete project"
+msgstr ""
+
+msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}"
+msgstr ""
+
msgid "Advanced"
msgstr ""
@@ -172,6 +220,12 @@ msgstr ""
msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while adding approver"
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
@@ -181,12 +235,36 @@ msgstr ""
msgid "An error occurred while fetching sidebar data"
msgstr ""
+msgid "An error occurred while fetching the pipeline."
+msgstr ""
+
msgid "An error occurred while getting projects"
msgstr ""
+msgid "An error occurred while importing project"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading commits"
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
msgid "An error occurred while loading filenames"
msgstr ""
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while removing approver"
+msgstr ""
+
msgid "An error occurred while rendering KaTeX"
msgstr ""
@@ -199,6 +277,12 @@ msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
+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 validating username"
msgstr ""
@@ -223,15 +307,15 @@ msgstr "此專案已å°å­˜ï¼æª”案庫 (repository) 為唯讀狀態"
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "確定è¦åˆªé™¤æ­¤æµæ°´ç·š (pipeline) 排程嗎?"
-msgid "Are you sure you want to discard your changes?"
-msgstr "確定è¦æ”¾æ£„修改嗎?"
-
msgid "Are you sure you want to reset registration token?"
msgstr "確定è¦é‡ç½®è¨»å†Šæ†‘è­‰ (registration token) 嗎?"
msgid "Are you sure you want to reset the health check token?"
msgstr "確定è¦é‡ç½®å¥åº·æª¢æŸ¥å­˜å–憑證 (access token) 嗎?"
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
msgid "Are you sure?"
msgstr "確定嗎?"
@@ -271,6 +355,9 @@ msgstr "作者"
msgid "Authors: %{authors}"
msgstr ""
+msgid "Auto DevOps enabled"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -295,8 +382,14 @@ msgstr "將根據設定的的 CI / CD æµç¨‹è‡ªå‹•å»ºæ§‹ã€æ¸¬è©¦å’Œéƒ¨ç½²æ‡‰ç”¨
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "了解更多於 %{link_to_documentation}"
-msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
-msgstr "ä½ å¯ä»¥ç‚ºæ­¤å°ˆæ¡ˆå•Ÿå‹• %{link_to_settings}"
+msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
+msgstr ""
+
+msgid "AutoDevOps|add a Kubernetes cluster"
+msgstr ""
+
+msgid "AutoDevOps|enable Auto DevOps (Beta)"
+msgstr ""
msgid "Available"
msgstr ""
@@ -307,6 +400,9 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
+msgid "Begin with the selected commit"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -361,12 +457,9 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
-msgid "Begin with the selected commit"
-msgstr ""
-
-msgid "Branch"
-msgid_plural "Branches"
-msgstr[0] "分支 (branch) "
+msgid "Branch (%{branch_count})"
+msgid_plural "Branches (%{branch_count})"
+msgstr[0] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "已建立分支 (branch) <strong>%{branch_name}</strong> 。如需設定自動部署, 在é¸æ“‡åˆé©çš„ GitLab CI Yaml 模æ¿å¾Œï¼Œè«‹é€äº¤ (commit) 您的編輯內容。%{link_to_autodeploy_doc}"
@@ -659,6 +752,9 @@ msgstr ""
msgid "CircuitBreakerApiLink|circuitbreaker api"
msgstr "斷路器 (circuitbreaker) API"
+msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
+msgstr ""
+
msgid "Click to expand text"
msgstr ""
@@ -713,6 +809,9 @@ msgstr ""
msgid "ClusterIntegration|Copy CA Certificate"
msgstr ""
+msgid "ClusterIntegration|Copy Ingress IP Address to clipboard"
+msgstr ""
+
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
@@ -761,6 +860,9 @@ msgstr ""
msgid "ClusterIntegration|Ingress"
msgstr ""
+msgid "ClusterIntegration|Ingress IP Address"
+msgstr ""
+
msgid "ClusterIntegration|Install"
msgstr ""
@@ -812,9 +914,6 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "學習更多有關於%{link_to_documentation}"
-msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
-
msgid "ClusterIntegration|Learn more about environments"
msgstr ""
@@ -950,6 +1049,12 @@ msgstr "設定正確"
msgid "Collapse"
msgstr ""
+msgid "Comment and resolve discussion"
+msgstr ""
+
+msgid "Comment and unresolve discussion"
+msgstr ""
+
msgid "Comments"
msgstr "留言"
@@ -957,6 +1062,10 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "更動記錄 (commit) "
+msgid "Commit (%{commit_count})"
+msgid_plural "Commits (%{commit_count})"
+msgstr[0] ""
+
msgid "Commit Message"
msgstr "更動訊æ¯"
@@ -969,6 +1078,9 @@ msgstr "更動說明 (commit) "
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
+msgid "Commit to %{branchName} branch"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr "é€äº¤"
@@ -1110,6 +1222,9 @@ msgstr "複製網å€åˆ°å‰ªè²¼ç°¿"
msgid "Copy branch name to clipboard"
msgstr ""
+msgid "Copy command to clipboard"
+msgstr ""
+
msgid "Copy commit SHA to clipboard"
msgstr "複製更動記錄 (commit) 的 SHA 值到剪貼簿"
@@ -1122,9 +1237,18 @@ msgstr ""
msgid "Create New Directory"
msgstr "建立新目錄"
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new branch and merge request"
+msgstr ""
+
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "建立個人存å–憑證 (access token) 以使用 %{protocol} 來上傳 (push) 或下載 (pull) 。"
+msgid "Create branch"
+msgstr ""
+
msgid "Create directory"
msgstr "建立目錄"
@@ -1143,6 +1267,9 @@ msgstr ""
msgid "Create merge request"
msgstr "發出åˆä½µè«‹æ±‚ (merge request) "
+msgid "Create merge request and branch"
+msgstr ""
+
msgid "Create new branch"
msgstr "新增分支(branch)"
@@ -1167,6 +1294,12 @@ msgstr "建立標籤"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "建立個人存å–憑證 (access token)"
+msgid "Creates a new branch from %{branchName}"
+msgstr ""
+
+msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
+msgstr ""
+
msgid "Creating epic"
msgstr ""
@@ -1221,6 +1354,9 @@ msgstr ""
msgid "December"
msgstr ""
+msgid "Default classification label"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "使用 Cron 語法自訂排程"
@@ -1252,8 +1388,8 @@ msgstr "目錄å稱"
msgid "Disable"
msgstr ""
-msgid "Discard changes"
-msgstr "放棄修改"
+msgid "Discard draft"
+msgstr ""
msgid "Discover GitLab Geo."
msgstr ""
@@ -1312,6 +1448,9 @@ msgstr "é›»å­éƒµä»¶"
msgid "Enable"
msgstr ""
+msgid "Enable Auto DevOps"
+msgstr ""
+
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
@@ -1366,9 +1505,18 @@ msgstr ""
msgid "Epics"
msgstr ""
+msgid "Epics Roadmap"
+msgstr ""
+
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
+msgid "Error checking branch data. Please try again."
+msgstr ""
+
+msgid "Error committing changes. Please try again."
+msgstr ""
+
msgid "Error creating epic"
msgstr ""
@@ -1435,12 +1583,36 @@ msgstr "ç€è¦½å°ˆæ¡ˆ"
msgid "Explore public groups"
msgstr "æœå°‹å…¬é–‹çš„群組"
+msgid "External Classification Policy Authorization"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification Label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "無法變更所有權"
+msgid "Failed to remove issue from board, please try again."
+msgstr ""
+
msgid "Failed to remove the pipeline schedule"
msgstr "無法刪除æµæ°´ç·š (pipeline) 排程"
+msgid "Failed to update issues, please try again."
+msgstr ""
+
msgid "Feb"
msgstr ""
@@ -1456,6 +1628,9 @@ msgstr "檔案å稱"
msgid "Files"
msgstr "檔案"
+msgid "Files (%{human_size})"
+msgstr ""
+
msgid "Filter by commit message"
msgstr "以更動說明篩é¸"
@@ -1490,6 +1665,9 @@ msgstr "從議題 (issue) 建立直到部署至營é‹ç’°å¢ƒ"
msgid "From merge request merge until deploy to production"
msgstr "從請求被åˆä½µå¾Œ (merge request merged) 直到部署至營é‹ç’°å¢ƒ"
+msgid "From the Kubernetes cluster details view, install Runner from the applications list"
+msgstr ""
+
msgid "GPG Keys"
msgstr "GPG 金鑰"
@@ -1637,6 +1815,24 @@ msgstr "Google 身份驗證ä¸æ˜¯ %{link_to_documentation}。如果您想使用æ
msgid "Got it!"
msgstr ""
+msgid "GroupRoadmap|Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "GroupRoadmap|From %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading roadmap"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown &ndash; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|Until %{dateWord}"
+msgstr ""
+
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr "ç¦æ­¢èˆ‡å…¶ä»–群組共享 %{group} 中的專案"
@@ -1734,6 +1930,9 @@ msgstr "æ­·å²"
msgid "Housekeeping successfully started"
msgstr "已開始維護"
+msgid "If you already have files you can push them using the %{link_to_cli} below."
+msgstr ""
+
msgid "Import repository"
msgstr "匯入檔案庫 (repository)"
@@ -1746,6 +1945,9 @@ msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
msgstr ""
+msgid "Install Runner on Kubernetes"
+msgstr ""
+
msgid "Install a Runner compatible with GitLab CI"
msgstr "安è£èˆ‡ GitLab CI 相容的 Runner"
@@ -1795,6 +1997,9 @@ msgstr ""
msgid "January"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "Jul"
msgstr ""
@@ -1825,6 +2030,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
+msgid "Kubernetes configured"
+msgstr ""
+
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
@@ -1871,6 +2079,12 @@ msgstr "æ–¼"
msgid "Learn more"
msgstr ""
+msgid "Learn more about Kubernetes"
+msgstr ""
+
+msgid "Learn more about protected branches"
+msgstr ""
+
msgid "Learn more in the"
msgstr "了解更多"
@@ -1889,6 +2103,9 @@ msgstr "退出專案"
msgid "License"
msgstr ""
+msgid "List"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -1898,6 +2115,9 @@ msgstr "鎖定"
msgid "Lock %{issuableDisplayName}"
msgstr ""
+msgid "Lock not found"
+msgstr ""
+
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgstr ""
@@ -1907,6 +2127,9 @@ msgstr "鎖定"
msgid "Locked Files"
msgstr ""
+msgid "Locks give the ability to lock specific file or folder."
+msgstr ""
+
msgid "Login"
msgstr "登入"
@@ -1937,9 +2160,6 @@ msgstr "中ä½æ•¸"
msgid "Members"
msgstr "æˆå“¡"
-msgid "Merge Request"
-msgstr ""
-
msgid "Merge Requests"
msgstr "åˆä½µè«‹æ±‚ (merge request)"
@@ -1952,6 +2172,9 @@ msgstr "åˆä½µè«‹æ±‚"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "MergeRequest|Approved"
+msgstr ""
+
msgid "Merged"
msgstr ""
@@ -1976,9 +2199,18 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "新增 SSH 金鑰"
+msgid "Modal|Cancel"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
msgid "Monitoring"
msgstr "監控"
+msgid "More information"
+msgstr ""
+
msgid "More information is available|here"
msgstr "å¥åº·æª¢æŸ¥"
@@ -2073,9 +2305,6 @@ msgstr "找ä¸åˆ°æª”案庫 (repository)"
msgid "No schedules"
msgstr "沒有排程"
-msgid "No time spent"
-msgstr ""
-
msgid "None"
msgstr "ç„¡"
@@ -2091,6 +2320,9 @@ msgstr ""
msgid "Not enough data"
msgstr "資料ä¸è¶³"
+msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
+msgstr ""
+
msgid "Notification events"
msgstr "事件通知"
@@ -2193,6 +2425,9 @@ msgstr "於新視窗開啟"
msgid "Options"
msgstr "é¸é …"
+msgid "Otherwise it is recommended you start with one of the options below."
+msgstr ""
+
msgid "Overview"
msgstr "總覽"
@@ -2298,6 +2533,24 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
+msgid "Pipeline|Retry pipeline"
+msgstr ""
+
+msgid "Pipeline|Retry pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
+msgstr ""
+
msgid "Pipeline|all"
msgstr "所有"
@@ -2331,6 +2584,9 @@ msgstr "ç§æœ‰ - 專案權é™å¿…須一一指派給æ¯å€‹ä½¿ç”¨è€…"
msgid "Private - The group and its projects can only be viewed by members."
msgstr "ç§æœ‰ - 群組åŠæ——下專案åªèƒ½è¢«è©²ç¾¤çµ„æˆå“¡æŸ¥çœ‹"
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
msgid "Profile"
msgstr "個人資料"
@@ -2493,12 +2749,30 @@ msgstr "抱歉,沒有符åˆæœå°‹æ¢ä»¶çš„專案"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "此功能需è¦ç€è¦½å™¨æ”¯æ´ localStorage"
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration"
+msgstr ""
+
+msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
+msgstr ""
+
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
msgstr ""
msgid "PrometheusService|Finding and configuring metrics..."
msgstr ""
+msgid "PrometheusService|Install Prometheus on clusters"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
msgid "PrometheusService|Metrics"
msgstr ""
@@ -2520,9 +2794,18 @@ msgstr ""
msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
+msgid "PrometheusService|Prometheus is being automatically managed on your clusters"
+msgstr ""
+
msgid "PrometheusService|Time-series monitoring service"
msgstr ""
+msgid "PrometheusService|To enable manual configuration, uninstall Prometheus from your clusters"
+msgstr ""
+
+msgid "PrometheusService|To enable the installation of Prometheus on your clusters, deactivate the manual configuration below"
+msgstr ""
+
msgid "PrometheusService|View environments"
msgstr ""
@@ -2541,6 +2824,12 @@ msgstr ""
msgid "Push events"
msgstr "æŽ¨é€ (push) 事件"
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
msgid "PushRule|Committer restriction"
msgstr ""
@@ -2604,6 +2893,9 @@ msgstr ""
msgid "Repository"
msgstr "檔案庫 (repository)"
+msgid "Repository has no locks."
+msgstr ""
+
msgid "Request Access"
msgstr "申請權é™"
@@ -2616,6 +2908,9 @@ msgstr "é‡ç½®å¥åº·æª¢æŸ¥å­˜å–憑證 (access token)"
msgid "Reset runners registration token"
msgstr "é‡ç½® Runner 註冊憑證 (registration token)"
+msgid "Resolve discussion"
+msgstr ""
+
msgid "Reveal value"
msgid_plural "Reveal values"
msgstr[0] ""
@@ -2626,6 +2921,9 @@ msgstr "還原此更動記錄 (commit)"
msgid "Revert this merge request"
msgstr "還原此åˆä½µè«‹æ±‚ (merge request) "
+msgid "Roadmap"
+msgstr ""
+
msgid "SSH Keys"
msgstr "SSH 金鑰"
@@ -2671,12 +2969,18 @@ msgstr "等待存å–儲存空間的嘗試時間(秒)"
msgid "Secret variables"
msgstr ""
+msgid "Security report"
+msgstr ""
+
msgid "Select Archive Format"
msgstr "é¸æ“‡ä¸‹è¼‰æ ¼å¼"
msgid "Select a timezone"
msgstr "é¸æ“‡æ™‚å€"
+msgid "Select an existing Kubernetes cluster or create a new one"
+msgstr ""
+
msgid "Select assignee"
msgstr ""
@@ -2689,6 +2993,9 @@ msgstr "é¸æ“‡ç›®æ¨™åˆ†æ”¯ (branch) "
msgid "Selective synchronization"
msgstr ""
+msgid "Send email"
+msgstr ""
+
msgid "Sep"
msgstr ""
@@ -2701,6 +3008,9 @@ msgstr ""
msgid "Service Templates"
msgstr "æœå‹™ç¯„本"
+msgid "Service URL"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "請先設定密碼,æ‰èƒ½ä½¿ç”¨ %{protocol} 來上傳 (push) 或下載 (pull) 。"
@@ -2710,15 +3020,15 @@ msgstr ""
msgid "Set up Koding"
msgstr "設定 Koding"
-msgid "Set up auto deploy"
-msgstr "設定自動部署"
-
msgid "SetPasswordToCloneLink|set a password"
msgstr "設定密碼"
msgid "Settings"
msgstr "設定"
+msgid "Setup a specific Runner automatically"
+msgstr ""
+
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
@@ -2728,6 +3038,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
+msgid "Show command"
+msgstr ""
+
msgid "Show parent pages"
msgstr "顯示上層é é¢"
@@ -2768,12 +3081,24 @@ msgstr ""
msgid "Something went wrong when toggling the button"
msgstr ""
+msgid "Something went wrong while closing the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while fetching SAST."
+msgstr ""
+
msgid "Something went wrong while fetching the projects."
msgstr "讀å–專案時發生錯誤。"
msgid "Something went wrong while fetching the registry list."
msgstr "讀å–註冊列表時發生錯誤。"
+msgid "Something went wrong while reopening the %{issuable}. Please try again later"
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
msgid "Something went wrong. Please try again."
msgstr ""
@@ -2879,6 +3204,9 @@ msgstr ""
msgid "Source"
msgstr ""
+msgid "Source (branch or tag)"
+msgstr ""
+
msgid "Source code"
msgstr "原始碼"
@@ -2918,9 +3246,9 @@ msgstr "切æ›åˆ†æ”¯ (branch) 或標籤"
msgid "System Hooks"
msgstr "系統鉤å­"
-msgid "Tag"
-msgid_plural "Tags"
-msgstr[0] "標籤"
+msgid "Tag (%{tag_count})"
+msgid_plural "Tags (%{tag_count})"
+msgstr[0] ""
msgid "Tags"
msgstr "標籤"
@@ -3051,9 +3379,15 @@ msgstr "本專案å¯è®“任何人存å–"
msgid "The repository for this project does not exist."
msgstr "本專案沒有檔案庫 (repository) "
+msgid "The repository for this project is empty"
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "複閱階段顯示從åˆä½µè«‹æ±‚ (merge request) 建立後至被åˆä½µçš„時間。當建立第一個åˆä½µè«‹æ±‚ (merge request) 後,資料將自動填入。"
+msgid "The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "試營é‹æ®µé¡¯ç¤ºå¾žåˆä½µè«‹æ±‚ (merge request) 被åˆä½µå¾Œè‡³éƒ¨ç½²ç‡Ÿé‹çš„時間。當第一次部署營é‹å¾Œï¼Œè³‡æ–™å°‡è‡ªå‹•å¡«å…¥"
@@ -3147,6 +3481,9 @@ msgstr "這代表在您建立一個空的檔案庫 (repository) 或是匯入一å
msgid "This merge request is locked."
msgstr "這個åˆä½µè«‹æ±‚已被鎖定。"
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
msgid "This project"
msgstr ""
@@ -3314,9 +3651,15 @@ msgstr[0] "分é˜"
msgid "Time|s"
msgstr "秒"
+msgid "Tip:"
+msgstr ""
+
msgid "Title"
msgstr ""
+msgid "To view the roadmap, add a planned start or finish date to one of your epics in this group or its subgroups. Only epics in the past 3 months and the next 3 months are shown."
+msgstr ""
+
msgid "Todo"
msgstr ""
@@ -3332,19 +3675,16 @@ msgstr ""
msgid "Total Time"
msgstr "總時間"
-msgid "Total issue time spent"
-msgstr ""
-
msgid "Total test time for all commits/merges"
msgstr "åˆä½µ (merge) 與更動記錄 (commit) 的總測試時間"
-msgid "Track activity with Contribution Analytics."
+msgid "Total: %{total}"
msgstr ""
-msgid "Track groups of issues that share a theme, across projects and milestones"
+msgid "Track activity with Contribution Analytics."
msgstr ""
-msgid "Total: %{total}"
+msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
msgid "Track time with quick actions"
@@ -3356,9 +3696,6 @@ msgstr ""
msgid "Turn on Service Desk"
msgstr ""
-msgid "Type %{value} to confirm:"
-msgstr ""
-
msgid "Unable to reset project cache."
msgstr ""
@@ -3374,6 +3711,9 @@ msgstr ""
msgid "Unlocked"
msgstr "已解鎖"
+msgid "Unresolve discussion"
+msgstr ""
+
msgid "Unstar"
msgstr "å–消收è—"
@@ -3419,6 +3759,9 @@ msgstr "使用全域通知設定"
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
+msgid "View epics list"
+msgstr ""
+
msgid "View file @ "
msgstr "ç€è¦½æª”案 @ "
@@ -3455,6 +3798,9 @@ msgstr "因該階段的資料ä¸è¶³è€Œç„¡æ³•é¡¯ç¤ºç›¸é—œè³‡è¨Š"
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "Web IDE"
+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 ""
@@ -3575,6 +3921,9 @@ msgstr ""
msgid "Withdraw Access Request"
msgstr "å–消權é™ç”³è«‹"
+msgid "Write a commit message..."
+msgstr ""
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr "å°‡è¦åˆªé™¤ %{group_name}。被刪除的群組無法復原ï¼çœŸçš„「確定ã€è¦é€™éº¼åšå—Žï¼Ÿ"
@@ -3587,10 +3936,13 @@ msgstr "å°‡è¦åˆªé™¤æœ¬åˆ†æ”¯å°ˆæ¡ˆèˆ‡ä¸»å¹¹ %{forked_from_project} 的所有關
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "å°‡è¦æŠŠ %{project_name_with_namespace} 的所有權轉移給å¦ä¸€å€‹äººã€‚真的「確定ã€è¦é€™éº¼åšå—Žï¼Ÿ"
+msgid "You can also create a project from the command line."
+msgstr ""
+
msgid "You can also star a label to make it a priority label."
msgstr ""
-msgid "You can move around the graph by using the arrow keys."
+msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}"
msgstr ""
msgid "You can move around the graph by using the arrow keys."
@@ -3608,12 +3960,24 @@ msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr "您ä¸èƒ½ä¿®æ”¹é€™å€‹å”¯è®€çš„ GitLab 主機。"
+msgid "You do not have the correct permissions to override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
msgid "You have reached your project limit"
msgstr "您已é”到專案數é‡é™åˆ¶"
+msgid "You must have master access to force delete a lock"
+msgstr ""
+
msgid "You must sign in to star a project"
msgstr "必須登入æ‰èƒ½æ”¶è—專案"
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
msgid "You need permission."
msgstr "需è¦æ¬Šé™æ‰èƒ½é€™éº¼åšã€‚"
@@ -3647,6 +4011,9 @@ msgstr ""
msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
msgstr ""
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr "你的留言將ä¸æœƒè¢«å…¬é–‹ã€‚"
@@ -3674,7 +4041,7 @@ msgstr ""
msgid "ciReport|DAST detected no alerts by analyzing the review app"
msgstr ""
-msgid "ciReport|Failed to load ${type} report"
+msgid "ciReport|Failed to load %{reportName} report"
msgstr ""
msgid "ciReport|Fixed:"
@@ -3686,7 +4053,7 @@ msgstr ""
msgid "ciReport|Learn more about whitelisting"
msgstr ""
-msgid "ciReport|Loading ${type} report"
+msgid "ciReport|Loading %{reportName} report"
msgstr ""
msgid "ciReport|No changes to code quality"
@@ -3701,6 +4068,15 @@ msgstr ""
msgid "ciReport|SAST"
msgstr ""
+msgid "ciReport|SAST degraded on"
+msgstr ""
+
+msgid "ciReport|SAST detected"
+msgstr ""
+
+msgid "ciReport|SAST detected no new security vulnerabilities"
+msgstr ""
+
msgid "ciReport|SAST detected no security vulnerabilities"
msgstr ""
@@ -3713,6 +4089,12 @@ msgstr ""
msgid "ciReport|Unapproved vulnerabilities (red) can be marked as approved. %{helpLink}"
msgstr ""
+msgid "ciReport|no security vulnerabilities"
+msgstr ""
+
+msgid "command line instructions"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -3729,10 +4111,40 @@ msgstr[0] "天"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
+msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
+msgstr ""
+
+msgid "mrWidget|Add approval"
+msgstr ""
+
+msgid "mrWidget|An error occured while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occured while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occured while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
msgid "mrWidget|Cancel automatic merge"
msgstr ""
@@ -3766,6 +4178,9 @@ msgstr ""
msgid "mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the"
msgstr ""
+msgid "mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line"
+msgstr ""
+
msgid "mrWidget|Mentions"
msgstr ""
@@ -3799,6 +4214,9 @@ msgstr ""
msgid "mrWidget|Remove source branch"
msgstr ""
+msgid "mrWidget|Remove your approval"
+msgstr ""
+
msgid "mrWidget|Request to merge"
msgstr ""
@@ -3853,6 +4271,9 @@ msgstr ""
msgid "mrWidget|You can remove source branch now"
msgstr ""
+msgid "mrWidget|branch does not exist."
+msgstr ""
+
msgid "mrWidget|command line"
msgstr ""
@@ -3899,3 +4320,6 @@ msgstr "使用者å稱"
msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
diff --git a/package.json b/package.json
index cbad55b4c85..48954e071da 100644
--- a/package.json
+++ b/package.json
@@ -91,7 +91,7 @@
"worker-loader": "^1.1.0"
},
"devDependencies": {
- "@gitlab-org/gitlab-svgs": "^1.8.0",
+ "@gitlab-org/gitlab-svgs": "^1.13.0",
"axios-mock-adapter": "^1.10.0",
"babel-eslint": "^8.0.2",
"babel-plugin-istanbul": "^4.1.5",
diff --git a/qa/qa/page/project/settings/ci_cd.rb b/qa/qa/page/project/settings/ci_cd.rb
index 99be21bbe89..17a1bc904e4 100644
--- a/qa/qa/page/project/settings/ci_cd.rb
+++ b/qa/qa/page/project/settings/ci_cd.rb
@@ -1,4 +1,4 @@
-module QA
+module QA # rubocop:disable Naming/FileName
module Page
module Project
module Settings
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 9110237c538..b36a3f9c8a0 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Naming/FileName
require_relative 'cop/gitlab/module_with_instance_variables'
require_relative 'cop/gitlab/predicate_memoization'
require_relative 'cop/include_sidekiq_worker'
diff --git a/scripts/trigger-build-docs b/scripts/trigger-build-docs
index a270823b857..c9aaba91aa0 100755
--- a/scripts/trigger-build-docs
+++ b/scripts/trigger-build-docs
@@ -7,7 +7,7 @@ require 'gitlab'
#
Gitlab.configure do |config|
config.endpoint = 'https://gitlab.com/api/v4'
- config.private_token = ENV["DOCS_API_TOKEN"] # GitLab Docs bot access token which has only Developer access to gitlab-docs
+ config.private_token = ENV["DOCS_API_TOKEN"] # GitLab Docs bot access token with Developer access to gitlab-docs
end
#
@@ -24,20 +24,40 @@ def docs_branch
# The maximum string length a file can have on a filesystem (ext4)
# is 63 characters. Let's use something smaller to be 100% sure.
max = 42
- # Prefix the remote branch with 'preview-' in order to avoid
- # name conflicts in the rare case the branch name already
+ # Prefix the remote branch with the slug of the project in order
+ # to avoid name conflicts in the rare case the branch name already
# exists in the docs repo and truncate to max length.
"#{slug}-#{ENV["CI_COMMIT_REF_SLUG"]}"[0...max]
end
#
-# Create a remote branch in gitlab-docs
+# Create a remote branch in gitlab-docs and immediately cancel the pipeline
+# to avoid race conditions, since a triggered pipeline will also run right
+# after the branch creation. This only happens the very first time a branch
+# is created and will be skipped in subsequent runs. Read more in
+# https://gitlab.com/gitlab-com/gitlab-docs/issues/154.
#
def create_remote_branch
Gitlab.create_branch(GITLAB_DOCS_REPO, docs_branch, 'master')
- puts "Remote branch '#{docs_branch}' created"
+ puts "=> Remote branch '#{docs_branch}' created"
+
+ pipelines = nil
+
+ # Wait until the pipeline is started
+ loop do
+ sleep 1
+ puts "=> Waiting for pipeline to start..."
+ pipelines = Gitlab.pipelines(GITLAB_DOCS_REPO, { ref: docs_branch })
+ break if pipelines.any?
+ end
+
+ # Get the first pipeline ID which should be the only one for the branch
+ pipeline_id = pipelines.first.id
+
+ # Cancel the pipeline
+ Gitlab.cancel_pipeline(GITLAB_DOCS_REPO, pipeline_id)
rescue Gitlab::Error::BadRequest
- puts "Remote branch '#{docs_branch}' already exists"
+ puts "=> Remote branch '#{docs_branch}' already exists"
end
#
@@ -45,7 +65,7 @@ end
#
def remove_remote_branch
Gitlab.delete_branch(GITLAB_DOCS_REPO, docs_branch)
- puts "Remote branch '#{docs_branch}' deleted"
+ puts "=> Remote branch '#{docs_branch}' deleted"
end
#
@@ -78,18 +98,22 @@ def trigger_pipeline
# The review app URL
app_url = "http://#{docs_branch}.#{ENV["DOCS_REVIEW_APPS_DOMAIN"]}/#{slug}"
- # Create the pipeline
- puts "=> Triggering a pipeline..."
+ # Create the cross project pipeline using CI_JOB_TOKEN
pipeline = Gitlab.run_trigger(GITLAB_DOCS_REPO, ENV["CI_JOB_TOKEN"], docs_branch, { param_name => ENV["CI_COMMIT_REF_NAME"] })
- puts "=> Pipeline created:"
+ puts "=> Follow the status of the triggered pipeline:"
puts ""
puts "https://gitlab.com/gitlab-com/gitlab-docs/pipelines/#{pipeline.id}"
puts ""
- puts "=> Preview your changes live at:"
+ puts "=> In a few minutes, you will be able to preview your changes under the following URL:"
puts ""
puts app_url
puts ""
+ puts "=> For more information, read the documentation"
+ puts "=> https://docs.gitlab.com/ee/development/writing_documentation.html#previewing-the-changes-live"
+ puts ""
+ puts "=> If something doesn't work, drop a line in the #docs chat channel."
+ puts ""
end
#
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index b7257fac608..fb6d82d7de3 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -246,7 +246,7 @@ describe AutocompleteController do
expect(json_response.size).to eq(1)
expect(json_response.first['id']).to eq authorized_project.id
- expect(json_response.first['name_with_namespace']).to eq authorized_project.name_with_namespace
+ expect(json_response.first['name_with_namespace']).to eq authorized_project.full_name
end
end
end
@@ -267,7 +267,7 @@ describe AutocompleteController do
expect(json_response.size).to eq(1)
expect(json_response.first['id']).to eq authorized_search_project.id
- expect(json_response.first['name_with_namespace']).to eq authorized_search_project.name_with_namespace
+ expect(json_response.first['name_with_namespace']).to eq authorized_search_project.full_name
end
end
end
diff --git a/spec/controllers/groups/boards_controller_spec.rb b/spec/controllers/groups/boards_controller_spec.rb
new file mode 100644
index 00000000000..0f5bde62006
--- /dev/null
+++ b/spec/controllers/groups/boards_controller_spec.rb
@@ -0,0 +1,136 @@
+require 'spec_helper'
+
+describe Groups::BoardsController do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+
+ before do
+ group.add_master(user)
+ sign_in(user)
+ end
+
+ describe 'GET index' do
+ it 'creates a new board when group does not have one' do
+ expect { list_boards }.to change(group.boards, :count).by(1)
+ end
+
+ context 'when format is HTML' do
+ it 'renders template' do
+ list_boards
+
+ expect(response).to render_template :index
+ expect(response.content_type).to eq 'text/html'
+ end
+
+ context 'with unauthorized user' do
+ before do
+ allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
+ allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(false)
+ end
+
+ it 'returns a not found 404 response' do
+ list_boards
+
+ expect(response).to have_gitlab_http_status(404)
+ expect(response.content_type).to eq 'text/html'
+ end
+ end
+ end
+
+ context 'when format is JSON' do
+ it 'return an array with one group board' do
+ create(:board, group: group)
+
+ list_boards format: :json
+
+ parsed_response = JSON.parse(response.body)
+
+ expect(response).to match_response_schema('boards')
+ expect(parsed_response.length).to eq 1
+ end
+
+ context 'with unauthorized user' do
+ before do
+ allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
+ allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(false)
+ end
+
+ it 'returns a not found 404 response' do
+ list_boards format: :json
+
+ expect(response).to have_gitlab_http_status(404)
+ expect(response.content_type).to eq 'application/json'
+ end
+ end
+ end
+
+ def list_boards(format: :html)
+ get :index, group_id: group, format: format
+ end
+ end
+
+ describe 'GET show' do
+ let!(:board) { create(:board, group: group) }
+
+ context 'when format is HTML' do
+ it 'renders template' do
+ read_board board: board
+
+ expect(response).to render_template :show
+ expect(response.content_type).to eq 'text/html'
+ end
+
+ context 'with unauthorized user' do
+ before do
+ allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
+ allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(false)
+ end
+
+ it 'returns a not found 404 response' do
+ read_board board: board
+
+ expect(response).to have_gitlab_http_status(404)
+ expect(response.content_type).to eq 'text/html'
+ end
+ end
+ end
+
+ context 'when format is JSON' do
+ it 'returns project board' do
+ read_board board: board, format: :json
+
+ expect(response).to match_response_schema('board')
+ end
+
+ context 'with unauthorized user' do
+ before do
+ allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true)
+ allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(false)
+ end
+
+ it 'returns a not found 404 response' do
+ read_board board: board, format: :json
+
+ expect(response).to have_gitlab_http_status(404)
+ expect(response.content_type).to eq 'application/json'
+ end
+ end
+ end
+
+ context 'when board does not belong to group' do
+ it 'returns a not found 404 response' do
+ another_board = create(:board)
+
+ read_board board: another_board
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ def read_board(board:, format: :html)
+ get :show, group_id: group,
+ id: board.to_param,
+ format: format
+ end
+ end
+end
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index 734396ddf7b..3b9e06cb5ad 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -407,10 +407,43 @@ describe Projects::BranchesController do
get :index,
namespace_id: project.namespace,
project_id: project,
+ state: 'all',
format: :html
expect(response).to have_gitlab_http_status(200)
end
end
+
+ context 'when depreated sort/search/page parameters are specified' do
+ it 'returns with a status 301 when sort specified' do
+ get :index,
+ namespace_id: project.namespace,
+ project_id: project,
+ sort: 'updated_asc',
+ format: :html
+
+ expect(response).to redirect_to project_branches_filtered_path(project, state: 'all')
+ end
+
+ it 'returns with a status 301 when search specified' do
+ get :index,
+ namespace_id: project.namespace,
+ project_id: project,
+ search: 'feature',
+ format: :html
+
+ expect(response).to redirect_to project_branches_filtered_path(project, state: 'all')
+ end
+
+ it 'returns with a status 301 when page specified' do
+ get :index,
+ namespace_id: project.namespace,
+ project_id: project,
+ page: 2,
+ format: :html
+
+ expect(response).to redirect_to project_branches_filtered_path(project, state: 'all')
+ end
+ end
end
end
diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb
index 73e7921fab7..6c67dfde63a 100644
--- a/spec/controllers/projects/deployments_controller_spec.rb
+++ b/spec/controllers/projects/deployments_controller_spec.rb
@@ -129,10 +129,10 @@ describe Projects::DeploymentsController do
end
context 'when metrics are enabled' do
- let(:prometheus_service) { double('prometheus_service') }
+ let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
before do
- allow(deployment.project).to receive(:prometheus_service).and_return(prometheus_service)
+ allow(deployment).to receive(:prometheus_adapter).and_return(prometheus_adapter)
end
context 'when environment has no metrics' do
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index 00cf464ec5b..306094f7ffb 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -98,10 +98,8 @@ describe Projects::MilestonesController do
it 'shows group milestone' do
post :promote, namespace_id: project.namespace.id, project_id: project.id, id: milestone.iid
- group_milestone = assigns(:milestone)
-
- expect(response).to redirect_to(group_milestone_path(project.group, group_milestone.iid))
- expect(flash[:notice]).to eq('Milestone has been promoted to group milestone.')
+ expect(flash[:notice]).to eq("#{milestone.title} promoted to group milestone")
+ expect(response).to redirect_to(project_milestones_path(project))
end
end
diff --git a/spec/controllers/projects/prometheus/metrics_controller_spec.rb b/spec/controllers/projects/prometheus/metrics_controller_spec.rb
index f17f819feee..b2b245dba90 100644
--- a/spec/controllers/projects/prometheus/metrics_controller_spec.rb
+++ b/spec/controllers/projects/prometheus/metrics_controller_spec.rb
@@ -4,21 +4,22 @@ describe Projects::Prometheus::MetricsController do
let(:user) { create(:user) }
let(:project) { create(:project) }
- let(:prometheus_service) { double('prometheus_service') }
+ let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
before do
- allow(controller).to receive(:project).and_return(project)
- allow(project).to receive(:find_or_initialize_service).with('prometheus').and_return(prometheus_service)
-
project.add_master(user)
sign_in(user)
end
describe 'GET #active_common' do
+ before do
+ allow(controller).to receive(:prometheus_adapter).and_return(prometheus_adapter)
+ end
+
context 'when prometheus metrics are enabled' do
context 'when data is not present' do
before do
- allow(prometheus_service).to receive(:matched_metrics).and_return({})
+ allow(prometheus_adapter).to receive(:query).with(:matched_metrics).and_return({})
end
it 'returns no content response' do
@@ -32,7 +33,7 @@ describe Projects::Prometheus::MetricsController do
let(:sample_response) { { some_data: 1 } }
before do
- allow(prometheus_service).to receive(:matched_metrics).and_return(sample_response)
+ allow(prometheus_adapter).to receive(:query).with(:matched_metrics).and_return(sample_response)
end
it 'returns no content response' do
@@ -53,6 +54,18 @@ describe Projects::Prometheus::MetricsController do
end
end
+ describe '#prometheus_adapter' do
+ before do
+ allow(controller).to receive(:project).and_return(project)
+ end
+
+ it 'calls prometheus adapter service' do
+ expect_any_instance_of(::Prometheus::AdapterService).to receive(:prometheus_adapter)
+
+ subject.__send__(:prometheus_adapter)
+ end
+ end
+
def project_params(opts = {})
opts.reverse_merge(namespace_id: project.namespace, project_id: project)
end
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 847ac6f2be0..e4dc61b3a68 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -23,6 +23,18 @@ describe Projects::ServicesController do
end
end
+ context 'when validations fail' do
+ let(:service_params) { { active: 'true', token: '' } }
+
+ it 'returns error messages in JSON response' do
+ put :test, namespace_id: project.namespace, project_id: project, id: :hipchat, service: service_params
+
+ expect(json_response['message']).to eq "Validations failed."
+ expect(json_response['service_response']).to eq "Token can't be blank"
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+
context 'success' do
context 'with empty project' do
let(:project) { create(:project) }
diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
index 0202149f335..293e76798ae 100644
--- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
@@ -27,7 +27,7 @@ describe Projects::Settings::CiCdController do
allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true)
end
- subject { post :reset_cache, namespace_id: project.namespace, project_id: project }
+ subject { post :reset_cache, namespace_id: project.namespace, project_id: project, format: :json }
it 'calls reset project cache service' do
expect(ResetProjectCacheService).to receive_message_chain(:new, :execute)
@@ -35,19 +35,11 @@ describe Projects::Settings::CiCdController do
subject
end
- it 'redirects to project pipelines path' do
- subject
-
- expect(response).to have_gitlab_http_status(:redirect)
- expect(response).to redirect_to(project_pipelines_path(project))
- end
-
context 'when service returns successfully' do
- it 'sets the flash notice variable' do
+ it 'returns a success header' do
subject
- expect(controller).to set_flash[:notice]
- expect(controller).not_to set_flash[:error]
+ expect(response).to have_gitlab_http_status(:ok)
end
end
@@ -56,11 +48,10 @@ describe Projects::Settings::CiCdController do
allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false)
end
- it 'sets the flash error variable' do
+ it 'returns an error header' do
subject
- expect(controller).not_to set_flash[:notice]
- expect(controller).to set_flash[:error]
+ expect(response).to have_gitlab_http_status(:bad_request)
end
end
end
diff --git a/spec/factories/badge.rb b/spec/factories/badge.rb
new file mode 100644
index 00000000000..b87ece946cb
--- /dev/null
+++ b/spec/factories/badge.rb
@@ -0,0 +1,14 @@
+FactoryBot.define do
+ trait :base_badge do
+ link_url { generate(:url) }
+ image_url { generate(:url) }
+ end
+
+ factory :project_badge, traits: [:base_badge], class: ProjectBadge do
+ project
+ end
+
+ factory :group_badge, aliases: [:badge], traits: [:base_badge], class: GroupBadge do
+ group
+ end
+end
diff --git a/spec/factories/boards.rb b/spec/factories/boards.rb
index 1e125237ae8..6524bb4830c 100644
--- a/spec/factories/boards.rb
+++ b/spec/factories/boards.rb
@@ -1,6 +1,29 @@
FactoryBot.define do
factory :board do
- project
+ transient do
+ project nil
+ group nil
+ project_id nil
+ group_id nil
+ parent nil
+ end
+
+ after(:build, :stub) do |board, evaluator|
+ if evaluator.group
+ board.group = evaluator.group
+ elsif evaluator.group_id
+ board.group_id = evaluator.group_id
+ elsif evaluator.project
+ board.project = evaluator.project
+ elsif evaluator.project_id
+ board.project_id = evaluator.project_id
+ elsif evaluator.parent
+ id = evaluator.parent.id
+ evaluator.parent.is_a?(Group) ? board.group_id = id : evaluator.project_id = id
+ else
+ board.project = create(:project, :empty_repo)
+ end
+ end
after(:create) do |board|
board.lists.create(list_type: :closed)
diff --git a/spec/factories/ci/job_artifacts.rb b/spec/factories/ci/job_artifacts.rb
index 7ee379ca2ec..8544d54ccaa 100644
--- a/spec/factories/ci/job_artifacts.rb
+++ b/spec/factories/ci/job_artifacts.rb
@@ -35,5 +35,11 @@ FactoryBot.define do
Rails.root.join('spec/fixtures/trace/sample_trace'), 'text/plain')
end
end
+
+ trait :correct_checksum do
+ after(:build) do |artifact, evaluator|
+ artifact.file_sha256 = Digest::SHA256.file(artifact.file.path).hexdigest
+ end
+ end
end
end
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 3f4e408b3a6..857333f222d 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -16,6 +16,8 @@ FactoryBot.define do
factory :note_on_personal_snippet, traits: [:on_personal_snippet]
factory :system_note, traits: [:system]
+ factory :discussion_note, class: DiscussionNote
+
factory :discussion_note_on_merge_request, traits: [:on_merge_request], class: DiscussionNote do
association :project, :repository
@@ -31,6 +33,8 @@ FactoryBot.define do
factory :discussion_note_on_personal_snippet, traits: [:on_personal_snippet], class: DiscussionNote
+ factory :discussion_note_on_snippet, traits: [:on_snippet], class: DiscussionNote
+
factory :legacy_diff_note_on_commit, traits: [:on_commit, :legacy_diff_note], class: LegacyDiffNote
factory :legacy_diff_note_on_merge_request, traits: [:on_merge_request, :legacy_diff_note], class: LegacyDiffNote do
@@ -96,6 +100,10 @@ FactoryBot.define do
noteable { create(:issue, project: project) }
end
+ trait :on_snippet do
+ noteable { create(:snippet, project: project) }
+ end
+
trait :on_merge_request do
noteable { create(:merge_request, source_project: project) }
end
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index a5f22848031..d5e603baeae 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -173,7 +173,7 @@ feature 'Admin Groups' do
visit admin_group_path(group)
- expect(page).to have_content(empty_project.name_with_namespace)
+ expect(page).to have_content(empty_project.full_name)
expect(page).to have_content('Projects shared with')
end
end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index f266f2ecc54..25ed3bdc88e 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -24,6 +24,16 @@ describe 'Admin::Hooks' do
visit admin_hooks_path
expect(page).to have_content(system_hook.url)
end
+
+ it 'renders plugins list as well' do
+ allow(Gitlab::Plugin).to receive(:files).and_return(['foo.rb', 'bar.clj'])
+
+ visit admin_hooks_path
+
+ expect(page).to have_content('Plugins')
+ expect(page).to have_content('foo.rb')
+ expect(page).to have_content('bar.clj')
+ end
end
describe 'New Hook' do
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index d02ac6c2e2a..6d8350e99f1 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -58,7 +58,7 @@ describe "Admin::Projects" do
expect(current_path).to eq admin_project_path(project)
expect(page).to have_content(project.path)
expect(page).to have_content(project.name)
- expect(page).to have_content(project.name_with_namespace)
+ expect(page).to have_content(project.full_name)
expect(page).to have_content(project.creator.name)
end
end
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 7eeed7da998..8de2e3d199b 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -76,8 +76,8 @@ describe "Admin Runners" do
describe 'projects' do
it 'contains project names' do
- expect(page).to have_content(@project1.name_with_namespace)
- expect(page).to have_content(@project2.name_with_namespace)
+ expect(page).to have_content(@project1.full_name)
+ expect(page).to have_content(@project2.full_name)
end
end
@@ -89,8 +89,8 @@ describe "Admin Runners" do
end
it 'contains name of correct project' do
- expect(page).to have_content(@project1.name_with_namespace)
- expect(page).not_to have_content(@project2.name_with_namespace)
+ expect(page).to have_content(@project1.full_name)
+ expect(page).not_to have_content(@project2.full_name)
end
end
diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb
index 54652e2d849..8d1d5a51750 100644
--- a/spec/features/dashboard/issues_spec.rb
+++ b/spec/features/dashboard/issues_spec.rb
@@ -74,8 +74,8 @@ RSpec.describe 'Dashboard Issues' do
find('.new-project-item-select-button').click
page.within('.select2-results') do
- expect(page).to have_content(project.name_with_namespace)
- expect(page).not_to have_content(project_with_issues_disabled.name_with_namespace)
+ expect(page).to have_content(project.full_name)
+ expect(page).not_to have_content(project_with_issues_disabled.full_name)
end
end
@@ -84,8 +84,8 @@ RSpec.describe 'Dashboard Issues' do
wait_for_requests
- project_path = "/#{project.path_with_namespace}"
- project_json = { name: project.name_with_namespace, url: project_path }.to_json
+ project_path = "/#{project.full_path}"
+ project_json = { name: project.full_name, url: project_path }.to_json
# simulate selection, and prevent overlap by dropdown menu
first('.project-item-select', visible: false)
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index 744041ac425..c8f3a8449f5 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -28,8 +28,8 @@ feature 'Dashboard Merge Requests' do
find('.new-project-item-select-button').click
page.within('.select2-results') do
- expect(page).to have_content(project.name_with_namespace)
- expect(page).not_to have_content(project_with_disabled_merge_requests.name_with_namespace)
+ expect(page).to have_content(project.full_name)
+ expect(page).not_to have_content(project_with_disabled_merge_requests.full_name)
end
end
end
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 586c7b48d0b..986f864f0b5 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -37,6 +37,14 @@ feature 'Dashboard Projects' do
expect(page).to have_xpath("//time[@datetime='#{project.last_repository_updated_at.getutc.iso8601}']")
end
+
+ it 'shows the last_activity_at attribute as the update date' do
+ project.update_attributes!(last_repository_updated_at: 1.hour.ago, last_activity_at: Time.now)
+
+ visit dashboard_projects_path
+
+ expect(page).to have_xpath("//time[@datetime='#{project.last_activity_at.getutc.iso8601}']")
+ end
end
context 'when last_repository_updated_at and last_activity_at are missing' do
diff --git a/spec/features/dashboard/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb
index 2fc34301d51..7b359b0c651 100644
--- a/spec/features/dashboard/todos/todos_filtering_spec.rb
+++ b/spec/features/dashboard/todos/todos_filtering_spec.rb
@@ -24,14 +24,14 @@ feature 'Dashboard > User filters todos', :js do
it 'filters by project' do
click_button 'Project'
within '.dropdown-menu-project' do
- fill_in 'Search projects', with: project_1.name_with_namespace
- click_link project_1.name_with_namespace
+ fill_in 'Search projects', with: project_1.full_name
+ click_link project_1.full_name
end
wait_for_requests
- expect(page).to have_content project_1.name_with_namespace
- expect(page).not_to have_content project_2.name_with_namespace
+ expect(page).to have_content project_1.full_name
+ expect(page).not_to have_content project_2.full_name
end
context 'Author filter' do
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index 076a02150a4..3c01ff345fc 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -73,7 +73,7 @@ feature 'issue move to another project' do
wait_for_requests
page.within '.js-sidebar-move-issue-block' do
- expect(page).to have_content new_project.name_with_namespace
+ expect(page).to have_content new_project.full_name
end
end
end
diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb
new file mode 100644
index 00000000000..a3323da1b1f
--- /dev/null
+++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe 'a maintainer edits files on a source-branch of an MR from a fork', :js do
+ include ProjectForksHelper
+ let(:user) { create(:user, username: 'the-maintainer') }
+ let(:target_project) { create(:project, :public, :repository) }
+ let(:author) { create(:user, username: 'mr-authoring-machine') }
+ let(:source_project) { fork_project(target_project, author, repository: true) }
+
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ target_project: target_project,
+ source_branch: 'fix',
+ target_branch: 'master',
+ author: author,
+ allow_maintainer_to_push: true)
+ end
+
+ before do
+ target_project.add_master(user)
+ sign_in(user)
+
+ visit project_merge_request_path(target_project, merge_request)
+ click_link 'Changes'
+ wait_for_requests
+ first('.js-file-title').click_link 'Edit'
+ wait_for_requests
+ end
+
+ it 'mentions commits will go to the source branch' do
+ expect(page).to have_content('Your changes can be committed to fix because a merge request is open.')
+ end
+
+ it 'allows committing to the source branch' do
+ find('.ace_text-input', visible: false).send_keys('Updated the readme')
+
+ click_button 'Commit changes'
+ wait_for_requests
+
+ expect(page).to have_content('Your changes have been successfully committed')
+ expect(page).to have_content('Updated the readme')
+ end
+end
diff --git a/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb b/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb
new file mode 100644
index 00000000000..eb41d7de8ed
--- /dev/null
+++ b/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb
@@ -0,0 +1,85 @@
+require 'spec_helper'
+
+describe 'create a merge request that allows maintainers to push', :js do
+ include ProjectForksHelper
+ let(:user) { create(:user) }
+ let(:target_project) { create(:project, :public, :repository) }
+ let(:source_project) { fork_project(target_project, user, repository: true, namespace: user.namespace) }
+
+ def visit_new_merge_request
+ visit project_new_merge_request_path(
+ source_project,
+ merge_request: {
+ source_project_id: source_project.id,
+ target_project_id: target_project.id,
+ source_branch: 'fix',
+ target_branch: 'master'
+ })
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ it 'allows setting maintainer push possible' do
+ visit_new_merge_request
+
+ check 'Allow edits from maintainers'
+
+ click_button 'Submit merge request'
+
+ wait_for_requests
+
+ expect(page).to have_content('Allows edits from maintainers')
+ end
+
+ it 'shows a message when one of the projects is private' do
+ source_project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+
+ visit_new_merge_request
+
+ expect(page).to have_content('Not available for private projects')
+ end
+
+ it 'shows a message when the source branch is protected' do
+ create(:protected_branch, project: source_project, name: 'fix')
+
+ visit_new_merge_request
+
+ expect(page).to have_content('Not available for protected branches')
+ end
+
+ context 'when the merge request is being created within the same project' do
+ let(:source_project) { target_project }
+
+ it 'hides the checkbox if the merge request is being created within the same project' do
+ target_project.add_developer(user)
+
+ visit_new_merge_request
+
+ expect(page).not_to have_content('Allows edits from maintainers')
+ end
+ end
+
+ context 'when a maintainer tries to edit the option' do
+ let(:maintainer) { create(:user) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ target_project: target_project,
+ source_branch: 'fixes')
+ end
+
+ before do
+ target_project.add_master(maintainer)
+
+ sign_in(maintainer)
+ end
+
+ it 'it hides the option from maintainers' do
+ visit edit_project_merge_request_path(target_project, merge_request)
+
+ expect(page).not_to have_content('Allows edits from maintainers')
+ end
+ end
+end
diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb
index 56224e505d9..51a65407aec 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -1,6 +1,8 @@
require 'rails_helper'
describe 'Merge request > User sees merge widget', :js do
+ include ProjectForksHelper
+
let(:project) { create(:project, :repository) }
let(:project_only_mwps) { create(:project, :repository, only_allow_merge_if_pipeline_succeeds: true) }
let(:user) { project.creator }
@@ -285,7 +287,29 @@ describe 'Merge request > User sees merge widget', :js do
end
it 'user cannot remove source branch' do
- expect(page).to have_field('remove-source-branch-input', disabled: true)
+ expect(page).not_to have_field('remove-source-branch-input')
+ end
+ end
+
+ context 'user cannot merge project and cannot push to fork', :js do
+ let(:forked_project) { fork_project(project, nil, repository: true) }
+ let(:user2) { create(:user) }
+
+ before do
+ project.add_developer(user2)
+ sign_out(:user)
+ sign_in(user2)
+ merge_request.update(
+ source_project: forked_project,
+ target_project: project,
+ merge_params: { 'force_remove_source_branch' => '1' }
+ )
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'user cannot remove source branch' do
+ expect(page).not_to have_field('remove-source-branch-input')
+ expect(page).to have_content('Removes source branch')
end
end
diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb
index cc12a1005ba..19152bf1f0f 100644
--- a/spec/features/milestone_spec.rb
+++ b/spec/features/milestone_spec.rb
@@ -97,4 +97,15 @@ feature 'Milestone' do
end
end
end
+
+ feature 'Deleting a milestone' do
+ scenario "The delete milestone button does not show for unauthorized users" do
+ create(:milestone, project: project, title: 8.7)
+ sign_out(user)
+
+ visit group_milestones_path(group)
+
+ expect(page).to have_selector('.js-delete-milestone-button', count: 0)
+ end
+ end
end
diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb
index 39bcea013e7..605298ba8ab 100644
--- a/spec/features/projects/branches/download_buttons_spec.rb
+++ b/spec/features/projects/branches/download_buttons_spec.rb
@@ -29,7 +29,7 @@ feature 'Download buttons in branches page' do
describe 'when checking branches' do
context 'with artifacts' do
before do
- visit project_branches_path(project, search: 'binary-encoding')
+ visit project_branches_filtered_path(project, state: 'all', search: 'binary-encoding')
end
scenario 'shows download artifacts button' do
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index 2fddd274078..2a9d9e6416c 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -11,15 +11,109 @@ describe 'Branches' do
project.add_developer(user)
end
- describe 'Initial branches page' do
- it 'shows all the branches sorted by last updated by default' do
+ context 'on the projects with 6 active branches and 4 stale branches' do
+ let(:project) { create(:project, :public, :empty_repo) }
+ let(:repository) { project.repository }
+ let(:threshold) { Gitlab::Git::Branch::STALE_BRANCH_THRESHOLD }
+
+ 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}") }
+ 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}") }
+ end
+ end
+
+ describe 'Overview page of the branches' do
+ it 'shows the first 5 active branches and the first 4 stale branches sorted by last updated' do
+ visit project_branches_path(project)
+
+ expect(page).to have_content(sorted_branches(repository, count: 5, sort_by: :updated_desc, state: 'active'))
+ expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_desc, state: 'stale'))
+
+ expect(page).to have_link('Show more active branches', href: project_branches_filtered_path(project, state: 'active'))
+ expect(page).not_to have_content('Show more stale branches')
+ end
+ end
+
+ describe 'Active branches page' do
+ it 'shows 6 active branches sorted by last updated' do
+ visit project_branches_filtered_path(project, state: 'active')
+
+ expect(page).to have_content(sorted_branches(repository, count: 6, sort_by: :updated_desc, state: 'active'))
+ end
+ end
+
+ describe 'Stale branches page' do
+ it 'shows 4 active branches sorted by last updated' do
+ visit project_branches_filtered_path(project, state: 'stale')
+
+ expect(page).to have_content(sorted_branches(repository, count: 4, sort_by: :updated_desc, state: 'stale'))
+ end
+ end
+
+ describe 'All branches page' do
+ it 'shows 10 branches sorted by last updated' do
+ visit project_branches_filtered_path(project, state: 'all')
+
+ expect(page).to have_content(sorted_branches(repository, count: 10, sort_by: :updated_desc))
+ end
+ end
+
+ context 'with branches over more than one page' do
+ before do
+ allow(Kaminari.config).to receive(:default_per_page).and_return(5)
+ end
+
+ it 'shows only default_per_page active branches sorted by last updated' do
+ visit project_branches_filtered_path(project, state: 'active')
+
+ expect(page).to have_content(sorted_branches(repository, count: Kaminari.config.default_per_page, sort_by: :updated_desc, state: 'active'))
+ end
+
+ it 'shows only default_per_page branches sorted by last updated on All branches' do
+ visit project_branches_filtered_path(project, state: 'all')
+
+ expect(page).to have_content(sorted_branches(repository, count: Kaminari.config.default_per_page, sort_by: :updated_desc))
+ end
+ end
+ end
+
+ describe 'Find branches' do
+ it 'shows filtered branches', :js do
visit project_branches_path(project)
+ fill_in 'branch-search', with: 'fix'
+ find('#branch-search').native.send_keys(:enter)
+
+ expect(page).to have_content('fix')
+ expect(find('.all-branches')).to have_selector('li', count: 1)
+ end
+ end
+
+ describe 'Delete unprotected branch on Overview' do
+ it 'removes branch after confirmation', :js do
+ visit project_branches_filtered_path(project, state: 'all')
+
+ expect(all('.all-branches').last).to have_selector('li', count: 20)
+ accept_confirm { find('.js-branch-add-pdf-text-binary .btn-remove').click }
+
+ expect(all('.all-branches').last).to have_selector('li', count: 19)
+ end
+ end
+
+ describe 'All branches page' do
+ it 'shows all the branches sorted by last updated by default' do
+ visit project_branches_filtered_path(project, state: 'all')
+
expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :updated_desc))
end
it 'sorts the branches by name' do
- visit project_branches_path(project)
+ visit project_branches_filtered_path(project, state: 'all')
click_button "Last updated" # Open sorting dropdown
click_link "Name"
@@ -28,7 +122,7 @@ describe 'Branches' do
end
it 'sorts the branches by oldest updated' do
- visit project_branches_path(project)
+ visit project_branches_filtered_path(project, state: 'all')
click_button "Last updated" # Open sorting dropdown
click_link "Oldest updated"
@@ -41,13 +135,13 @@ describe 'Branches' do
%w(one two three four five).each { |ref| repository.add_branch(user, ref, 'master') }
- expect { visit project_branches_path(project) }.not_to exceed_query_limit(control_count)
+ expect { visit project_branches_filtered_path(project, state: 'all') }.not_to exceed_query_limit(control_count)
end
end
- describe 'Find branches' do
+ describe 'Find branches on All branches' do
it 'shows filtered branches', :js do
- visit project_branches_path(project)
+ visit project_branches_filtered_path(project, state: 'all')
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
@@ -57,9 +151,9 @@ describe 'Branches' do
end
end
- describe 'Delete unprotected branch' do
+ describe 'Delete unprotected branch on All branches' do
it 'removes branch after confirmation', :js do
- visit project_branches_path(project)
+ visit project_branches_filtered_path(project, state: 'all')
fill_in 'branch-search', with: 'fix'
@@ -73,6 +167,19 @@ describe 'Branches' do
expect(find('.all-branches')).to have_selector('li', count: 0)
end
end
+
+ context 'on project with 0 branch' do
+ let(:project) { create(:project, :public, :empty_repo) }
+ let(:repository) { project.repository }
+
+ describe '0 branches on Overview' do
+ it 'shows warning' do
+ visit project_branches_path(project)
+
+ expect(page).not_to have_selector('.all-branches')
+ end
+ end
+ end
end
context 'logged in as master' do
@@ -83,7 +190,7 @@ describe 'Branches' do
describe 'Initial branches page' do
it 'shows description for admin' do
- visit project_branches_path(project)
+ visit project_branches_filtered_path(project, state: 'all')
expect(page).to have_content("Protected branches can be managed in project settings")
end
@@ -102,12 +209,18 @@ describe 'Branches' do
end
end
- def sorted_branches(repository, count:, sort_by:)
+ def sorted_branches(repository, count:, sort_by:, state: nil)
+ branches = repository.branches_sorted_by(sort_by)
+ branches = branches.select { |b| state == 'active' ? b.active? : b.stale? } if state
sorted_branches =
- repository.branches_sorted_by(sort_by).first(count).map do |branch|
+ branches.first(count).map do |branch|
Regexp.escape(branch.name)
end
Regexp.new(sorted_branches.join('.*'))
end
+
+ def create_file(message: 'message', branch_name:)
+ repository.create_file(user, generate(:branch), 'content', message: message, branch_name: branch_name)
+ end
end
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index 64e600144e0..b233af83eec 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -234,7 +234,7 @@ feature 'Environment' do
end
scenario 'user deletes the branch with running environment' do
- visit project_branches_path(project, search: 'feature')
+ 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 }
diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb
index d575596937d..1f4eec0a317 100644
--- a/spec/features/projects/members/master_manages_access_requests_spec.rb
+++ b/spec/features/projects/members/master_manages_access_requests_spec.rb
@@ -25,7 +25,7 @@ feature 'Projects > Members > Master manages access requests' do
perform_enqueued_jobs { click_on 'Grant access' }
expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
- expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{project.name_with_namespace} project was granted"
+ expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{project.full_name} project was granted"
end
scenario 'master can deny access' do
@@ -36,7 +36,7 @@ feature 'Projects > Members > Master manages access requests' do
perform_enqueued_jobs { click_on 'Deny access' }
expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
- expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{project.name_with_namespace} project was denied"
+ expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{project.full_name} project was denied"
end
def expect_visible_access_request(project, user)
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
index 4eb36156812..672d5daa3d8 100644
--- a/spec/features/projects/members/user_requests_access_spec.rb
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -21,7 +21,7 @@ feature 'Projects > Members > User requests access', :js do
perform_enqueued_jobs { click_link 'Request Access' }
expect(ActionMailer::Base.deliveries.last.to).to eq [master.notification_email]
- expect(ActionMailer::Base.deliveries.last.subject).to eq "Request to join the #{project.name_with_namespace} project"
+ expect(ActionMailer::Base.deliveries.last.subject).to eq "Request to join the #{project.full_name} project"
expect(project.requesters.exists?(user_id: user)).to be_truthy
expect(page).to have_content 'Your request for access has been queued for review.'
diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb
index 85d518c0cc3..40689964b91 100644
--- a/spec/features/projects/merge_request_button_spec.rb
+++ b/spec/features/projects/merge_request_button_spec.rb
@@ -81,8 +81,8 @@ feature 'Merge Request button' do
context 'on branches page' do
it_behaves_like 'Merge request button only shown when allowed' do
let(:label) { 'Merge request' }
- let(:url) { project_branches_path(project, search: 'feature') }
- let(:fork_url) { project_branches_path(forked_project, search: 'feature') }
+ let(:url) { project_branches_filtered_path(project, state: 'all', search: 'feature') }
+ let(:fork_url) { project_branches_filtered_path(forked_project, state: 'all', search: 'feature') }
end
end
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index b5104747d00..a5954fec54b 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -142,7 +142,7 @@ feature 'New project' do
context 'from git repository url, "Repo by URL"' do
before do
- first('.import_git').click
+ first('.js-import-git-toggle-button').click
end
it 'does not autocomplete sensitive git repo URL' do
@@ -173,11 +173,11 @@ feature 'New project' do
context 'from GitHub' do
before do
- first('.import_github').click
+ first('.js-import-github').click
end
it 'shows import instructions' do
- expect(page).to have_content('Import Projects from GitHub')
+ expect(page).to have_content('Import repositories from GitHub')
expect(current_path).to eq new_import_github_path
end
end
diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb
index 2a0d235ef04..233d2e67b9d 100644
--- a/spec/features/projects/pages_spec.rb
+++ b/spec/features/projects/pages_spec.rb
@@ -258,7 +258,7 @@ feature 'Pages' do
end
let(:ci_build) do
- build(
+ create(
:ci_build,
project: project,
pipeline: pipeline,
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 3a8e7c05cc4..33ad59abfdf 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -86,7 +86,22 @@ describe 'Pipelines', :js do
it 'updates content when tab is clicked' do
page.find('.js-pipelines-tab-pending').click
wait_for_requests
- expect(page).to have_content('No pipelines to show.')
+ expect(page).to have_content('There are currently no pending pipelines.')
+ end
+ end
+
+ context 'navigation links' do
+ before do
+ visit project_pipelines_path(project)
+ wait_for_requests
+ end
+
+ it 'renders run pipeline link' do
+ expect(page).to have_link('Run Pipeline')
+ end
+
+ it 'renders ci lint link' do
+ expect(page).to have_link('CI Lint')
end
end
@@ -542,7 +557,7 @@ describe 'Pipelines', :js do
end
it 'has a clear caches button' do
- expect(page).to have_link 'Clear runner caches'
+ expect(page).to have_button 'Clear Runner Caches'
end
describe 'user clicks the button' do
@@ -552,19 +567,33 @@ describe 'Pipelines', :js do
end
it 'increments jobs_cache_index' do
- click_link 'Clear runner caches'
+ click_button 'Clear Runner Caches'
+ wait_for_requests
expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
end
end
context 'when project does not have jobs_cache_index' do
it 'sets jobs_cache_index to 1' do
- click_link 'Clear runner caches'
+ click_button 'Clear Runner Caches'
+ wait_for_requests
expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
end
end
end
end
+
+ describe 'Empty State' do
+ let(:project) { create(:project, :repository) }
+
+ before do
+ visit project_pipelines_path(project)
+ end
+
+ it 'renders empty state' do
+ expect(page).to have_content 'Build with confidence'
+ end
+ end
end
context 'when user is not logged in' do
@@ -575,7 +604,9 @@ describe 'Pipelines', :js do
context 'when project is public' do
let(:project) { create(:project, :public, :repository) }
- it { expect(page).to have_content 'Build with confidence' }
+ context 'without pipelines' do
+ it { expect(page).to have_content 'This project is not currently set up to run pipelines.' }
+ end
end
context 'when project is private' do
diff --git a/spec/features/projects/services/disable_triggers_spec.rb b/spec/features/projects/services/disable_triggers_spec.rb
new file mode 100644
index 00000000000..1a13fe03a67
--- /dev/null
+++ b/spec/features/projects/services/disable_triggers_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe 'Disable individual triggers' do
+ let(:project) { create(:project) }
+ let(:user) { project.owner }
+ let(:checkbox_selector) { 'input[type=checkbox][id$=_events]' }
+
+ before do
+ sign_in(user)
+
+ visit(project_settings_integrations_path(project))
+
+ click_link(service_name)
+ end
+
+ context 'service has multiple supported events' do
+ let(:service_name) { 'HipChat' }
+
+ it 'shows trigger checkboxes' do
+ event_count = HipchatService.supported_events.count
+
+ expect(page).to have_content "Trigger"
+ expect(page).to have_css(checkbox_selector, count: event_count)
+ end
+ end
+
+ context 'services only has one supported event' do
+ let(:service_name) { 'Asana' }
+
+ it "doesn't show unnecessary Trigger checkboxes" do
+ expect(page).not_to have_content "Trigger"
+ expect(page).not_to have_css(checkbox_selector)
+ end
+ end
+end
diff --git a/spec/features/projects/settings/user_manages_project_members_spec.rb b/spec/features/projects/settings/user_manages_project_members_spec.rb
index 2709047b8de..0a4f57bcd21 100644
--- a/spec/features/projects/settings/user_manages_project_members_spec.rb
+++ b/spec/features/projects/settings/user_manages_project_members_spec.rb
@@ -39,7 +39,7 @@ describe 'User manages project members' do
click_link('Import')
end
- select(project2.name_with_namespace, from: 'source_project_id')
+ select(project2.full_name, from: 'source_project_id')
click_button('Import')
project_member = project.project_members.find_by(user_id: user_mike.id)
diff --git a/spec/features/projects/user_creates_files_spec.rb b/spec/features/projects/user_creates_files_spec.rb
index 7a935dd2477..8993533676b 100644
--- a/spec/features/projects/user_creates_files_spec.rb
+++ b/spec/features/projects/user_creates_files_spec.rb
@@ -133,13 +133,20 @@ describe 'User creates files' do
before do
project2.add_reporter(user)
visit(project2_tree_path_root_ref)
- end
- it 'creates and commit new file in forked project', :js do
find('.add-to-tree').click
click_link('New file')
+ end
+
+ it 'shows a message saying the file will be committed in a fork' do
+ message = "A new branch will be created in your fork and a new merge request will be started."
+ expect(page).to have_content(message)
+ end
+
+ it 'creates and commit new file in forked project', :js do
expect(page).to have_selector('.file-editor')
+ expect(page).to have_content
find('#editor')
execute_script("ace.edit('editor').setValue('*.rbca')")
diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb
index 77212fb105b..9e089c5a6cb 100644
--- a/spec/features/search/user_searches_for_code_spec.rb
+++ b/spec/features/search/user_searches_for_code_spec.rb
@@ -35,7 +35,7 @@ describe 'User searches for code' do
find('.js-search-project-dropdown').click
page.within('.project-filter') do
- click_link(project.name_with_namespace)
+ click_link(project.full_name)
end
fill_in('dashboard_search', with: 'rspec')
diff --git a/spec/features/search/user_searches_for_issues_spec.rb b/spec/features/search/user_searches_for_issues_spec.rb
index ef9553f2a91..d6120ff8517 100644
--- a/spec/features/search/user_searches_for_issues_spec.rb
+++ b/spec/features/search/user_searches_for_issues_spec.rb
@@ -34,7 +34,7 @@ describe 'User searches for issues', :js do
find('.js-search-project-dropdown').click
page.within('.project-filter') do
- click_link(project.name_with_namespace)
+ click_link(project.full_name)
end
fill_in('dashboard_search', with: issue1.title)
diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb
index 3b6739aecbd..68e2f7a857d 100644
--- a/spec/features/search/user_searches_for_merge_requests_spec.rb
+++ b/spec/features/search/user_searches_for_merge_requests_spec.rb
@@ -33,7 +33,7 @@ describe 'User searches for merge requests', :js do
find('.js-search-project-dropdown').click
page.within('.project-filter') do
- click_link(project.name_with_namespace)
+ click_link(project.full_name)
end
fill_in('dashboard_search', with: merge_request1.title)
diff --git a/spec/features/search/user_searches_for_milestones_spec.rb b/spec/features/search/user_searches_for_milestones_spec.rb
index 6e197aee498..fc6cd81eb68 100644
--- a/spec/features/search/user_searches_for_milestones_spec.rb
+++ b/spec/features/search/user_searches_for_milestones_spec.rb
@@ -33,7 +33,7 @@ describe 'User searches for milestones', :js do
find('.js-search-project-dropdown').click
page.within('.project-filter') do
- click_link(project.name_with_namespace)
+ click_link(project.full_name)
end
fill_in('dashboard_search', with: milestone1.title)
diff --git a/spec/features/search/user_searches_for_wiki_pages_spec.rb b/spec/features/search/user_searches_for_wiki_pages_spec.rb
index 00af625dc86..7934779058f 100644
--- a/spec/features/search/user_searches_for_wiki_pages_spec.rb
+++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb
@@ -18,7 +18,7 @@ describe 'User searches for wiki pages', :js do
find('.js-search-project-dropdown').click
page.within('.project-filter') do
- click_link(project.name_with_namespace)
+ click_link(project.full_name)
end
fill_in('dashboard_search', with: 'content')
diff --git a/spec/features/search/user_uses_search_filters_spec.rb b/spec/features/search/user_uses_search_filters_spec.rb
index aa883c964d2..66afe163447 100644
--- a/spec/features/search/user_uses_search_filters_spec.rb
+++ b/spec/features/search/user_uses_search_filters_spec.rb
@@ -31,7 +31,7 @@ describe 'User uses search filters', :js do
wait_for_requests
- expect(page).to have_link(group_project.name_with_namespace)
+ expect(page).to have_link(group_project.full_name)
end
end
end
@@ -43,10 +43,10 @@ describe 'User uses search filters', :js do
wait_for_requests
- click_link(project.name_with_namespace)
+ click_link(project.full_name)
end
- expect(find('.js-search-project-dropdown')).to have_content(project.name_with_namespace)
+ expect(find('.js-search-project-dropdown')).to have_content(project.full_name)
end
end
end
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 6ef235cf870..bc75dc5d19b 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -145,6 +145,18 @@ feature 'Login' do
expect { enter_code(codes.sample) }
.to change { user.reload.otp_backup_codes.size }.by(-1)
end
+
+ it 'invalidates backup codes twice in a row' do
+ random_code = codes.delete(codes.sample)
+ expect { enter_code(random_code) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+
+ gitlab_sign_out
+ gitlab_sign_in(user)
+
+ expect { enter_code(codes.sample) }
+ .to change { user.reload.otp_backup_codes.size }.by(-1)
+ end
end
context 'with invalid code' do
diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb
index 90eb0fe21e4..9747b9402a7 100644
--- a/spec/finders/todos_finder_spec.rb
+++ b/spec/finders/todos_finder_spec.rb
@@ -2,12 +2,13 @@ require 'spec_helper'
describe TodosFinder do
describe '#execute' do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:finder) { described_class }
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
+ let(:finder) { described_class }
before do
- project.add_developer(user)
+ group.add_developer(user)
end
describe '#sort' do
@@ -34,17 +35,20 @@ describe TodosFinder do
end
it "sorts by priority" do
+ project_2 = create(:project)
+
label_1 = create(:label, title: 'label_1', project: project, priority: 1)
label_2 = create(:label, title: 'label_2', project: project, priority: 2)
label_3 = create(:label, title: 'label_3', project: project, priority: 3)
+ label_1_2 = create(:label, title: 'label_1', project: project_2, priority: 1)
issue_1 = create(:issue, title: 'issue_1', project: project)
issue_2 = create(:issue, title: 'issue_2', project: project)
issue_3 = create(:issue, title: 'issue_3', project: project)
issue_4 = create(:issue, title: 'issue_4', project: project)
- merge_request_1 = create(:merge_request, source_project: project)
+ merge_request_1 = create(:merge_request, source_project: project_2)
- merge_request_1.labels << label_1
+ merge_request_1.labels << label_1_2
# Covers the case where Todo has more than one label
issue_3.labels << label_1
@@ -57,15 +61,14 @@ describe TodosFinder do
todo_2 = create(:todo, user: user, project: project, target: issue_2)
todo_3 = create(:todo, user: user, project: project, target: issue_3, created_at: 2.hours.ago)
todo_4 = create(:todo, user: user, project: project, target: issue_1)
- todo_5 = create(:todo, user: user, project: project, target: merge_request_1, created_at: 1.hour.ago)
+ todo_5 = create(:todo, user: user, project: project_2, target: merge_request_1, created_at: 1.hour.ago)
+
+ project_2.add_developer(user)
todos = finder.new(user, { sort: 'priority' }).execute
- expect(todos.first).to eq(todo_3)
- expect(todos.second).to eq(todo_5)
- expect(todos.third).to eq(todo_4)
- expect(todos.fourth).to eq(todo_2)
- expect(todos.fifth).to eq(todo_1)
+ puts todos.to_sql
+ expect(todos).to eq([todo_3, todo_5, todo_4, todo_2, todo_1])
end
end
end
diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json
index f1199468d53..46031961cca 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_basic.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json
@@ -12,7 +12,8 @@
"rebase_in_progress": { "type": "boolean" },
"assignee_id": { "type": ["integer", "null"] },
"subscribed": { "type": ["boolean", "null"] },
- "participants": { "type": "array" }
+ "participants": { "type": "array" },
+ "allow_maintainer_to_push": { "type": "boolean"}
},
"additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index cfbeec58a45..a622bf88b13 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -30,6 +30,7 @@
"source_project_id": { "type": "integer" },
"target_branch": { "type": "string" },
"target_project_id": { "type": "integer" },
+ "allow_maintainer_to_push": { "type": "boolean"},
"metrics": {
"oneOf": [
{ "type": "null" },
diff --git a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
index e86176e5316..0dc2eabec5d 100644
--- a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
+++ b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
@@ -80,7 +80,8 @@
"total_time_spent": { "type": "integer" },
"human_time_estimate": { "type": ["string", "null"] },
"human_total_time_spent": { "type": ["string", "null"] }
- }
+ },
+ "allow_maintainer_to_push": { "type": ["boolean", "null"] }
},
"required": [
"id", "iid", "project_id", "title", "description",
diff --git a/spec/fixtures/api/schemas/public_api/v4/notes.json b/spec/fixtures/api/schemas/public_api/v4/notes.json
index 6525f7c2c80..4c4ca3b582f 100644
--- a/spec/fixtures/api/schemas/public_api/v4/notes.json
+++ b/spec/fixtures/api/schemas/public_api/v4/notes.json
@@ -4,6 +4,7 @@
"type": "object",
"properties" : {
"id": { "type": "integer" },
+ "type": { "type": ["string", "null"] },
"body": { "type": "string" },
"attachment": { "type": ["string", "null"] },
"author": {
diff --git a/spec/fixtures/api/schemas/public_api/v4/project/export_status.json b/spec/fixtures/api/schemas/public_api/v4/project/export_status.json
new file mode 100644
index 00000000000..d24a6f93f4b
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/project/export_status.json
@@ -0,0 +1,17 @@
+{
+ "type": "object",
+ "allOf": [
+ { "$ref": "identity.json" },
+ {
+ "required": [
+ "export_status"
+ ],
+ "properties": {
+ "export_status": {
+ "type": "string",
+ "enum": ["none", "started", "finished"]
+ }
+ }
+ }
+ ]
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/project/identity.json b/spec/fixtures/api/schemas/public_api/v4/project/identity.json
new file mode 100644
index 00000000000..e35ab023d44
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/project/identity.json
@@ -0,0 +1,21 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "description",
+ "name",
+ "name_with_namespace",
+ "path",
+ "path_with_namespace",
+ "created_at"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "description": { "type": ["string", "null"] },
+ "name": { "type": "string" },
+ "name_with_namespace": { "type": "string" },
+ "path": { "type": "string" },
+ "path_with_namespace": { "type": "string" },
+ "created_at": { "type": "date" }
+ }
+}
diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb
index a3c5ab99c87..b22947911b9 100644
--- a/spec/helpers/boards_helper_spec.rb
+++ b/spec/helpers/boards_helper_spec.rb
@@ -1,6 +1,34 @@
require 'spec_helper'
describe BoardsHelper do
+ describe '#build_issue_link_base' do
+ context 'project board' do
+ it 'returns correct path for project board' do
+ @project = create(:project)
+ @board = create(:board, project: @project)
+
+ expect(build_issue_link_base).to eq("/#{@project.namespace.path}/#{@project.path}/issues")
+ end
+ end
+
+ context 'group board' do
+ let(:base_group) { create(:group, path: 'base') }
+
+ it 'returns correct path for base group' do
+ @board = create(:board, group: base_group)
+
+ expect(build_issue_link_base).to eq('/base/:project_path/issues')
+ end
+
+ it 'returns correct path for subgroup' do
+ subgroup = create(:group, parent: base_group, path: 'sub')
+ @board = create(:board, group: subgroup)
+
+ expect(build_issue_link_base).to eq('/base/sub/:project_path/issues')
+ end
+ end
+ end
+
describe '#board_data' do
let(:user) { create(:user) }
let(:project) { create(:project) }
diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb
index 45ffbeb27a4..4590904c93d 100644
--- a/spec/helpers/members_helper_spec.rb
+++ b/spec/helpers/members_helper_spec.rb
@@ -12,10 +12,10 @@ describe MembersHelper do
let(:group_member_invite) { build(:group_member, group: group).tap { |m| m.generate_invite_token! } }
let(:group_member_request) { group.request_access(requester) }
- it { expect(remove_member_message(project_member)).to eq "Are you sure you want to remove #{project_member.user.name} from the #{project.name_with_namespace} project?" }
- it { expect(remove_member_message(project_member_invite)).to eq "Are you sure you want to revoke the invitation for #{project_member_invite.invite_email} to join the #{project.name_with_namespace} project?" }
- it { expect(remove_member_message(project_member_request)).to eq "Are you sure you want to deny #{requester.name}'s request to join the #{project.name_with_namespace} project?" }
- it { expect(remove_member_message(project_member_request, user: requester)).to eq "Are you sure you want to withdraw your access request for the #{project.name_with_namespace} project?" }
+ it { expect(remove_member_message(project_member)).to eq "Are you sure you want to remove #{project_member.user.name} from the #{project.full_name} project?" }
+ it { expect(remove_member_message(project_member_invite)).to eq "Are you sure you want to revoke the invitation for #{project_member_invite.invite_email} to join the #{project.full_name} project?" }
+ it { expect(remove_member_message(project_member_request)).to eq "Are you sure you want to deny #{requester.name}'s request to join the #{project.full_name} project?" }
+ it { expect(remove_member_message(project_member_request, user: requester)).to eq "Are you sure you want to withdraw your access request for the #{project.full_name} project?" }
it { expect(remove_member_message(group_member)).to eq "Are you sure you want to remove #{group_member.user.name} from the #{group.name} group?" }
it { expect(remove_member_message(group_member_invite)).to eq "Are you sure you want to revoke the invitation for #{group_member_invite.invite_email} to join the #{group.name} group?" }
it { expect(remove_member_message(group_member_request)).to eq "Are you sure you want to deny #{requester.name}'s request to join the #{group.name} group?" }
@@ -42,7 +42,7 @@ describe MembersHelper do
let(:group) { build_stubbed(:group) }
let(:user) { build_stubbed(:user) }
- it { expect(leave_confirmation_message(project)).to eq "Are you sure you want to leave the \"#{project.name_with_namespace}\" project?" }
+ it { expect(leave_confirmation_message(project)).to eq "Are you sure you want to leave the \"#{project.full_name}\" project?" }
it { expect(leave_confirmation_message(group)).to eq "Are you sure you want to leave the \"#{group.name}\" group?" }
end
end
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index f55163c26e9..63806ef91f3 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -26,8 +26,8 @@ describe TodosHelper do
expected_results = [
{ 'id' => '', 'text' => 'Any Project' },
- { 'id' => projects.second.id, 'text' => projects.second.name_with_namespace },
- { 'id' => projects.first.id, 'text' => projects.first.name_with_namespace }
+ { 'id' => projects.second.id, 'text' => projects.second.full_name },
+ { 'id' => projects.first.id, 'text' => projects.first.full_name }
]
expect(JSON.parse(helper.todo_projects_options)).to match_array(expected_results)
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index d3b1be599dd..ccac6e29447 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -62,4 +62,13 @@ describe TreeHelper do
end
end
end
+
+ describe '#commit_in_single_accessible_branch' do
+ it 'escapes HTML from the branch name' do
+ helper.instance_variable_set(:@branch_name, "<script>alert('escape me!');</script>")
+ escaped_branch_name = '&lt;script&gt;alert(&#39;escape me!&#39;);&lt;/script&gt;'
+
+ expect(helper.commit_in_single_accessible_branch).to include(escaped_branch_name)
+ end
+ end
end
diff --git a/spec/javascripts/api_spec.js b/spec/javascripts/api_spec.js
index cf3a76d0d2e..5477581c1b9 100644
--- a/spec/javascripts/api_spec.js
+++ b/spec/javascripts/api_spec.js
@@ -137,6 +137,27 @@ describe('Api', () => {
done();
});
});
+
+ it('creates a group label', (done) => {
+ const namespace = 'group/subgroup';
+ const labelData = { some: 'data' };
+ const expectedUrl = `${dummyUrlRoot}/groups/${namespace}/-/labels`;
+ const expectedData = {
+ label: labelData,
+ };
+ mock.onPost(expectedUrl).reply((config) => {
+ expect(config.data).toBe(JSON.stringify(expectedData));
+
+ return [200, {
+ name: 'test',
+ }];
+ });
+
+ Api.newLabel(namespace, undefined, labelData, (response) => {
+ expect(response.name).toBe('test');
+ done();
+ });
+ });
});
describe('groupProjects', () => {
diff --git a/spec/javascripts/boards/board_card_spec.js b/spec/javascripts/boards/board_card_spec.js
index 80a598e63bd..13d607a06d2 100644
--- a/spec/javascripts/boards/board_card_spec.js
+++ b/spec/javascripts/boards/board_card_spec.js
@@ -9,8 +9,8 @@ import axios from '~/lib/utils/axios_utils';
import '~/boards/models/assignee';
import eventHub from '~/boards/eventhub';
+import '~/vue_shared/models/label';
import '~/boards/models/list';
-import '~/boards/models/label';
import '~/boards/stores/boards_store';
import boardCard from '~/boards/components/board_card.vue';
import { listObj, boardsMockInterceptor, mockBoardService } from './mock_data';
diff --git a/spec/javascripts/boards/boards_store_spec.js b/spec/javascripts/boards/boards_store_spec.js
index 8411f4dd8a6..0cf9e4c9ba1 100644
--- a/spec/javascripts/boards/boards_store_spec.js
+++ b/spec/javascripts/boards/boards_store_spec.js
@@ -7,8 +7,8 @@ import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import Cookies from 'js-cookie';
+import '~/vue_shared/models/label';
import '~/boards/models/issue';
-import '~/boards/models/label';
import '~/boards/models/list';
import '~/boards/models/assignee';
import '~/boards/services/board_service';
diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js
index 278155c585e..37088a6421c 100644
--- a/spec/javascripts/boards/issue_card_spec.js
+++ b/spec/javascripts/boards/issue_card_spec.js
@@ -4,8 +4,8 @@
import Vue from 'vue';
+import '~/vue_shared/models/label';
import '~/boards/models/issue';
-import '~/boards/models/label';
import '~/boards/models/list';
import '~/boards/models/assignee';
import '~/boards/stores/boards_store';
diff --git a/spec/javascripts/boards/issue_spec.js b/spec/javascripts/boards/issue_spec.js
index dbbe14fe3e0..4a11131b55c 100644
--- a/spec/javascripts/boards/issue_spec.js
+++ b/spec/javascripts/boards/issue_spec.js
@@ -3,8 +3,8 @@
/* global ListIssue */
import Vue from 'vue';
+import '~/vue_shared/models/label';
import '~/boards/models/issue';
-import '~/boards/models/label';
import '~/boards/models/list';
import '~/boards/models/assignee';
import '~/boards/services/board_service';
diff --git a/spec/javascripts/boards/list_spec.js b/spec/javascripts/boards/list_spec.js
index 34964b20b05..d9a1d692949 100644
--- a/spec/javascripts/boards/list_spec.js
+++ b/spec/javascripts/boards/list_spec.js
@@ -6,8 +6,8 @@
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import _ from 'underscore';
+import '~/vue_shared/models/label';
import '~/boards/models/issue';
-import '~/boards/models/label';
import '~/boards/models/list';
import '~/boards/models/assignee';
import '~/boards/services/board_service';
diff --git a/spec/javascripts/boards/modal_store_spec.js b/spec/javascripts/boards/modal_store_spec.js
index 7eecb58a4c3..e9d77f035e3 100644
--- a/spec/javascripts/boards/modal_store_spec.js
+++ b/spec/javascripts/boards/modal_store_spec.js
@@ -1,7 +1,7 @@
/* global ListIssue */
+import '~/vue_shared/models/label';
import '~/boards/models/issue';
-import '~/boards/models/label';
import '~/boards/models/list';
import '~/boards/models/assignee';
import '~/boards/stores/modal_store';
diff --git a/spec/javascripts/environments/environments_app_spec.js b/spec/javascripts/environments/environments_app_spec.js
index 5bb37304372..e4c3bf2bef1 100644
--- a/spec/javascripts/environments/environments_app_spec.js
+++ b/spec/javascripts/environments/environments_app_spec.js
@@ -61,6 +61,7 @@ describe('Environment', () => {
});
describe('with paginated environments', () => {
+ let backupInterceptors;
const environmentsResponseInterceptor = (request, next) => {
next((response) => {
response.headers.set('X-nExt-pAge', '2');
@@ -84,16 +85,16 @@ describe('Environment', () => {
};
beforeEach(() => {
- Vue.http.interceptors.push(environmentsResponseInterceptor);
- Vue.http.interceptors.push(headersInterceptor);
+ backupInterceptors = Vue.http.interceptors;
+ Vue.http.interceptors = [
+ environmentsResponseInterceptor,
+ headersInterceptor,
+ ];
component = mountComponent(EnvironmentsComponent, mockData);
});
afterEach(() => {
- Vue.http.interceptors = _.without(
- Vue.http.interceptors, environmentsResponseInterceptor,
- );
- Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
+ Vue.http.interceptors = backupInterceptors;
});
it('should render a table with environments', (done) => {
diff --git a/spec/javascripts/fixtures/environments.rb b/spec/javascripts/fixtures/environments.rb
deleted file mode 100644
index d2457d75419..00000000000
--- a/spec/javascripts/fixtures/environments.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require 'spec_helper'
-
-describe Projects::EnvironmentsController, '(JavaScript fixtures)', type: :controller do
- include JavaScriptFixturesHelpers
-
- let(:admin) { create(:admin) }
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
- let(:project) { create(:project_empty_repo, namespace: namespace, path: 'environments-project') }
- let(:environment) { create(:environment, name: 'production', project: project) }
-
- render_views
-
- before(:all) do
- clean_frontend_fixtures('environments/metrics')
- end
-
- before do
- sign_in(admin)
- end
-
- it 'environments/metrics/metrics.html.raw' do |example|
- get :metrics,
- namespace_id: project.namespace,
- project_id: project,
- id: environment.id
-
- expect(response).to be_success
- store_frontend_fixture(response, example.description)
- end
-end
diff --git a/spec/javascripts/groups/components/app_spec.js b/spec/javascripts/groups/components/app_spec.js
index 3adc29262f3..46c7b9f54f2 100644
--- a/spec/javascripts/groups/components/app_spec.js
+++ b/spec/javascripts/groups/components/app_spec.js
@@ -129,7 +129,7 @@ describe('AppComponent', () => {
vm.fetchGroups({});
setTimeout(() => {
- expect(vm.isLoading).toBeFalsy();
+ expect(vm.isLoading).toBe(false);
expect($.scrollTo).toHaveBeenCalledWith(0);
expect(window.Flash).toHaveBeenCalledWith('An error occurred. Please try again.');
done();
@@ -144,10 +144,10 @@ describe('AppComponent', () => {
spyOn(vm, 'updateGroups').and.callThrough();
vm.fetchAllGroups();
- expect(vm.isLoading).toBeTruthy();
+ expect(vm.isLoading).toBe(true);
expect(vm.fetchGroups).toHaveBeenCalled();
setTimeout(() => {
- expect(vm.isLoading).toBeFalsy();
+ expect(vm.isLoading).toBe(false);
expect(vm.updateGroups).toHaveBeenCalled();
done();
}, 0);
@@ -181,7 +181,7 @@ describe('AppComponent', () => {
spyOn($, 'scrollTo');
vm.fetchPage(2, null, null, true);
- expect(vm.isLoading).toBeTruthy();
+ expect(vm.isLoading).toBe(true);
expect(vm.fetchGroups).toHaveBeenCalledWith({
page: 2,
filterGroupsBy: null,
@@ -190,7 +190,7 @@ describe('AppComponent', () => {
archived: true,
});
setTimeout(() => {
- expect(vm.isLoading).toBeFalsy();
+ expect(vm.isLoading).toBe(false);
expect($.scrollTo).toHaveBeenCalledWith(0);
expect(utils.mergeUrlParams).toHaveBeenCalledWith({ page: 2 }, jasmine.any(String));
expect(window.history.replaceState).toHaveBeenCalledWith({
@@ -216,7 +216,7 @@ describe('AppComponent', () => {
spyOn(vm.store, 'setGroupChildren');
vm.toggleChildren(groupItem);
- expect(groupItem.isChildrenLoading).toBeTruthy();
+ expect(groupItem.isChildrenLoading).toBe(true);
expect(vm.fetchGroups).toHaveBeenCalledWith({
parentId: groupItem.id,
});
@@ -232,7 +232,7 @@ describe('AppComponent', () => {
vm.toggleChildren(groupItem);
expect(vm.fetchGroups).not.toHaveBeenCalled();
- expect(groupItem.isOpen).toBeTruthy();
+ expect(groupItem.isOpen).toBe(true);
});
it('should collapse group if it is already expanded', () => {
@@ -241,16 +241,16 @@ describe('AppComponent', () => {
vm.toggleChildren(groupItem);
expect(vm.fetchGroups).not.toHaveBeenCalled();
- expect(groupItem.isOpen).toBeFalsy();
+ expect(groupItem.isOpen).toBe(false);
});
it('should set `isChildrenLoading` back to `false` if load request fails', (done) => {
spyOn(vm, 'fetchGroups').and.returnValue(returnServicePromise({}, true));
vm.toggleChildren(groupItem);
- expect(groupItem.isChildrenLoading).toBeTruthy();
+ expect(groupItem.isChildrenLoading).toBe(true);
setTimeout(() => {
- expect(groupItem.isChildrenLoading).toBeFalsy();
+ expect(groupItem.isChildrenLoading).toBe(false);
done();
}, 0);
});
@@ -268,10 +268,10 @@ describe('AppComponent', () => {
it('updates props which show modal confirmation dialog', () => {
const group = Object.assign({}, mockParentGroupItem);
- expect(vm.updateModal).toBeFalsy();
+ expect(vm.showModal).toBe(false);
expect(vm.groupLeaveConfirmationMessage).toBe('');
vm.showLeaveGroupModal(group, mockParentGroupItem);
- expect(vm.updateModal).toBeTruthy();
+ expect(vm.showModal).toBe(true);
expect(vm.groupLeaveConfirmationMessage).toBe(`Are you sure you want to leave the "${group.fullName}" group?`);
});
});
@@ -280,9 +280,9 @@ describe('AppComponent', () => {
it('hides modal confirmation which is shown before leaving the group', () => {
const group = Object.assign({}, mockParentGroupItem);
vm.showLeaveGroupModal(group, mockParentGroupItem);
- expect(vm.updateModal).toBeTruthy();
+ expect(vm.showModal).toBe(true);
vm.hideLeaveGroupModal();
- expect(vm.updateModal).toBeFalsy();
+ expect(vm.showModal).toBe(false);
});
});
@@ -307,8 +307,8 @@ describe('AppComponent', () => {
spyOn($, 'scrollTo');
vm.leaveGroup();
- expect(vm.updateModal).toBeFalsy();
- expect(vm.targetGroup.isBeingRemoved).toBeTruthy();
+ expect(vm.showModal).toBe(false);
+ expect(vm.targetGroup.isBeingRemoved).toBe(true);
expect(vm.service.leaveGroup).toHaveBeenCalledWith(vm.targetGroup.leavePath);
setTimeout(() => {
expect($.scrollTo).toHaveBeenCalledWith(0);
@@ -325,12 +325,12 @@ describe('AppComponent', () => {
spyOn(window, 'Flash');
vm.leaveGroup();
- expect(vm.targetGroup.isBeingRemoved).toBeTruthy();
+ expect(vm.targetGroup.isBeingRemoved).toBe(true);
expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath);
setTimeout(() => {
expect(vm.store.removeGroup).not.toHaveBeenCalled();
expect(window.Flash).toHaveBeenCalledWith(message);
- expect(vm.targetGroup.isBeingRemoved).toBeFalsy();
+ expect(vm.targetGroup.isBeingRemoved).toBe(false);
done();
}, 0);
});
@@ -342,12 +342,12 @@ describe('AppComponent', () => {
spyOn(window, 'Flash');
vm.leaveGroup(childGroupItem, groupItem);
- expect(vm.targetGroup.isBeingRemoved).toBeTruthy();
+ expect(vm.targetGroup.isBeingRemoved).toBe(true);
expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath);
setTimeout(() => {
expect(vm.store.removeGroup).not.toHaveBeenCalled();
expect(window.Flash).toHaveBeenCalledWith(message);
- expect(vm.targetGroup.isBeingRemoved).toBeFalsy();
+ expect(vm.targetGroup.isBeingRemoved).toBe(false);
done();
}, 0);
});
@@ -379,10 +379,10 @@ describe('AppComponent', () => {
it('should set `isSearchEmpty` prop based on groups count', () => {
vm.updateGroups(mockGroups);
- expect(vm.isSearchEmpty).toBeFalsy();
+ expect(vm.isSearchEmpty).toBe(false);
vm.updateGroups([]);
- expect(vm.isSearchEmpty).toBeTruthy();
+ expect(vm.isSearchEmpty).toBe(true);
});
});
});
@@ -473,13 +473,16 @@ describe('AppComponent', () => {
});
});
- it('renders modal confirmation dialog', () => {
+ it('renders modal confirmation dialog', (done) => {
vm.groupLeaveConfirmationMessage = 'Are you sure you want to leave the "foo" group?';
- vm.updateModal = true;
- const modalDialogEl = vm.$el.querySelector('.modal');
- expect(modalDialogEl).not.toBe(null);
- expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?');
- expect(modalDialogEl.querySelector('.btn.btn-warning').innerText.trim()).toBe('Leave');
+ vm.showModal = true;
+ Vue.nextTick(() => {
+ const modalDialogEl = vm.$el.querySelector('.modal');
+ expect(modalDialogEl).not.toBe(null);
+ expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?');
+ expect(modalDialogEl.querySelector('.btn.btn-warning').innerText.trim()).toBe('Leave');
+ done();
+ });
});
});
});
diff --git a/spec/javascripts/importer_status_spec.js b/spec/javascripts/importer_status_spec.js
index 71a2cd51f63..0575d02886d 100644
--- a/spec/javascripts/importer_status_spec.js
+++ b/spec/javascripts/importer_status_spec.js
@@ -29,7 +29,10 @@ describe('Importer Status', () => {
`);
spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
- instance = new ImporterStatus('', importUrl);
+ instance = new ImporterStatus({
+ jobsUrl: '',
+ importUrl,
+ });
});
it('sets table row to active after post request', (done) => {
@@ -65,7 +68,9 @@ describe('Importer Status', () => {
spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
- instance = new ImporterStatus(jobsUrl);
+ instance = new ImporterStatus({
+ jobsUrl,
+ });
});
function setupMock(importStatus) {
@@ -86,17 +91,17 @@ describe('Importer Status', () => {
it('sets the job status to done', (done) => {
setupMock('finished');
- expectJobStatus(done, 'done');
+ expectJobStatus(done, 'Done');
});
it('sets the job status to scheduled', (done) => {
setupMock('scheduled');
- expectJobStatus(done, 'scheduled');
+ expectJobStatus(done, 'Scheduled');
});
it('sets the job status to started', (done) => {
setupMock('started');
- expectJobStatus(done, 'started');
+ expectJobStatus(done, 'Started');
});
it('sets the job status to custom status', (done) => {
diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js
index eb8f6bbe50d..29b355307ef 100644
--- a/spec/javascripts/monitoring/dashboard_spec.js
+++ b/spec/javascripts/monitoring/dashboard_spec.js
@@ -5,24 +5,35 @@ import axios from '~/lib/utils/axios_utils';
import { metricsGroupsAPIResponse, mockApiEndpoint } from './mock_data';
describe('Dashboard', () => {
- const fixtureName = 'environments/metrics/metrics.html.raw';
let DashboardComponent;
- let component;
- preloadFixtures(fixtureName);
+
+ const propsData = {
+ hasMetrics: false,
+ documentationPath: '/path/to/docs',
+ settingsPath: '/path/to/settings',
+ clustersPath: '/path/to/clusters',
+ tagsPath: '/path/to/tags',
+ projectPath: '/path/to/project',
+ metricsEndpoint: mockApiEndpoint,
+ deploymentEndpoint: null,
+ emptyGettingStartedSvgPath: '/path/to/getting-started.svg',
+ emptyLoadingSvgPath: '/path/to/loading.svg',
+ emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
+ };
beforeEach(() => {
- loadFixtures(fixtureName);
+ setFixtures('<div class="prometheus-graphs"></div>');
DashboardComponent = Vue.extend(Dashboard);
});
describe('no metrics are available yet', () => {
it('shows a getting started empty state when no metrics are present', () => {
- component = new DashboardComponent({
- el: document.querySelector('#prometheus-graphs'),
+ const component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData,
});
- component.$mount();
- expect(component.$el.querySelector('#prometheus-graphs')).toBe(null);
+ expect(component.$el.querySelector('.prometheus-graphs')).toBe(null);
expect(component.state).toEqual('gettingStarted');
});
});
@@ -30,11 +41,8 @@ describe('Dashboard', () => {
describe('requests information to the server', () => {
let mock;
beforeEach(() => {
- document.querySelector('#prometheus-graphs').setAttribute('data-has-metrics', 'true');
mock = new MockAdapter(axios);
- mock.onGet(mockApiEndpoint).reply(200, {
- metricsGroupsAPIResponse,
- });
+ mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
});
afterEach(() => {
@@ -42,14 +50,43 @@ describe('Dashboard', () => {
});
it('shows up a loading state', (done) => {
- component = new DashboardComponent({
- el: document.querySelector('#prometheus-graphs'),
+ const component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData: { ...propsData, hasMetrics: true },
});
- component.$mount();
+
Vue.nextTick(() => {
expect(component.state).toEqual('loading');
done();
});
});
+
+ it('hides the legend when showLegend is false', (done) => {
+ const component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData: { ...propsData, hasMetrics: true, showLegend: false },
+ });
+
+ setTimeout(() => {
+ expect(component.showEmptyState).toEqual(false);
+ expect(component.$el.querySelector('.legend-group')).toEqual(null);
+ expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy();
+ done();
+ });
+ });
+
+ it('hides the group panels when showPanels is false', (done) => {
+ const component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData: { ...propsData, hasMetrics: true, showPanels: false },
+ });
+
+ setTimeout(() => {
+ expect(component.showEmptyState).toEqual(false);
+ expect(component.$el.querySelector('.prometheus-panel')).toEqual(null);
+ expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy();
+ done();
+ });
+ });
});
});
diff --git a/spec/javascripts/pages/labels/components/promote_label_modal_spec.js b/spec/javascripts/pages/labels/components/promote_label_modal_spec.js
new file mode 100644
index 00000000000..ba2e07f02f7
--- /dev/null
+++ b/spec/javascripts/pages/labels/components/promote_label_modal_spec.js
@@ -0,0 +1,88 @@
+import Vue from 'vue';
+import promoteLabelModal from '~/pages/projects/labels/components/promote_label_modal.vue';
+import eventHub from '~/pages/projects/labels/event_hub';
+import axios from '~/lib/utils/axios_utils';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
+
+describe('Promote label modal', () => {
+ let vm;
+ const Component = Vue.extend(promoteLabelModal);
+ const labelMockData = {
+ labelTitle: 'Documentation',
+ labelColor: '#5cb85c',
+ labelTextColor: '#ffffff',
+ url: `${gl.TEST_HOST}/dummy/promote/labels`,
+ };
+
+ describe('Modal title and description', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, labelMockData);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('contains the proper description', () => {
+ expect(vm.text).toContain('Promoting this label will make it available for all projects inside the group');
+ });
+
+ it('contains a label span with the color', () => {
+ const labelFromTitle = vm.$el.querySelector('.modal-header .label.color-label');
+
+ expect(labelFromTitle.style.backgroundColor).not.toBe(null);
+ expect(labelFromTitle.textContent).toContain(vm.labelTitle);
+ });
+ });
+
+ describe('When requesting a label promotion', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ ...labelMockData,
+ });
+ spyOn(eventHub, '$emit');
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('redirects when a label is promoted', (done) => {
+ const responseURL = `${gl.TEST_HOST}/dummy/endpoint`;
+ spyOn(axios, 'post').and.callFake((url) => {
+ expect(url).toBe(labelMockData.url);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestStarted', labelMockData.url);
+ return Promise.resolve({
+ request: {
+ responseURL,
+ },
+ });
+ });
+
+ vm.onSubmit()
+ .then(() => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestFinished', { labelUrl: labelMockData.url, successful: true });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('displays an error if promoting a label failed', (done) => {
+ const dummyError = new Error('promoting label failed');
+ dummyError.response = { status: 500 };
+ spyOn(axios, 'post').and.callFake((url) => {
+ expect(url).toBe(labelMockData.url);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestStarted', labelMockData.url);
+ return Promise.reject(dummyError);
+ });
+
+ vm.onSubmit()
+ .catch((error) => {
+ expect(error).toBe(dummyError);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteLabelModal.requestFinished', { labelUrl: labelMockData.url, successful: false });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js b/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js
new file mode 100644
index 00000000000..bf044fe8fb5
--- /dev/null
+++ b/spec/javascripts/pages/milestones/shared/components/promote_milestone_modal_spec.js
@@ -0,0 +1,83 @@
+import Vue from 'vue';
+import promoteMilestoneModal from '~/pages/milestones/shared/components/promote_milestone_modal.vue';
+import eventHub from '~/pages/milestones/shared/event_hub';
+import axios from '~/lib/utils/axios_utils';
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+describe('Promote milestone modal', () => {
+ let vm;
+ const Component = Vue.extend(promoteMilestoneModal);
+ const milestoneMockData = {
+ milestoneTitle: 'v1.0',
+ url: `${gl.TEST_HOST}/dummy/promote/milestones`,
+ };
+
+ describe('Modal title and description', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, milestoneMockData);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('contains the proper description', () => {
+ expect(vm.text).toContain('Promoting this milestone will make it available for all projects inside the group.');
+ });
+
+ it('contains the correct title', () => {
+ expect(vm.title).toEqual('Promote v1.0 to group milestone?');
+ });
+ });
+
+ describe('When requesting a milestone promotion', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ ...milestoneMockData,
+ });
+ spyOn(eventHub, '$emit');
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('redirects when a milestone is promoted', (done) => {
+ const responseURL = `${gl.TEST_HOST}/dummy/endpoint`;
+ spyOn(axios, 'post').and.callFake((url) => {
+ expect(url).toBe(milestoneMockData.url);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestStarted', milestoneMockData.url);
+ return Promise.resolve({
+ request: {
+ responseURL,
+ },
+ });
+ });
+
+ vm.onSubmit()
+ .then(() => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestFinished', { milestoneUrl: milestoneMockData.url, successful: true });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('displays an error if promoting a milestone failed', (done) => {
+ const dummyError = new Error('promoting milestone failed');
+ dummyError.response = { status: 500 };
+ spyOn(axios, 'post').and.callFake((url) => {
+ expect(url).toBe(milestoneMockData.url);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestStarted', milestoneMockData.url);
+ return Promise.reject(dummyError);
+ });
+
+ vm.onSubmit()
+ .catch((error) => {
+ expect(error).toBe(dummyError);
+ expect(eventHub.$emit).toHaveBeenCalledWith('promoteMilestoneModal.requestFinished', { milestoneUrl: milestoneMockData.url, successful: false });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/javascripts/pipelines/blank_state_spec.js b/spec/javascripts/pipelines/blank_state_spec.js
new file mode 100644
index 00000000000..b7a9b60d85c
--- /dev/null
+++ b/spec/javascripts/pipelines/blank_state_spec.js
@@ -0,0 +1,29 @@
+import Vue from 'vue';
+import component from '~/pipelines/components/blank_state.vue';
+import mountComponent from '../helpers/vue_mount_component_helper';
+
+describe('Pipelines Blank State', () => {
+ let vm;
+ let Component;
+
+ beforeEach(() => {
+ Component = Vue.extend(component);
+
+ vm = mountComponent(Component,
+ {
+ svgPath: 'foo',
+ message: 'Blank State',
+ },
+ );
+ });
+
+ it('should render svg', () => {
+ expect(vm.$el.querySelector('.svg-content img').getAttribute('src')).toEqual('foo');
+ });
+
+ it('should render message', () => {
+ expect(
+ vm.$el.querySelector('h4').textContent.trim(),
+ ).toEqual('Blank State');
+ });
+});
diff --git a/spec/javascripts/pipelines/empty_state_spec.js b/spec/javascripts/pipelines/empty_state_spec.js
index 97f04844b3a..71f77e5f42e 100644
--- a/spec/javascripts/pipelines/empty_state_spec.js
+++ b/spec/javascripts/pipelines/empty_state_spec.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import emptyStateComp from '~/pipelines/components/empty_state.vue';
+import mountComponent from '../helpers/vue_mount_component_helper';
describe('Pipelines Empty State', () => {
let component;
@@ -8,12 +9,15 @@ describe('Pipelines Empty State', () => {
beforeEach(() => {
EmptyStateComponent = Vue.extend(emptyStateComp);
- component = new EmptyStateComponent({
- propsData: {
- helpPagePath: 'foo',
- emptyStateSvgPath: 'foo',
- },
- }).$mount();
+ component = mountComponent(EmptyStateComponent, {
+ helpPagePath: 'foo',
+ emptyStateSvgPath: 'foo',
+ canSetCi: true,
+ });
+ });
+
+ afterEach(() => {
+ component.$destroy();
});
it('should render empty state SVG', () => {
@@ -24,16 +28,16 @@ describe('Pipelines Empty State', () => {
expect(component.$el.querySelector('h4').textContent).toContain('Build with confidence');
expect(
- component.$el.querySelector('p').textContent.trim().replace(/[\r\n]+/g, ' '),
- ).toContain('Continous Integration can help catch bugs by running your tests automatically');
+ component.$el.querySelector('p').innerHTML.trim().replace(/\n+\s+/m, ' ').replace(/\s\s+/g, ' '),
+ ).toContain('Continous Integration can help catch bugs by running your tests automatically,');
expect(
- component.$el.querySelector('p').textContent.trim().replace(/[\r\n]+/g, ' '),
- ).toContain('Continuous Deployment can help you deliver code to your product environment');
+ component.$el.querySelector('p').innerHTML.trim().replace(/\n+\s+/m, ' ').replace(/\s\s+/g, ' '),
+ ).toContain('while Continuous Deployment can help you deliver code to your product environment');
});
it('should render a link with provided help path', () => {
- expect(component.$el.querySelector('.btn-info').getAttribute('href')).toEqual('foo');
- expect(component.$el.querySelector('.btn-info').textContent).toContain('Get started with Pipelines');
+ expect(component.$el.querySelector('.js-get-started-pipelines').getAttribute('href')).toEqual('foo');
+ expect(component.$el.querySelector('.js-get-started-pipelines').textContent).toContain('Get started with Pipelines');
});
});
diff --git a/spec/javascripts/pipelines/error_state_spec.js b/spec/javascripts/pipelines/error_state_spec.js
deleted file mode 100644
index a402857a4d1..00000000000
--- a/spec/javascripts/pipelines/error_state_spec.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import Vue from 'vue';
-import errorStateComp from '~/pipelines/components/error_state.vue';
-
-describe('Pipelines Error State', () => {
- let component;
- let ErrorStateComponent;
-
- beforeEach(() => {
- ErrorStateComponent = Vue.extend(errorStateComp);
-
- component = new ErrorStateComponent({
- propsData: {
- errorStateSvgPath: 'foo',
- },
- }).$mount();
- });
-
- it('should render error state SVG', () => {
- expect(component.$el.querySelector('.svg-content svg')).toBeDefined();
- });
-
- it('should render emtpy state information', () => {
- expect(
- component.$el.querySelector('h4').textContent,
- ).toContain('The API failed to fetch the pipelines');
- });
-});
diff --git a/spec/javascripts/pipelines/nav_controls_spec.js b/spec/javascripts/pipelines/nav_controls_spec.js
index 09a0c14d96c..d6232f5c567 100644
--- a/spec/javascripts/pipelines/nav_controls_spec.js
+++ b/spec/javascripts/pipelines/nav_controls_spec.js
@@ -1,116 +1,79 @@
import Vue from 'vue';
import navControlsComp from '~/pipelines/components/nav_controls.vue';
+import mountComponent from '../helpers/vue_mount_component_helper';
describe('Pipelines Nav Controls', () => {
let NavControlsComponent;
+ let component;
beforeEach(() => {
NavControlsComponent = Vue.extend(navControlsComp);
});
- it('should render link to create a new pipeline', () => {
- const mockData = {
- newPipelinePath: 'foo',
- hasCiEnabled: true,
- helpPagePath: 'foo',
- ciLintPath: 'foo',
- resetCachePath: 'foo',
- canCreatePipeline: true,
- };
-
- const component = new NavControlsComponent({
- propsData: mockData,
- }).$mount();
-
- expect(component.$el.querySelector('.btn-create').textContent).toContain('Run Pipeline');
- expect(component.$el.querySelector('.btn-create').getAttribute('href')).toEqual(mockData.newPipelinePath);
+ afterEach(() => {
+ component.$destroy();
});
- it('should not render link to create pipeline if no permission is provided', () => {
+ it('should render link to create a new pipeline', () => {
const mockData = {
newPipelinePath: 'foo',
- hasCiEnabled: true,
- helpPagePath: 'foo',
ciLintPath: 'foo',
resetCachePath: 'foo',
- canCreatePipeline: false,
};
- const component = new NavControlsComponent({
- propsData: mockData,
- }).$mount();
+ component = mountComponent(NavControlsComponent, mockData);
- expect(component.$el.querySelector('.btn-create')).toEqual(null);
+ expect(component.$el.querySelector('.js-run-pipeline').textContent).toContain('Run Pipeline');
+ expect(component.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(mockData.newPipelinePath);
});
- it('should render link for resetting runner caches', () => {
+ it('should not render link to create pipeline if no path is provided', () => {
const mockData = {
- newPipelinePath: 'foo',
- hasCiEnabled: true,
helpPagePath: 'foo',
ciLintPath: 'foo',
resetCachePath: 'foo',
- canCreatePipeline: false,
};
- const component = new NavControlsComponent({
- propsData: mockData,
- }).$mount();
+ component = mountComponent(NavControlsComponent, mockData);
- expect(component.$el.querySelectorAll('.btn-default')[0].textContent).toContain('Clear runner caches');
- expect(component.$el.querySelectorAll('.btn-default')[0].getAttribute('href')).toEqual(mockData.resetCachePath);
+ expect(component.$el.querySelector('.js-run-pipeline')).toEqual(null);
});
it('should render link for CI lint', () => {
const mockData = {
newPipelinePath: 'foo',
- hasCiEnabled: true,
helpPagePath: 'foo',
ciLintPath: 'foo',
resetCachePath: 'foo',
- canCreatePipeline: true,
};
- const component = new NavControlsComponent({
- propsData: mockData,
- }).$mount();
+ component = mountComponent(NavControlsComponent, mockData);
- expect(component.$el.querySelectorAll('.btn-default')[1].textContent).toContain('CI Lint');
- expect(component.$el.querySelectorAll('.btn-default')[1].getAttribute('href')).toEqual(mockData.ciLintPath);
+ expect(component.$el.querySelector('.js-ci-lint').textContent.trim()).toContain('CI Lint');
+ expect(component.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(mockData.ciLintPath);
});
- it('should render link to help page when CI is not enabled', () => {
- const mockData = {
- newPipelinePath: 'foo',
- hasCiEnabled: false,
- helpPagePath: 'foo',
- ciLintPath: 'foo',
- resetCachePath: 'foo',
- canCreatePipeline: true,
- };
+ describe('Reset Runners Cache', () => {
+ beforeEach(() => {
+ const mockData = {
+ newPipelinePath: 'foo',
+ ciLintPath: 'foo',
+ resetCachePath: 'foo',
+ };
- const component = new NavControlsComponent({
- propsData: mockData,
- }).$mount();
+ component = mountComponent(NavControlsComponent, mockData);
+ });
- expect(component.$el.querySelector('.btn-info').textContent).toContain('Get started with Pipelines');
- expect(component.$el.querySelector('.btn-info').getAttribute('href')).toEqual(mockData.helpPagePath);
- });
+ it('should render button for resetting runner caches', () => {
+ expect(component.$el.querySelector('.js-clear-cache').textContent.trim()).toContain('Clear Runner Caches');
+ });
- it('should not render link to help page when CI is enabled', () => {
- const mockData = {
- newPipelinePath: 'foo',
- hasCiEnabled: true,
- helpPagePath: 'foo',
- ciLintPath: 'foo',
- resetCachePath: 'foo',
- canCreatePipeline: true,
- };
+ it('should emit postAction event when reset runner cache button is clicked', () => {
+ spyOn(component, '$emit');
- const component = new NavControlsComponent({
- propsData: mockData,
- }).$mount();
+ component.$el.querySelector('.js-clear-cache').click();
- expect(component.$el.querySelector('.btn-info')).toEqual(null);
+ expect(component.$emit).toHaveBeenCalledWith('resetRunnersCache', 'foo');
+ });
});
});
diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js
index 54d5bfd51e6..7e242eb45e1 100644
--- a/spec/javascripts/pipelines/pipelines_spec.js
+++ b/spec/javascripts/pipelines/pipelines_spec.js
@@ -7,36 +7,380 @@ import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Pipelines', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
- preloadFixtures('static/pipelines.html.raw');
preloadFixtures(jsonFixtureName);
let PipelinesComponent;
let pipelines;
- let component;
+ let vm;
+ const paths = {
+ endpoint: 'twitter/flight/pipelines.json',
+ autoDevopsPath: '/help/topics/autodevops/index.md',
+ helpPagePath: '/help/ci/quick_start/README',
+ emptyStateSvgPath: '/assets/illustrations/pipelines_empty.svg',
+ errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
+ noPipelinesSvgPath: '/assets/illustrations/pipelines_pending.svg',
+ ciLintPath: '/ci/lint',
+ resetCachePath: '/twitter/flight/settings/ci_cd/reset_cache',
+ newPipelinePath: '/twitter/flight/pipelines/new',
+ };
+
+ const noPermissions = {
+ endpoint: 'twitter/flight/pipelines.json',
+ autoDevopsPath: '/help/topics/autodevops/index.md',
+ helpPagePath: '/help/ci/quick_start/README',
+ emptyStateSvgPath: '/assets/illustrations/pipelines_empty.svg',
+ errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
+ noPipelinesSvgPath: '/assets/illustrations/pipelines_pending.svg',
+ };
beforeEach(() => {
- loadFixtures('static/pipelines.html.raw');
pipelines = getJSONFixture(jsonFixtureName);
PipelinesComponent = Vue.extend(pipelinesComp);
});
afterEach(() => {
- component.$destroy();
+ vm.$destroy();
+ });
+
+ const pipelinesInterceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify(pipelines), {
+ status: 200,
+ }));
+ };
+
+ const emptyStateInterceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify({
+ pipelines: [],
+ count: {
+ all: 0,
+ pending: 0,
+ running: 0,
+ finished: 0,
+ },
+ }), {
+ status: 200,
+ }));
+ };
+
+ const errorInterceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify({}), {
+ status: 500,
+ }));
+ };
+
+ describe('With permission', () => {
+ describe('With pipelines in main tab', () => {
+ beforeEach((done) => {
+ Vue.http.interceptors.push(pipelinesInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: true,
+ canCreatePipeline: true,
+ ...paths,
+ });
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, pipelinesInterceptor,
+ );
+ });
+
+ it('renders tabs', () => {
+ expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
+ });
+
+ it('renders Run Pipeline link', () => {
+ expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath);
+ });
+
+ it('renders CI Lint link', () => {
+ expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath);
+ });
+
+ it('renders Clear Runner Cache button', () => {
+ expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches');
+ });
+
+ it('renders pipelines table', () => {
+ expect(
+ vm.$el.querySelectorAll('.gl-responsive-table-row').length,
+ ).toEqual(pipelines.pipelines.length + 1);
+ });
+ });
+
+ describe('Without pipelines on main tab with CI', () => {
+ beforeEach((done) => {
+ Vue.http.interceptors.push(emptyStateInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: true,
+ canCreatePipeline: true,
+ ...paths,
+ });
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, emptyStateInterceptor,
+ );
+ });
+
+ it('renders tabs', () => {
+ expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
+ });
+
+ it('renders Run Pipeline link', () => {
+ expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath);
+ });
+
+ it('renders CI Lint link', () => {
+ expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath);
+ });
+
+ it('renders Clear Runner Cache button', () => {
+ expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches');
+ });
+
+ it('renders tab empty state', () => {
+ expect(vm.$el.querySelector('.empty-state h4').textContent.trim()).toEqual('There are currently no pipelines.');
+ });
+ });
+
+ describe('Without pipelines nor CI', () => {
+ beforeEach((done) => {
+ Vue.http.interceptors.push(emptyStateInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: false,
+ canCreatePipeline: true,
+ ...paths,
+ });
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, emptyStateInterceptor,
+ );
+ });
+
+ it('renders empty state', () => {
+ expect(vm.$el.querySelector('.js-empty-state h4').textContent.trim()).toEqual('Build with confidence');
+ expect(vm.$el.querySelector('.js-get-started-pipelines').getAttribute('href')).toEqual(paths.helpPagePath);
+ });
+
+ it('does not render tabs nor buttons', () => {
+ expect(vm.$el.querySelector('.js-pipelines-tab-all')).toBeNull();
+ expect(vm.$el.querySelector('.js-run-pipeline')).toBeNull();
+ expect(vm.$el.querySelector('.js-ci-lint')).toBeNull();
+ expect(vm.$el.querySelector('.js-clear-cache')).toBeNull();
+ });
+ });
+
+ describe('When API returns error', () => {
+ beforeEach((done) => {
+ Vue.http.interceptors.push(errorInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: false,
+ canCreatePipeline: true,
+ ...paths,
+ });
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, errorInterceptor,
+ );
+ });
+
+ it('renders tabs', () => {
+ expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
+ });
+
+ it('renders buttons', () => {
+ expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath);
+ expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath);
+ expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches');
+ });
+
+ it('renders error state', () => {
+ expect(vm.$el.querySelector('.empty-state').textContent.trim()).toContain('There was an error fetching the pipelines.');
+ });
+ });
+ });
+
+ describe('Without permission', () => {
+ describe('With pipelines in main tab', () => {
+ beforeEach((done) => {
+ Vue.http.interceptors.push(pipelinesInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: false,
+ canCreatePipeline: false,
+ ...noPermissions,
+ });
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, pipelinesInterceptor,
+ );
+ });
+
+ it('renders tabs', () => {
+ expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
+ });
+
+ it('does not render buttons', () => {
+ expect(vm.$el.querySelector('.js-run-pipeline')).toBeNull();
+ expect(vm.$el.querySelector('.js-ci-lint')).toBeNull();
+ expect(vm.$el.querySelector('.js-clear-cache')).toBeNull();
+ });
+
+ it('renders pipelines table', () => {
+ expect(
+ vm.$el.querySelectorAll('.gl-responsive-table-row').length,
+ ).toEqual(pipelines.pipelines.length + 1);
+ });
+ });
+
+ describe('Without pipelines on main tab with CI', () => {
+ beforeEach((done) => {
+ Vue.http.interceptors.push(emptyStateInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: true,
+ canCreatePipeline: false,
+ ...noPermissions,
+ });
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, emptyStateInterceptor,
+ );
+ });
+ it('renders tabs', () => {
+ expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
+ });
+
+ it('does not render buttons', () => {
+ expect(vm.$el.querySelector('.js-run-pipeline')).toBeNull();
+ expect(vm.$el.querySelector('.js-ci-lint')).toBeNull();
+ expect(vm.$el.querySelector('.js-clear-cache')).toBeNull();
+ });
+
+ it('renders tab empty state', () => {
+ expect(vm.$el.querySelector('.empty-state h4').textContent.trim()).toEqual('There are currently no pipelines.');
+ });
+ });
+
+ describe('Without pipelines nor CI', () => {
+ beforeEach((done) => {
+ Vue.http.interceptors.push(emptyStateInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: false,
+ canCreatePipeline: false,
+ ...noPermissions,
+ });
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, emptyStateInterceptor,
+ );
+ });
+
+ it('renders empty state without button to set CI', () => {
+ expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toEqual('This project is not currently set up to run pipelines.');
+ expect(vm.$el.querySelector('.js-get-started-pipelines')).toBeNull();
+ });
+
+ it('does not render tabs or buttons', () => {
+ expect(vm.$el.querySelector('.js-pipelines-tab-all')).toBeNull();
+ expect(vm.$el.querySelector('.js-run-pipeline')).toBeNull();
+ expect(vm.$el.querySelector('.js-ci-lint')).toBeNull();
+ expect(vm.$el.querySelector('.js-clear-cache')).toBeNull();
+ });
+ });
+
+ describe('When API returns error', () => {
+ beforeEach((done) => {
+ Vue.http.interceptors.push(errorInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: false,
+ canCreatePipeline: true,
+ ...noPermissions,
+ });
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, errorInterceptor,
+ );
+ });
+
+ it('renders tabs', () => {
+ expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
+ });
+
+ it('does not renders buttons', () => {
+ expect(vm.$el.querySelector('.js-run-pipeline')).toBeNull();
+ expect(vm.$el.querySelector('.js-ci-lint')).toBeNull();
+ expect(vm.$el.querySelector('.js-clear-cache')).toBeNull();
+ });
+
+ it('renders error state', () => {
+ expect(vm.$el.querySelector('.empty-state').textContent.trim()).toContain('There was an error fetching the pipelines.');
+ });
+ });
});
describe('successfull request', () => {
describe('with pipelines', () => {
- const pipelinesInterceptor = (request, next) => {
- next(request.respondWith(JSON.stringify(pipelines), {
- status: 200,
- }));
- };
-
beforeEach(() => {
Vue.http.interceptors.push(pipelinesInterceptor);
- component = mountComponent(PipelinesComponent, {
+ vm = mountComponent(PipelinesComponent, {
store: new Store(),
+ hasGitlabCi: true,
+ canCreatePipeline: true,
+ ...paths,
});
});
@@ -48,9 +392,9 @@ describe('Pipelines', () => {
it('should render table', (done) => {
setTimeout(() => {
- expect(component.$el.querySelector('.table-holder')).toBeDefined();
+ expect(vm.$el.querySelector('.table-holder')).toBeDefined();
expect(
- component.$el.querySelectorAll('.gl-responsive-table-row').length,
+ vm.$el.querySelectorAll('.gl-responsive-table-row').length,
).toEqual(pipelines.pipelines.length + 1);
done();
});
@@ -59,22 +403,22 @@ describe('Pipelines', () => {
it('should render navigation tabs', (done) => {
setTimeout(() => {
expect(
- component.$el.querySelector('.js-pipelines-tab-pending').textContent.trim(),
+ vm.$el.querySelector('.js-pipelines-tab-pending').textContent.trim(),
).toContain('Pending');
expect(
- component.$el.querySelector('.js-pipelines-tab-all').textContent.trim(),
+ vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim(),
).toContain('All');
expect(
- component.$el.querySelector('.js-pipelines-tab-running').textContent.trim(),
+ vm.$el.querySelector('.js-pipelines-tab-running').textContent.trim(),
).toContain('Running');
expect(
- component.$el.querySelector('.js-pipelines-tab-finished').textContent.trim(),
+ vm.$el.querySelector('.js-pipelines-tab-finished').textContent.trim(),
).toContain('Finished');
expect(
- component.$el.querySelector('.js-pipelines-tab-branches').textContent.trim(),
+ vm.$el.querySelector('.js-pipelines-tab-branches').textContent.trim(),
).toContain('Branches');
expect(
- component.$el.querySelector('.js-pipelines-tab-tags').textContent.trim(),
+ vm.$el.querySelector('.js-pipelines-tab-tags').textContent.trim(),
).toContain('Tags');
done();
});
@@ -82,10 +426,10 @@ describe('Pipelines', () => {
it('should make an API request when using tabs', (done) => {
setTimeout(() => {
- spyOn(component, 'updateContent');
- component.$el.querySelector('.js-pipelines-tab-finished').click();
+ spyOn(vm, 'updateContent');
+ vm.$el.querySelector('.js-pipelines-tab-finished').click();
- expect(component.updateContent).toHaveBeenCalledWith({ scope: 'finished', page: '1' });
+ expect(vm.updateContent).toHaveBeenCalledWith({ scope: 'finished', page: '1' });
done();
});
});
@@ -93,9 +437,9 @@ describe('Pipelines', () => {
describe('with pagination', () => {
it('should make an API request when using pagination', (done) => {
setTimeout(() => {
- spyOn(component, 'updateContent');
+ spyOn(vm, 'updateContent');
// Mock pagination
- component.store.state.pageInfo = {
+ vm.store.state.pageInfo = {
page: 1,
total: 10,
perPage: 2,
@@ -103,9 +447,9 @@ describe('Pipelines', () => {
totalPages: 5,
};
- Vue.nextTick(() => {
- component.$el.querySelector('.js-next-button a').click();
- expect(component.updateContent).toHaveBeenCalledWith({ scope: 'all', page: '2' });
+ vm.$nextTick(() => {
+ vm.$el.querySelector('.js-next-button a').click();
+ expect(vm.updateContent).toHaveBeenCalledWith({ scope: 'all', page: '2' });
done();
});
@@ -113,112 +457,249 @@ describe('Pipelines', () => {
});
});
});
+ });
- describe('without pipelines', () => {
- const emptyInterceptor = (request, next) => {
- next(request.respondWith(JSON.stringify([]), {
- status: 200,
- }));
- };
+ describe('methods', () => {
+ beforeEach(() => {
+ spyOn(history, 'pushState').and.stub();
+ });
- beforeEach(() => {
- Vue.http.interceptors.push(emptyInterceptor);
- });
+ describe('updateContent', () => {
+ it('should set given parameters', () => {
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: true,
+ canCreatePipeline: true,
+ ...paths,
+ });
+ vm.updateContent({ scope: 'finished', page: '4' });
- afterEach(() => {
- Vue.http.interceptors = _.without(
- Vue.http.interceptors, emptyInterceptor,
- );
+ expect(vm.page).toEqual('4');
+ expect(vm.scope).toEqual('finished');
+ expect(vm.requestData.scope).toEqual('finished');
+ expect(vm.requestData.page).toEqual('4');
});
+ });
+
+ describe('onChangeTab', () => {
+ it('should set page to 1', () => {
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: true,
+ canCreatePipeline: true,
+ ...paths,
+ });
+ spyOn(vm, 'updateContent');
- it('should render empty state', (done) => {
- component = new PipelinesComponent({
- propsData: {
- store: new Store(),
- },
- }).$mount();
+ vm.onChangeTab('running');
- setTimeout(() => {
- expect(component.$el.querySelector('.empty-state')).not.toBe(null);
- done();
+ expect(vm.updateContent).toHaveBeenCalledWith({ scope: 'running', page: '1' });
+ });
+ });
+
+ describe('onChangePage', () => {
+ it('should update page and keep scope', () => {
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: true,
+ canCreatePipeline: true,
+ ...paths,
});
+ spyOn(vm, 'updateContent');
+
+ vm.onChangePage(4);
+
+ expect(vm.updateContent).toHaveBeenCalledWith({ scope: vm.scope, page: '4' });
});
});
});
- describe('unsuccessfull request', () => {
- const errorInterceptor = (request, next) => {
- next(request.respondWith(JSON.stringify([]), {
- status: 500,
- }));
- };
-
+ describe('computed properties', () => {
beforeEach(() => {
- Vue.http.interceptors.push(errorInterceptor);
+ vm = mountComponent(PipelinesComponent, {
+ store: new Store(),
+ hasGitlabCi: true,
+ canCreatePipeline: true,
+ ...paths,
+ });
});
- afterEach(() => {
- Vue.http.interceptors = _.without(
- Vue.http.interceptors, errorInterceptor,
- );
+ describe('tabs', () => {
+ it('returns default tabs', () => {
+ expect(vm.tabs).toEqual([
+ { name: 'All', scope: 'all', count: undefined, isActive: true },
+ { name: 'Pending', scope: 'pending', count: undefined, isActive: false },
+ { name: 'Running', scope: 'running', count: undefined, isActive: false },
+ { name: 'Finished', scope: 'finished', count: undefined, isActive: false },
+ { name: 'Branches', scope: 'branches', isActive: false },
+ { name: 'Tags', scope: 'tags', isActive: false },
+ ]);
+ });
});
- it('should render error state', (done) => {
- component = new PipelinesComponent({
- propsData: {
- store: new Store(),
- },
- }).$mount();
+ describe('emptyTabMessage', () => {
+ it('returns message with scope', (done) => {
+ vm.scope = 'pending';
- setTimeout(() => {
- expect(component.$el.querySelector('.js-pipelines-error-state')).toBeDefined();
- done();
+ vm.$nextTick(() => {
+ expect(vm.emptyTabMessage).toEqual('There are currently no pending pipelines.');
+ done();
+ });
});
- });
- });
- describe('methods', () => {
- beforeEach(() => {
- spyOn(history, 'pushState').and.stub();
+ it('returns message without scope when scope is `all`', () => {
+ expect(vm.emptyTabMessage).toEqual('There are currently no pipelines.');
+ });
});
- describe('updateContent', () => {
- it('should set given parameters', () => {
- component = mountComponent(PipelinesComponent, {
- store: new Store(),
+ describe('stateToRender', () => {
+ it('returns loading state when the app is loading', () => {
+ expect(vm.stateToRender).toEqual('loading');
+ });
+
+ it('returns error state when app has error', (done) => {
+ vm.hasError = true;
+ vm.isLoading = false;
+
+ vm.$nextTick(() => {
+ expect(vm.stateToRender).toEqual('error');
+ done();
+ });
+ });
+
+ it('returns table list when app has pipelines', (done) => {
+ vm.isLoading = false;
+ vm.hasError = false;
+ vm.state.pipelines = pipelines.pipelines;
+
+ vm.$nextTick(() => {
+ expect(vm.stateToRender).toEqual('tableList');
+
+ done();
+ });
+ });
+
+ it('returns empty tab when app does not have pipelines but project has pipelines', (done) => {
+ vm.state.count.all = 10;
+ vm.isLoading = false;
+
+ vm.$nextTick(() => {
+ expect(vm.stateToRender).toEqual('emptyTab');
+
+ done();
});
- component.updateContent({ scope: 'finished', page: '4' });
+ });
+
+ it('returns empty tab when project has CI', (done) => {
+ vm.isLoading = false;
+ vm.$nextTick(() => {
+ expect(vm.stateToRender).toEqual('emptyTab');
- expect(component.page).toEqual('4');
- expect(component.scope).toEqual('finished');
- expect(component.requestData.scope).toEqual('finished');
- expect(component.requestData.page).toEqual('4');
+ done();
+ });
+ });
+
+ it('returns empty state when project does not have pipelines nor CI', (done) => {
+ vm.isLoading = false;
+ vm.hasGitlabCi = false;
+ vm.$nextTick(() => {
+ expect(vm.stateToRender).toEqual('emptyState');
+
+ done();
+ });
});
});
- describe('onChangeTab', () => {
- it('should set page to 1', () => {
- component = mountComponent(PipelinesComponent, {
- store: new Store(),
+ describe('shouldRenderTabs', () => {
+ it('returns true when state is loading & has already made the first request', (done) => {
+ vm.isLoading = true;
+ vm.hasMadeRequest = true;
+
+ vm.$nextTick(() => {
+ expect(vm.shouldRenderTabs).toEqual(true);
+
+ done();
});
- spyOn(component, 'updateContent');
+ });
- component.onChangeTab('running');
+ it('returns true when state is tableList & has already made the first request', (done) => {
+ vm.isLoading = false;
+ vm.state.pipelines = pipelines.pipelines;
+ vm.hasMadeRequest = true;
- expect(component.updateContent).toHaveBeenCalledWith({ scope: 'running', page: '1' });
+ vm.$nextTick(() => {
+ expect(vm.shouldRenderTabs).toEqual(true);
+
+ done();
+ });
+ });
+
+ it('returns true when state is error & has already made the first request', (done) => {
+ vm.isLoading = false;
+ vm.hasError = true;
+ vm.hasMadeRequest = true;
+
+ vm.$nextTick(() => {
+ expect(vm.shouldRenderTabs).toEqual(true);
+
+ done();
+ });
+ });
+
+ it('returns true when state is empty tab & has already made the first request', (done) => {
+ vm.isLoading = false;
+ vm.state.count.all = 10;
+ vm.hasMadeRequest = true;
+
+ vm.$nextTick(() => {
+ expect(vm.shouldRenderTabs).toEqual(true);
+
+ done();
+ });
+ });
+
+ it('returns false when has not made first request', (done) => {
+ vm.hasMadeRequest = false;
+
+ vm.$nextTick(() => {
+ expect(vm.shouldRenderTabs).toEqual(false);
+
+ done();
+ });
+ });
+
+ it('returns false when state is emtpy state', (done) => {
+ vm.isLoading = false;
+ vm.hasMadeRequest = true;
+ vm.hasGitlabCi = false;
+
+ vm.$nextTick(() => {
+ expect(vm.shouldRenderTabs).toEqual(false);
+
+ done();
+ });
});
});
- describe('onChangePage', () => {
- it('should update page and keep scope', () => {
- component = mountComponent(PipelinesComponent, {
- store: new Store(),
+ describe('shouldRenderButtons', () => {
+ it('returns true when it has paths & has made the first request', (done) => {
+ vm.hasMadeRequest = true;
+
+ vm.$nextTick(() => {
+ expect(vm.shouldRenderButtons).toEqual(true);
+
+ done();
});
- spyOn(component, 'updateContent');
+ });
+
+ it('returns false when it has not made the first request', (done) => {
+ vm.hasMadeRequest = false;
- component.onChangePage(4);
+ vm.$nextTick(() => {
+ expect(vm.shouldRenderButtons).toEqual(false);
- expect(component.updateContent).toHaveBeenCalledWith({ scope: component.scope, page: '4' });
+ done();
+ });
});
});
});
diff --git a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
index f6c0f51cf62..955ec6a531c 100644
--- a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
+++ b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
@@ -85,7 +85,7 @@ describe('PrometheusMetrics', () => {
expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeFalsy();
- expect(prometheusMetrics.$monitoredMetricsCount.text()).toEqual('12');
+ expect(prometheusMetrics.$monitoredMetricsCount.text()).toEqual('3 exporters with 12 metrics were found');
expect($metricsListLi.length).toEqual(metrics.length);
expect($metricsListLi.first().find('.badge').text()).toEqual(`${metrics[0].active_metrics}`);
});
diff --git a/spec/javascripts/sidebar/sidebar_assignees_spec.js b/spec/javascripts/sidebar/sidebar_assignees_spec.js
index 2fbb7268e0b..ebaaa6e806b 100644
--- a/spec/javascripts/sidebar/sidebar_assignees_spec.js
+++ b/spec/javascripts/sidebar/sidebar_assignees_spec.js
@@ -1,6 +1,6 @@
import _ from 'underscore';
import Vue from 'vue';
-import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees';
+import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees.vue';
import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarService from '~/sidebar/services/sidebar_service';
import SidebarStore from '~/sidebar/stores/sidebar_store';
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js
new file mode 100644
index 00000000000..cee22d5342a
--- /dev/null
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_maintainer_edit_spec.js
@@ -0,0 +1,40 @@
+import Vue from 'vue';
+import maintainerEditComponent from '~/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue';
+import mountComponent from 'spec/helpers/vue_mount_component_helper';
+
+describe('RWidgetMaintainerEdit', () => {
+ let Component;
+ let vm;
+
+ beforeEach(() => {
+ Component = Vue.extend(maintainerEditComponent);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('when a maintainer is allowed to edit', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ maintainerEditAllowed: true,
+ });
+ });
+
+ it('it renders the message', () => {
+ expect(vm.$el.textContent.trim()).toEqual('Allows edits from maintainers');
+ });
+ });
+
+ describe('when a maintainer is not allowed to edit', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ maintainerEditAllowed: false,
+ });
+ });
+
+ it('hides the message', () => {
+ expect(vm.$el.textContent.trim()).toEqual('');
+ });
+ });
+});
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
index 07ed7f7f532..31710551399 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import memoryUsageComponent from '~/vue_merge_request_widget/components/mr_widget_memory_usage';
+import MemoryUsage from '~/vue_merge_request_widget/components/memory_usage.vue';
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
const url = '/root/acets-review-apps/environments/15/deployments/1/metrics';
@@ -34,7 +34,7 @@ const metricsMockData = {
};
const createComponent = () => {
- const Component = Vue.extend(memoryUsageComponent);
+ const Component = Vue.extend(MemoryUsage);
return new Component({
el: document.createElement('div'),
@@ -67,21 +67,9 @@ describe('MemoryUsage', () => {
el = vm.$el;
});
- describe('props', () => {
- it('should have props with defaults', () => {
- const { metricsUrl } = memoryUsageComponent.props;
- const MetricsUrlTypeClass = metricsUrl.type;
-
- Vue.nextTick(() => {
- expect(new MetricsUrlTypeClass() instanceof String).toBeTruthy();
- expect(metricsUrl.required).toBeTruthy();
- });
- });
- });
-
describe('data', () => {
it('should have default data', () => {
- const data = memoryUsageComponent.data();
+ const data = MemoryUsage.data();
expect(Array.isArray(data.memoryMetrics)).toBeTruthy();
expect(data.memoryMetrics.length).toBe(0);
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
index 073f26cc78f..58f683fb3e6 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -517,13 +517,9 @@ describe('MRWidgetReadyToMerge', () => {
describe('Remove source branch checkbox', () => {
describe('when user can merge but cannot delete branch', () => {
- it('isRemoveSourceBranchButtonDisabled should be true', () => {
- expect(vm.isRemoveSourceBranchButtonDisabled).toBe(true);
- });
-
it('should be disabled in the rendered output', () => {
const checkboxElement = vm.$el.querySelector('#remove-source-branch-input');
- expect(checkboxElement.getAttribute('disabled')).toBe('disabled');
+ expect(checkboxElement).toBeNull();
});
});
@@ -540,7 +536,7 @@ describe('MRWidgetReadyToMerge', () => {
it('should be enabled in rendered output', () => {
const checkboxElement = this.customVm.$el.querySelector('#remove-source-branch-input');
- expect(checkboxElement.getAttribute('disabled')).toBeNull();
+ expect(checkboxElement).not.toBeNull();
});
});
});
@@ -549,12 +545,12 @@ describe('MRWidgetReadyToMerge', () => {
describe('when allowed to merge', () => {
beforeEach(() => {
vm = createComponent({
- mr: { isMergeAllowed: true },
+ mr: { isMergeAllowed: true, canRemoveSourceBranch: true },
});
});
it('shows remove source branch checkbox', () => {
- expect(vm.$el.querySelector('.js-remove-source-branch-checkbox')).toBeDefined();
+ expect(vm.$el.querySelector('.js-remove-source-branch-checkbox')).not.toBeNull();
});
it('shows modify commit message button', () => {
diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
index 18ba34b55a5..3e310980ffa 100644
--- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
@@ -81,6 +81,29 @@ describe('mrWidgetOptions', () => {
});
});
+ describe('shouldRenderSourceBranchRemovalStatus', () => {
+ it('should return true when cannot remove source branch and branch will be removed', () => {
+ vm.mr.canRemoveSourceBranch = false;
+ vm.mr.shouldRemoveSourceBranch = true;
+
+ expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(true);
+ });
+
+ it('should return false when can remove source branch and branch will be removed', () => {
+ vm.mr.canRemoveSourceBranch = true;
+ vm.mr.shouldRemoveSourceBranch = true;
+
+ expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false);
+ });
+
+ it('should return false when cannot remove source branch and branch will not be removed', () => {
+ vm.mr.canRemoveSourceBranch = false;
+ vm.mr.shouldRemoveSourceBranch = false;
+
+ expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false);
+ });
+ });
+
describe('shouldRenderDeployments', () => {
it('should return false for the initial data', () => {
expect(vm.shouldRenderDeployments).toBeFalsy();
@@ -349,6 +372,7 @@ describe('mrWidgetOptions', () => {
expect(comps['mr-widget-pipeline-blocked']).toBeDefined();
expect(comps['mr-widget-pipeline-failed']).toBeDefined();
expect(comps['mr-widget-merge-when-pipeline-succeeds']).toBeDefined();
+ expect(comps['mr-widget-maintainer-edit']).toBeDefined();
});
});
@@ -378,4 +402,22 @@ describe('mrWidgetOptions', () => {
});
});
});
+
+ describe('rendering source branch removal status', () => {
+ it('renders when user cannot remove branch and branch should be removed', (done) => {
+ vm.mr.canRemoveSourceBranch = false;
+ vm.mr.shouldRemoveSourceBranch = true;
+
+ vm.$nextTick(() => {
+ const tooltip = vm.$el.querySelector('.fa-question-circle');
+
+ expect(vm.$el.textContent).toContain('Removes source branch');
+ expect(tooltip.getAttribute('data-original-title')).toBe(
+ 'A user with write access to the source branch selected this option',
+ );
+
+ done();
+ });
+ });
+ });
});
diff --git a/spec/javascripts/vue_shared/components/clipboard_button_spec.js b/spec/javascripts/vue_shared/components/clipboard_button_spec.js
index d0fc10d69ea..f598b1afa74 100644
--- a/spec/javascripts/vue_shared/components/clipboard_button_spec.js
+++ b/spec/javascripts/vue_shared/components/clipboard_button_spec.js
@@ -10,6 +10,7 @@ describe('clipboard button', () => {
vm = mountComponent(Component, {
text: 'copy me',
title: 'Copy this value into Clipboard!',
+ cssClass: 'btn-danger',
});
});
@@ -28,4 +29,8 @@ describe('clipboard button', () => {
expect(vm.$el.getAttribute('data-placement')).toEqual('top');
expect(vm.$el.getAttribute('data-container')).toEqual(null);
});
+
+ it('should render provided classname', () => {
+ expect(vm.$el.classList).toContain('btn-danger');
+ });
});
diff --git a/spec/javascripts/vue_shared/components/memory_graph_spec.js b/spec/javascripts/vue_shared/components/memory_graph_spec.js
index d46a3f2328e..73a69df019e 100644
--- a/spec/javascripts/vue_shared/components/memory_graph_spec.js
+++ b/spec/javascripts/vue_shared/components/memory_graph_spec.js
@@ -1,12 +1,12 @@
import Vue from 'vue';
-import memoryGraphComponent from '~/vue_shared/components/memory_graph';
+import MemoryGraph from '~/vue_shared/components/memory_graph.vue';
import { mockMetrics, mockMedian, mockMedianIndex } from './mock_data';
const defaultHeight = '25';
const defaultWidth = '100';
const createComponent = () => {
- const Component = Vue.extend(memoryGraphComponent);
+ const Component = Vue.extend(MemoryGraph);
return new Component({
el: document.createElement('div'),
@@ -32,29 +32,9 @@ describe('MemoryGraph', () => {
el = vm.$el;
});
- describe('props', () => {
- it('should have props with defaults', (done) => {
- const { metrics, deploymentTime, width, height } = memoryGraphComponent.props;
-
- Vue.nextTick(() => {
- const typeClassMatcher = (propItem, expectedType) => {
- const PropItemTypeClass = propItem.type;
- expect(new PropItemTypeClass() instanceof expectedType).toBeTruthy();
- expect(propItem.required).toBeTruthy();
- };
-
- typeClassMatcher(metrics, Array);
- typeClassMatcher(deploymentTime, Number);
- typeClassMatcher(width, String);
- typeClassMatcher(height, String);
- done();
- });
- });
- });
-
describe('data', () => {
it('should have default data', () => {
- const data = memoryGraphComponent.data();
+ const data = MemoryGraph.data();
const dataValidator = (dataItem, expectedType, defaultVal) => {
expect(typeof dataItem).toBe(expectedType);
expect(dataItem).toBe(defaultVal);
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js
new file mode 100644
index 00000000000..67056793a20
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js
@@ -0,0 +1,81 @@
+import Vue from 'vue';
+
+import LabelsSelect from '~/labels_select';
+import baseComponent from '~/vue_shared/components/sidebar/labels_select/base.vue';
+
+import { mockConfig, mockLabels } from './mock_data';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = (config = mockConfig) => {
+ const Component = Vue.extend(baseComponent);
+
+ return mountComponent(Component, config);
+};
+
+describe('BaseComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('computed', () => {
+ describe('hiddenInputName', () => {
+ it('returns correct string when showCreate prop is `true`', () => {
+ expect(vm.hiddenInputName).toBe('issue[label_names][]');
+ });
+
+ it('returns correct string when showCreate prop is `false`', () => {
+ const mockConfigNonEditable = Object.assign({}, mockConfig, { showCreate: false });
+ const vmNonEditable = createComponent(mockConfigNonEditable);
+ expect(vmNonEditable.hiddenInputName).toBe('label_id[]');
+ vmNonEditable.$destroy();
+ });
+ });
+ });
+
+ describe('methods', () => {
+ describe('handleClick', () => {
+ it('emits onLabelClick event with label and list of labels as params', () => {
+ spyOn(vm, '$emit');
+ vm.handleClick(mockLabels[0]);
+ expect(vm.$emit).toHaveBeenCalledWith('onLabelClick', mockLabels[0]);
+ });
+ });
+ });
+
+ describe('mounted', () => {
+ it('creates LabelsSelect object and assigns it to `labelsDropdon` as prop', () => {
+ expect(vm.labelsDropdown instanceof LabelsSelect).toBe(true);
+ });
+ });
+
+ describe('template', () => {
+ it('renders component container element with classes `block labels`', () => {
+ expect(vm.$el.classList.contains('block')).toBe(true);
+ expect(vm.$el.classList.contains('labels')).toBe(true);
+ });
+
+ it('renders `.selectbox` element', () => {
+ expect(vm.$el.querySelector('.selectbox')).not.toBeNull();
+ expect(vm.$el.querySelector('.selectbox').getAttribute('style')).toBe('display: none;');
+ });
+
+ it('renders `.dropdown` element', () => {
+ expect(vm.$el.querySelector('.dropdown')).not.toBeNull();
+ });
+
+ it('renders `.dropdown-menu` element', () => {
+ const dropdownMenuEl = vm.$el.querySelector('.dropdown-menu');
+ expect(dropdownMenuEl).not.toBeNull();
+ expect(dropdownMenuEl.querySelector('.dropdown-page-one')).not.toBeNull();
+ expect(dropdownMenuEl.querySelector('.dropdown-content')).not.toBeNull();
+ expect(dropdownMenuEl.querySelector('.dropdown-loading')).not.toBeNull();
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button_spec.js
new file mode 100644
index 00000000000..ec63ac306d0
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button_spec.js
@@ -0,0 +1,82 @@
+import Vue from 'vue';
+
+import dropdownButtonComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_button.vue';
+
+import { mockConfig, mockLabels } from './mock_data';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const componentConfig = Object.assign({}, mockConfig, {
+ fieldName: 'label_id[]',
+ labels: mockLabels,
+ showExtraOptions: false,
+});
+
+const createComponent = (config = componentConfig) => {
+ const Component = Vue.extend(dropdownButtonComponent);
+
+ return mountComponent(Component, config);
+};
+
+describe('DropdownButtonComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('computed', () => {
+ describe('dropdownToggleText', () => {
+ it('returns text as `Label` when `labels` prop is empty array', () => {
+ const mockEmptyLabels = Object.assign({}, componentConfig, { labels: [] });
+ const vmEmptyLabels = createComponent(mockEmptyLabels);
+ expect(vmEmptyLabels.dropdownToggleText).toBe('Label');
+ vmEmptyLabels.$destroy();
+ });
+
+ it('returns first label name with remaining label count when `labels` prop has more than one item', () => {
+ const mockMoreLabels = Object.assign({}, componentConfig, {
+ labels: mockLabels.concat(mockLabels),
+ });
+ const vmMoreLabels = createComponent(mockMoreLabels);
+ expect(vmMoreLabels.dropdownToggleText).toBe('Foo Label +1 more');
+ vmMoreLabels.$destroy();
+ });
+
+ it('returns first label name when `labels` prop has only one item present', () => {
+ expect(vm.dropdownToggleText).toBe('Foo Label');
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders component container element of type `button`', () => {
+ expect(vm.$el.nodeName).toBe('BUTTON');
+ });
+
+ it('renders component container element with required data attributes', () => {
+ expect(vm.$el.dataset.abilityName).toBe(vm.abilityName);
+ expect(vm.$el.dataset.fieldName).toBe(vm.fieldName);
+ expect(vm.$el.dataset.issueUpdate).toBe(vm.updatePath);
+ expect(vm.$el.dataset.labels).toBe(vm.labelsPath);
+ expect(vm.$el.dataset.namespacePath).toBe(vm.namespace);
+ expect(vm.$el.dataset.showAny).not.toBeDefined();
+ });
+
+ it('renders dropdown toggle text element', () => {
+ const dropdownToggleTextEl = vm.$el.querySelector('.dropdown-toggle-text');
+ expect(dropdownToggleTextEl).not.toBeNull();
+ expect(dropdownToggleTextEl.innerText.trim()).toBe('Foo Label');
+ });
+
+ it('renders dropdown button icon', () => {
+ const dropdownIconEl = vm.$el.querySelector('i.fa');
+ expect(dropdownIconEl).not.toBeNull();
+ expect(dropdownIconEl.classList.contains('fa-chevron-down')).toBe(true);
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js
new file mode 100644
index 00000000000..f07aefb2f87
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js
@@ -0,0 +1,84 @@
+import Vue from 'vue';
+
+import dropdownCreateLabelComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue';
+
+import { mockSuggestedColors } from './mock_data';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = () => {
+ const Component = Vue.extend(dropdownCreateLabelComponent);
+
+ return mountComponent(Component);
+};
+
+describe('DropdownCreateLabelComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ gon.suggested_label_colors = mockSuggestedColors;
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('created', () => {
+ it('initializes `suggestedColors` prop on component from `gon.suggested_color_labels` object', () => {
+ expect(vm.suggestedColors.length).toBe(mockSuggestedColors.length);
+ });
+ });
+
+ describe('template', () => {
+ it('renders component container element with classes `dropdown-page-two dropdown-new-label`', () => {
+ expect(vm.$el.classList.contains('dropdown-page-two', 'dropdown-new-label')).toBe(true);
+ });
+
+ it('renders `Go back` button on component header', () => {
+ const backButtonEl = vm.$el.querySelector('.dropdown-title button.dropdown-title-button.dropdown-menu-back');
+ expect(backButtonEl).not.toBe(null);
+ expect(backButtonEl.querySelector('.fa-arrow-left')).not.toBe(null);
+ });
+
+ it('renders component header element', () => {
+ const headerEl = vm.$el.querySelector('.dropdown-title');
+ expect(headerEl.innerText.trim()).toContain('Create new label');
+ });
+
+ it('renders `Close` button on component header', () => {
+ const closeButtonEl = vm.$el.querySelector('.dropdown-title button.dropdown-title-button.dropdown-menu-close');
+ expect(closeButtonEl).not.toBe(null);
+ expect(closeButtonEl.querySelector('.fa-times.dropdown-menu-close-icon')).not.toBe(null);
+ });
+
+ it('renders `Name new label` input element', () => {
+ expect(vm.$el.querySelector('.dropdown-labels-error.js-label-error')).not.toBe(null);
+ expect(vm.$el.querySelector('input#new_label_name.default-dropdown-input')).not.toBe(null);
+ });
+
+ it('renders suggested colors list elements', () => {
+ const colorsListContainerEl = vm.$el.querySelector('.suggest-colors.suggest-colors-dropdown');
+ expect(colorsListContainerEl).not.toBe(null);
+ expect(colorsListContainerEl.querySelectorAll('a').length).toBe(mockSuggestedColors.length);
+
+ const colorItemEl = colorsListContainerEl.querySelectorAll('a')[0];
+ expect(colorItemEl.dataset.color).toBe(vm.suggestedColors[0]);
+ expect(colorItemEl.getAttribute('style')).toBe('background-color: rgb(0, 51, 204);');
+ });
+
+ it('renders color input element', () => {
+ expect(vm.$el.querySelector('.dropdown-label-color-input')).not.toBe(null);
+ expect(vm.$el.querySelector('.dropdown-label-color-preview.js-dropdown-label-color-preview')).not.toBe(null);
+ expect(vm.$el.querySelector('input#new_label_color.default-dropdown-input')).not.toBe(null);
+ });
+
+ it('renders component action buttons', () => {
+ const createBtnEl = vm.$el.querySelector('button.js-new-label-btn');
+ const cancelBtnEl = vm.$el.querySelector('button.js-cancel-label-btn');
+ expect(createBtnEl).not.toBe(null);
+ expect(createBtnEl.innerText.trim()).toBe('Create');
+ expect(cancelBtnEl.innerText.trim()).toBe('Cancel');
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js
new file mode 100644
index 00000000000..809e0327b1c
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js
@@ -0,0 +1,42 @@
+import Vue from 'vue';
+
+import dropdownFooterComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_footer.vue';
+
+import { mockConfig } from './mock_data';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = (labelsWebUrl = mockConfig.labelsWebUrl) => {
+ const Component = Vue.extend(dropdownFooterComponent);
+
+ return mountComponent(Component, {
+ labelsWebUrl,
+ });
+};
+
+describe('DropdownFooterComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('template', () => {
+ it('renders `Create new label` link element', () => {
+ const createLabelEl = vm.$el.querySelector('.dropdown-footer-list .dropdown-toggle-page');
+ expect(createLabelEl).not.toBeNull();
+ expect(createLabelEl.innerText.trim()).toBe('Create new label');
+ });
+
+ it('renders `Manage labels` link element', () => {
+ const manageLabelsEl = vm.$el.querySelector('.dropdown-footer-list .dropdown-external-link');
+ expect(manageLabelsEl).not.toBeNull();
+ expect(manageLabelsEl.getAttribute('href')).toBe(vm.labelsWebUrl);
+ expect(manageLabelsEl.innerText.trim()).toBe('Manage labels');
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header_spec.js
new file mode 100644
index 00000000000..325fa47c957
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header_spec.js
@@ -0,0 +1,36 @@
+import Vue from 'vue';
+
+import dropdownHeaderComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_header.vue';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = () => {
+ const Component = Vue.extend(dropdownHeaderComponent);
+
+ return mountComponent(Component);
+};
+
+describe('DropdownHeaderComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('template', () => {
+ it('renders header text element', () => {
+ const headerEl = vm.$el.querySelector('.dropdown-title span');
+ expect(headerEl.innerText.trim()).toBe('Assign labels');
+ });
+
+ it('renders `Close` button element', () => {
+ const closeBtnEl = vm.$el.querySelector('.dropdown-title button.dropdown-title-button.dropdown-menu-close');
+ expect(closeBtnEl).not.toBeNull();
+ expect(closeBtnEl.querySelector('.fa-times.dropdown-menu-close-icon')).not.toBeNull();
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_hidden_input_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_hidden_input_spec.js
new file mode 100644
index 00000000000..703b87498c7
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_hidden_input_spec.js
@@ -0,0 +1,37 @@
+import Vue from 'vue';
+
+import dropdownHiddenInputComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_hidden_input.vue';
+
+import { mockLabels } from './mock_data';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = (name = 'label_id[]', label = mockLabels[0]) => {
+ const Component = Vue.extend(dropdownHiddenInputComponent);
+
+ return mountComponent(Component, {
+ name,
+ label,
+ });
+};
+
+describe('DropdownHiddenInputComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('template', () => {
+ it('renders input element of type `hidden`', () => {
+ expect(vm.$el.nodeName).toBe('INPUT');
+ expect(vm.$el.getAttribute('type')).toBe('hidden');
+ expect(vm.$el.getAttribute('name')).toBe(vm.name);
+ expect(vm.$el.getAttribute('value')).toBe(`${vm.label.id}`);
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input_spec.js
new file mode 100644
index 00000000000..69e11d966c2
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input_spec.js
@@ -0,0 +1,39 @@
+import Vue from 'vue';
+
+import dropdownSearchInputComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = () => {
+ const Component = Vue.extend(dropdownSearchInputComponent);
+
+ return mountComponent(Component);
+};
+
+describe('DropdownSearchInputComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('template', () => {
+ it('renders input element with type `search`', () => {
+ const inputEl = vm.$el.querySelector('input.dropdown-input-field');
+ expect(inputEl).not.toBeNull();
+ expect(inputEl.getAttribute('type')).toBe('search');
+ });
+
+ it('renders search icon element', () => {
+ expect(vm.$el.querySelector('.fa-search.dropdown-input-search')).not.toBeNull();
+ });
+
+ it('renders clear search icon element', () => {
+ expect(vm.$el.querySelector('.fa-times.dropdown-input-clear.js-dropdown-input-clear')).not.toBeNull();
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title_spec.js
new file mode 100644
index 00000000000..c3580933072
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title_spec.js
@@ -0,0 +1,42 @@
+import Vue from 'vue';
+
+import dropdownTitleComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_title.vue';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = (canEdit = true) => {
+ const Component = Vue.extend(dropdownTitleComponent);
+
+ return mountComponent(Component, {
+ canEdit,
+ });
+};
+
+describe('DropdownTitleComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('template', () => {
+ it('renders title text', () => {
+ expect(vm.$el.classList.contains('title', 'hide-collapsed')).toBe(true);
+ expect(vm.$el.innerText.trim()).toContain('Labels');
+ });
+
+ it('renders spinner icon element', () => {
+ expect(vm.$el.querySelector('.fa-spinner.fa-spin.block-loading')).not.toBeNull();
+ });
+
+ it('renders `Edit` button element', () => {
+ const editBtnEl = vm.$el.querySelector('button.edit-link.js-sidebar-dropdown-toggle');
+ expect(editBtnEl).not.toBeNull();
+ expect(editBtnEl.innerText.trim()).toBe('Edit');
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js
new file mode 100644
index 00000000000..93b42795bea
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js
@@ -0,0 +1,74 @@
+import Vue from 'vue';
+
+import dropdownValueCollapsedComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue';
+
+import { mockLabels } from './mock_data';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = (labels = mockLabels) => {
+ const Component = Vue.extend(dropdownValueCollapsedComponent);
+
+ return mountComponent(Component, {
+ labels,
+ });
+};
+
+describe('DropdownValueCollapsedComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('computed', () => {
+ describe('labelsList', () => {
+ it('returns empty text when `labels` prop is empty array', () => {
+ const vmEmptyLabels = createComponent([]);
+ expect(vmEmptyLabels.labelsList).toBe('');
+ vmEmptyLabels.$destroy();
+ });
+
+ it('returns labels names separated by coma when `labels` prop has more than one item', () => {
+ const vmMoreLabels = createComponent(mockLabels.concat(mockLabels));
+ expect(vmMoreLabels.labelsList).toBe('Foo Label, Foo Label');
+ vmMoreLabels.$destroy();
+ });
+
+ it('returns labels names separated by coma with remaining labels count and `and more` phrase when `labels` prop has more than five items', () => {
+ const mockMoreLabels = Object.assign([], mockLabels);
+ for (let i = 0; i < 6; i += 1) {
+ mockMoreLabels.unshift(mockLabels[0]);
+ }
+
+ const vmMoreLabels = createComponent(mockMoreLabels);
+ expect(vmMoreLabels.labelsList).toBe('Foo Label, Foo Label, Foo Label, Foo Label, Foo Label, and 2 more');
+ vmMoreLabels.$destroy();
+ });
+
+ it('returns first label name when `labels` prop has only one item present', () => {
+ expect(vm.labelsList).toBe('Foo Label');
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders component container element with tooltip`', () => {
+ expect(vm.$el.dataset.placement).toBe('left');
+ expect(vm.$el.dataset.container).toBe('body');
+ expect(vm.$el.dataset.originalTitle).toBe(vm.labelsList);
+ });
+
+ it('renders tags icon element', () => {
+ expect(vm.$el.querySelector('.fa-tags')).not.toBeNull();
+ });
+
+ it('renders labels count', () => {
+ expect(vm.$el.querySelector('span').innerText.trim()).toBe(`${vm.labels.length}`);
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js
new file mode 100644
index 00000000000..66e0957b431
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js
@@ -0,0 +1,94 @@
+import Vue from 'vue';
+
+import dropdownValueComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_value.vue';
+
+import { mockConfig, mockLabels } from './mock_data';
+
+import mountComponent from '../../../../helpers/vue_mount_component_helper';
+
+const createComponent = (
+ labels = mockLabels,
+ labelFilterBasePath = mockConfig.labelFilterBasePath,
+) => {
+ const Component = Vue.extend(dropdownValueComponent);
+
+ return mountComponent(Component, {
+ labels,
+ labelFilterBasePath,
+ });
+};
+
+describe('DropdownValueComponent', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = createComponent();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('computed', () => {
+ describe('isEmpty', () => {
+ it('returns true if `labels` prop is empty', () => {
+ const vmEmptyLabels = createComponent([]);
+ expect(vmEmptyLabels.isEmpty).toBe(true);
+ vmEmptyLabels.$destroy();
+ });
+
+ it('returns false if `labels` prop is empty', () => {
+ expect(vm.isEmpty).toBe(false);
+ });
+ });
+ });
+
+ describe('methods', () => {
+ describe('labelFilterUrl', () => {
+ it('returns URL string starting with labelFilterBasePath and encoded label.title', () => {
+ expect(vm.labelFilterUrl({
+ title: 'Foo bar',
+ })).toBe('/gitlab-org/my-project/issues?label_name[]=Foo%20bar');
+ });
+ });
+
+ describe('labelStyle', () => {
+ it('returns object with `color` & `backgroundColor` properties from label.textColor & label.color', () => {
+ const label = {
+ textColor: '#FFFFFF',
+ color: '#BADA55',
+ };
+ const styleObj = vm.labelStyle(label);
+
+ expect(styleObj.color).toBe(label.textColor);
+ expect(styleObj.backgroundColor).toBe(label.color);
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders component container element with classes `hide-collapsed value issuable-show-labels`', () => {
+ expect(vm.$el.classList.contains('hide-collapsed', 'value', 'issuable-show-labels')).toBe(true);
+ });
+
+ it('render slot content inside component when `labels` prop is empty', () => {
+ const vmEmptyLabels = createComponent([]);
+ expect(vmEmptyLabels.$el.querySelector('.text-secondary').innerText.trim()).toBe(mockConfig.emptyValueText);
+ vmEmptyLabels.$destroy();
+ });
+
+ it('renders label element with filter URL', () => {
+ expect(vm.$el.querySelector('a').getAttribute('href')).toBe('/gitlab-org/my-project/issues?label_name[]=Foo%20Label');
+ });
+
+ it('renders label element with tooltip and styles based on label details', () => {
+ const labelEl = vm.$el.querySelector('a span.label.color-label');
+ expect(labelEl).not.toBeNull();
+ expect(labelEl.dataset.placement).toBe('bottom');
+ expect(labelEl.dataset.container).toBe('body');
+ expect(labelEl.dataset.originalTitle).toBe(mockLabels[0].description);
+ expect(labelEl.getAttribute('style')).toBe('background-color: rgb(186, 218, 85);');
+ expect(labelEl.innerText.trim()).toBe(mockLabels[0].title);
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js
new file mode 100644
index 00000000000..e9008c29b22
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js
@@ -0,0 +1,49 @@
+export const mockLabels = [
+ {
+ id: 26,
+ title: 'Foo Label',
+ description: 'Foobar',
+ color: '#BADA55',
+ text_color: '#FFFFFF',
+ },
+];
+
+export const mockSuggestedColors = [
+ '#0033CC',
+ '#428BCA',
+ '#44AD8E',
+ '#A8D695',
+ '#5CB85C',
+ '#69D100',
+ '#004E00',
+ '#34495E',
+ '#7F8C8D',
+ '#A295D6',
+ '#5843AD',
+ '#8E44AD',
+ '#FFECDB',
+ '#AD4363',
+ '#D10069',
+ '#CC0033',
+ '#FF0000',
+ '#D9534F',
+ '#D1D100',
+ '#F0AD4E',
+ '#AD8D43',
+];
+
+export const mockConfig = {
+ showCreate: true,
+ abilityName: 'issue',
+ context: {
+ labels: mockLabels,
+ },
+ namespace: 'gitlab-org',
+ updatePath: '/gitlab-org/my-project/issue/1',
+ labelsPath: '/gitlab-org/my-project/labels.json',
+ labelsWebUrl: '/gitlab-org/my-project/labels',
+ labelFilterBasePath: '/gitlab-org/my-project/issues',
+ canEdit: true,
+ suggestedColors: mockSuggestedColors,
+ emptyValueText: 'None',
+};
diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb
index b7c2ff03125..b502daea418 100644
--- a/spec/lib/banzai/filter/autolink_filter_spec.rb
+++ b/spec/lib/banzai/filter/autolink_filter_spec.rb
@@ -4,6 +4,7 @@ describe Banzai::Filter::AutolinkFilter do
include FilterSpecHelper
let(:link) { 'http://about.gitlab.com/' }
+ let(:quotes) { ['"', "'"] }
it 'does nothing when :autolink is false' do
exp = act = link
@@ -15,17 +16,7 @@ describe Banzai::Filter::AutolinkFilter do
expect(filter(act).to_html).to eq exp
end
- context 'when the input contains no links' do
- it 'does not parse_html back the rinku returned value' do
- act = HTML::Pipeline.parse('<p>This text contains no links to autolink</p>')
-
- expect_any_instance_of(described_class).not_to receive(:parse_html)
-
- filter(act).to_html
- end
- end
-
- context 'Rinku schemes' do
+ context 'Various schemes' do
it 'autolinks http' do
doc = filter("See #{link}")
expect(doc.at_css('a').text).to eq link
@@ -56,32 +47,26 @@ describe Banzai::Filter::AutolinkFilter do
expect(doc.at_css('a')['href']).to eq link
end
- it 'accepts link_attr options' do
- doc = filter("See #{link}", link_attr: { class: 'custom' })
+ it 'autolinks multiple URLs' do
+ link1 = 'http://localhost:3000/'
+ link2 = 'http://google.com/'
- expect(doc.at_css('a')['class']).to eq 'custom'
- end
+ doc = filter("See #{link1} and #{link2}")
- described_class::IGNORE_PARENTS.each do |elem|
- it "ignores valid links contained inside '#{elem}' element" do
- exp = act = "<#{elem}>See #{link}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
+ found_links = doc.css('a')
- context 'when the input contains link' do
- it 'does parse_html back the rinku returned value' do
- act = HTML::Pipeline.parse("<p>See #{link}</p>")
+ expect(found_links.size).to eq(2)
+ expect(found_links[0].text).to eq(link1)
+ expect(found_links[0]['href']).to eq(link1)
+ expect(found_links[1].text).to eq(link2)
+ expect(found_links[1]['href']).to eq(link2)
+ end
- expect_any_instance_of(described_class).to receive(:parse_html).at_least(:once).and_call_original
+ it 'accepts link_attr options' do
+ doc = filter("See #{link}", link_attr: { class: 'custom' })
- filter(act).to_html
- end
+ expect(doc.at_css('a')['class']).to eq 'custom'
end
- end
-
- context 'other schemes' do
- let(:link) { 'foo://bar.baz/' }
it 'autolinks smb' do
link = 'smb:///Volumes/shared/foo.pdf'
@@ -91,6 +76,21 @@ describe Banzai::Filter::AutolinkFilter do
expect(doc.at_css('a')['href']).to eq link
end
+ it 'autolinks multiple occurences of smb' do
+ link1 = 'smb:///Volumes/shared/foo.pdf'
+ link2 = 'smb:///Volumes/shared/bar.pdf'
+
+ doc = filter("See #{link1} and #{link2}")
+
+ found_links = doc.css('a')
+
+ expect(found_links.size).to eq(2)
+ expect(found_links[0].text).to eq(link1)
+ expect(found_links[0]['href']).to eq(link1)
+ expect(found_links[1].text).to eq(link2)
+ expect(found_links[1]['href']).to eq(link2)
+ end
+
it 'autolinks irc' do
link = 'irc://irc.freenode.net/git'
doc = filter("See #{link}")
@@ -132,6 +132,45 @@ describe Banzai::Filter::AutolinkFilter do
expect(doc.at_css('a').text).to eq link
end
+ it 'includes trailing punctuation when part of a balanced pair' do
+ described_class::PUNCTUATION_PAIRS.each do |close, open|
+ next if open.in?(quotes)
+
+ balanced_link = "#{link}#{open}abc#{close}"
+ balanced_actual = filter("See #{balanced_link}...")
+ unbalanced_link = "#{link}#{close}"
+ unbalanced_actual = filter("See #{unbalanced_link}...")
+
+ expect(balanced_actual.at_css('a').text).to eq(balanced_link)
+ expect(unescape(balanced_actual.to_html)).to eq(Rinku.auto_link("See #{balanced_link}..."))
+ expect(unbalanced_actual.at_css('a').text).to eq(link)
+ expect(unescape(unbalanced_actual.to_html)).to eq(Rinku.auto_link("See #{unbalanced_link}..."))
+ end
+ end
+
+ it 'removes trailing quotes' do
+ quotes.each do |quote|
+ balanced_link = "#{link}#{quote}abc#{quote}"
+ balanced_actual = filter("See #{balanced_link}...")
+ unbalanced_link = "#{link}#{quote}"
+ unbalanced_actual = filter("See #{unbalanced_link}...")
+
+ expect(balanced_actual.at_css('a').text).to eq(balanced_link[0...-1])
+ expect(unescape(balanced_actual.to_html)).to eq(Rinku.auto_link("See #{balanced_link}..."))
+ expect(unbalanced_actual.at_css('a').text).to eq(link)
+ expect(unescape(unbalanced_actual.to_html)).to eq(Rinku.auto_link("See #{unbalanced_link}..."))
+ end
+ end
+
+ it 'removes one closing punctuation mark when the punctuation in the link is unbalanced' do
+ complicated_link = "(#{link}(a'b[c'd]))'"
+ expected_complicated_link = %Q{(<a href="#{link}(a'b[c'd]))">#{link}(a'b[c'd]))</a>'}
+ actual = unescape(filter(complicated_link).to_html)
+
+ expect(actual).to eq(Rinku.auto_link(complicated_link))
+ expect(actual).to eq(expected_complicated_link)
+ end
+
it 'does not include trailing HTML entities' do
doc = filter("See &lt;&lt;&lt;#{link}&gt;&gt;&gt;")
@@ -151,4 +190,29 @@ describe Banzai::Filter::AutolinkFilter do
end
end
end
+
+ context 'when the link is inside a tag' do
+ %w[http rdar].each do |protocol|
+ it "renders text after the link correctly for #{protocol}" do
+ doc = filter(ERB::Util.html_escape_once("<#{protocol}://link><another>"))
+
+ expect(doc.children.last.text).to include('<another>')
+ end
+ end
+ end
+
+ # Rinku does not escape these characters in HTML attributes, but content_tag
+ # does. We don't care about that difference for these specs, though.
+ def unescape(html)
+ %w([ ] { }).each do |cgi_escape|
+ html.sub!(CGI.escape(cgi_escape), cgi_escape)
+ end
+
+ quotes.each do |html_escape|
+ html.sub!(CGI.escape_html(html_escape), html_escape)
+ html.sub!(CGI.escape(html_escape), CGI.escape_html(html_escape))
+ end
+
+ html
+ end
end
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index 862b1fe3fd3..0c524a1551f 100644
--- a/spec/lib/banzai/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -381,11 +381,11 @@ describe Banzai::Filter::LabelReferenceFilter do
end
it 'has valid link text' do
- expect(result.css('a').first.text).to eq "#{label.name} in #{project2.name_with_namespace}"
+ expect(result.css('a').first.text).to eq "#{label.name} in #{project2.full_name}"
end
it 'has valid text' do
- expect(result.text).to eq "See #{label.name} in #{project2.name_with_namespace}"
+ expect(result.text).to eq "See #{label.name} in #{project2.full_name}"
end
it 'ignores invalid IDs on the referenced label' do
@@ -481,12 +481,12 @@ describe Banzai::Filter::LabelReferenceFilter do
it 'has valid link text' do
expect(result.css('a').first.text)
- .to eq "#{group_label.name} in #{another_project.name_with_namespace}"
+ .to eq "#{group_label.name} in #{another_project.full_name}"
end
it 'has valid text' do
expect(result.text)
- .to eq "See #{group_label.name} in #{another_project.name_with_namespace}"
+ .to eq "See #{group_label.name} in #{another_project.full_name}"
end
it 'ignores invalid IDs on the referenced label' do
diff --git a/spec/lib/constraints/group_url_constrainer_spec.rb b/spec/lib/constraints/group_url_constrainer_spec.rb
index 4dab58b26a0..ff295068ba9 100644
--- a/spec/lib/constraints/group_url_constrainer_spec.rb
+++ b/spec/lib/constraints/group_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GroupUrlConstrainer do
+describe Constraints::GroupUrlConstrainer do
let!(:group) { create(:group, path: 'gitlab') }
describe '#matches?' do
diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb
index 92331eb2e5d..c96e7ab8495 100644
--- a/spec/lib/constraints/project_url_constrainer_spec.rb
+++ b/spec/lib/constraints/project_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProjectUrlConstrainer do
+describe Constraints::ProjectUrlConstrainer do
let!(:project) { create(:project) }
let!(:namespace) { project.namespace }
diff --git a/spec/lib/constraints/user_url_constrainer_spec.rb b/spec/lib/constraints/user_url_constrainer_spec.rb
index cb3b4ff1391..e2c85bb27bb 100644
--- a/spec/lib/constraints/user_url_constrainer_spec.rb
+++ b/spec/lib/constraints/user_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UserUrlConstrainer do
+describe Constraints::UserUrlConstrainer do
let!(:user) { create(:user, username: 'dz') }
describe '#matches?' do
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index b49ddbfc780..48e9902027c 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -30,9 +30,10 @@ describe Gitlab::Checks::ChangeAccess do
end
end
- context 'when the user is not allowed to push code' do
+ context 'when the user is not allowed to push to the repo' do
it 'raises an error' do
expect(user_access).to receive(:can_do_action?).with(:push_code).and_return(false)
+ expect(user_access).to receive(:can_push_to_branch?).with('master').and_return(false)
expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to push code to this project.')
end
diff --git a/spec/lib/gitlab/checks/lfs_integrity_spec.rb b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
index 17756621221..7201e4f7bf6 100644
--- a/spec/lib/gitlab/checks/lfs_integrity_spec.rb
+++ b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
@@ -2,23 +2,25 @@ require 'spec_helper'
describe Gitlab::Checks::LfsIntegrity do
include ProjectForksHelper
+
let(:project) { create(:project, :repository) }
- let(:newrev) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' }
+ let(:repository) { project.repository }
+ let(:newrev) do
+ operations = BareRepoOperations.new(repository.path)
+
+ # Create a commit not pointed at by any ref to emulate being in the
+ # pre-receive hook so that `--not --all` returns some objects
+ operations.commit_tree('8856a329dd38ca86dfb9ce5aa58a16d88cc119bd', "New LFS objects")
+ end
subject { described_class.new(project, newrev) }
describe '#objects_missing?' do
- let(:blob_object) { project.repository.blob_at_branch('lfs', 'files/lfs/lfs_object.iso') }
-
- before do
- allow_any_instance_of(Gitlab::Git::RevList).to receive(:new_objects) do |&lazy_block|
- lazy_block.call([blob_object.id])
- end
- end
+ let(:blob_object) { repository.blob_at_branch('lfs', 'files/lfs/lfs_object.iso') }
context 'with LFS not enabled' do
it 'skips integrity check' do
- expect_any_instance_of(Gitlab::Git::RevList).not_to receive(:new_objects)
+ expect_any_instance_of(Gitlab::Git::LfsChanges).not_to receive(:new_pointers)
subject.objects_missing?
end
@@ -33,7 +35,7 @@ describe Gitlab::Checks::LfsIntegrity do
let(:newrev) { nil }
it 'skips integrity check' do
- expect_any_instance_of(Gitlab::Git::RevList).not_to receive(:new_objects)
+ expect_any_instance_of(Gitlab::Git::LfsChanges).not_to receive(:new_pointers)
expect(subject.objects_missing?).to be_falsey
end
diff --git a/spec/lib/gitlab/ci/charts_spec.rb b/spec/lib/gitlab/ci/charts_spec.rb
index f8188675013..1668d3bbaac 100644
--- a/spec/lib/gitlab/ci/charts_spec.rb
+++ b/spec/lib/gitlab/ci/charts_spec.rb
@@ -1,6 +1,51 @@
require 'spec_helper'
describe Gitlab::Ci::Charts do
+ context "yearchart" do
+ let(:project) { create(:project) }
+ let(:chart) { Gitlab::Ci::Charts::YearChart.new(project) }
+
+ subject { chart.to }
+
+ it 'goes until the end of the current month (including the whole last day of the month)' do
+ is_expected.to eq(Date.today.end_of_month.end_of_day)
+ end
+
+ it 'starts at the beginning of the current year' do
+ expect(chart.from).to eq(chart.to.years_ago(1).beginning_of_month.beginning_of_day)
+ end
+ end
+
+ context "monthchart" do
+ let(:project) { create(:project) }
+ let(:chart) { Gitlab::Ci::Charts::MonthChart.new(project) }
+
+ subject { chart.to }
+
+ it 'includes the whole current day' do
+ is_expected.to eq(Date.today.end_of_day)
+ end
+
+ it 'starts one month ago' do
+ expect(chart.from).to eq(1.month.ago.beginning_of_day)
+ end
+ end
+
+ context "weekchart" do
+ let(:project) { create(:project) }
+ let(:chart) { Gitlab::Ci::Charts::WeekChart.new(project) }
+
+ subject { chart.to }
+
+ it 'includes the whole current day' do
+ is_expected.to eq(Date.today.end_of_day)
+ end
+
+ it 'starts one week ago' do
+ expect(chart.from).to eq(1.week.ago.beginning_of_day)
+ end
+ end
+
context "pipeline_times" do
let(:project) { create(:project) }
let(:chart) { Gitlab::Ci::Charts::PipelineTime.new(project) }
diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb
index 91c9625ba06..448c6fb57dd 100644
--- a/spec/lib/gitlab/ci/trace_spec.rb
+++ b/spec/lib/gitlab/ci/trace_spec.rb
@@ -399,4 +399,140 @@ describe Gitlab::Ci::Trace do
end
end
end
+
+ describe '#archive!' do
+ subject { trace.archive! }
+
+ shared_examples 'archive trace file' do
+ it do
+ expect { subject }.to change { Ci::JobArtifact.count }.by(1)
+
+ build.reload
+ expect(build.trace.exist?).to be_truthy
+ expect(build.job_artifacts_trace.file.exists?).to be_truthy
+ expect(build.job_artifacts_trace.file.filename).to eq('job.log')
+ expect(File.exist?(src_path)).to be_falsy
+ expect(src_checksum)
+ .to eq(Digest::SHA256.file(build.job_artifacts_trace.file.path).hexdigest)
+ expect(build.job_artifacts_trace.file_sha256).to eq(src_checksum)
+ end
+ end
+
+ shared_examples 'source trace file stays intact' do |error:|
+ it do
+ expect { subject }.to raise_error(error)
+
+ build.reload
+ expect(build.trace.exist?).to be_truthy
+ expect(build.job_artifacts_trace).to be_nil
+ expect(File.exist?(src_path)).to be_truthy
+ end
+ end
+
+ shared_examples 'archive trace in database' do
+ it do
+ expect { subject }.to change { Ci::JobArtifact.count }.by(1)
+
+ build.reload
+ expect(build.trace.exist?).to be_truthy
+ expect(build.job_artifacts_trace.file.exists?).to be_truthy
+ expect(build.job_artifacts_trace.file.filename).to eq('job.log')
+ expect(build.old_trace).to be_nil
+ expect(src_checksum)
+ .to eq(Digest::SHA256.file(build.job_artifacts_trace.file.path).hexdigest)
+ expect(build.job_artifacts_trace.file_sha256).to eq(src_checksum)
+ end
+ end
+
+ shared_examples 'source trace in database stays intact' do |error:|
+ it do
+ expect { subject }.to raise_error(error)
+
+ build.reload
+ expect(build.trace.exist?).to be_truthy
+ expect(build.job_artifacts_trace).to be_nil
+ expect(build.old_trace).to eq(trace_content)
+ end
+ end
+
+ context 'when job does not have trace artifact' do
+ context 'when trace file stored in default path' do
+ let!(:build) { create(:ci_build, :success, :trace_live) }
+ let!(:src_path) { trace.read { |s| return s.path } }
+ let!(:src_checksum) { Digest::SHA256.file(src_path).hexdigest }
+
+ it_behaves_like 'archive trace file'
+
+ context 'when failed to create clone file' do
+ before do
+ allow(IO).to receive(:copy_stream).and_return(0)
+ end
+
+ it_behaves_like 'source trace file stays intact', error: Gitlab::Ci::Trace::ArchiveError
+ end
+
+ context 'when failed to create job artifact record' do
+ before do
+ allow_any_instance_of(Ci::JobArtifact).to receive(:save).and_return(false)
+ allow_any_instance_of(Ci::JobArtifact).to receive_message_chain(:errors, :full_messages)
+ .and_return(%w[Error Error])
+ end
+
+ it_behaves_like 'source trace file stays intact', error: ActiveRecord::RecordInvalid
+ end
+ end
+
+ context 'when trace is stored in database' do
+ let(:build) { create(:ci_build, :success) }
+ let(:trace_content) { 'Sample trace' }
+ let!(:src_checksum) { Digest::SHA256.hexdigest(trace_content) }
+
+ before do
+ build.update_column(:trace, trace_content)
+ end
+
+ it_behaves_like 'archive trace in database'
+
+ context 'when failed to create clone file' do
+ before do
+ allow(IO).to receive(:copy_stream).and_return(0)
+ end
+
+ it_behaves_like 'source trace in database stays intact', error: Gitlab::Ci::Trace::ArchiveError
+ end
+
+ context 'when failed to create job artifact record' do
+ before do
+ allow_any_instance_of(Ci::JobArtifact).to receive(:save).and_return(false)
+ allow_any_instance_of(Ci::JobArtifact).to receive_message_chain(:errors, :full_messages)
+ .and_return(%w[Error Error])
+ end
+
+ it_behaves_like 'source trace in database stays intact', error: ActiveRecord::RecordInvalid
+ end
+ end
+ end
+
+ context 'when job has trace artifact' do
+ before do
+ create(:ci_job_artifact, :trace, job: build)
+ end
+
+ it 'does not archive' do
+ expect_any_instance_of(described_class).not_to receive(:archive_stream!)
+ expect { subject }.to raise_error('Already archived')
+ expect(build.job_artifacts_trace.file.exists?).to be_truthy
+ end
+ end
+
+ context 'when job is not finished yet' do
+ let!(:build) { create(:ci_build, :running, :trace_live) }
+
+ it 'does not archive' do
+ expect_any_instance_of(described_class).not_to receive(:archive_stream!)
+ expect { subject }.to raise_error('Job is not finished yet')
+ expect(build.trace.exist?).to be_truthy
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/conflict/file_collection_spec.rb b/spec/lib/gitlab/conflict/file_collection_spec.rb
index 5944ce8049a..c93912db411 100644
--- a/spec/lib/gitlab/conflict/file_collection_spec.rb
+++ b/spec/lib/gitlab/conflict/file_collection_spec.rb
@@ -10,6 +10,38 @@ describe Gitlab::Conflict::FileCollection do
end
end
+ describe '#cache' do
+ it 'specifies a custom namespace with the merge request commit ids' do
+ our_commit = merge_request.source_branch_head.raw
+ their_commit = merge_request.target_branch_head.raw
+ custom_namespace = "#{our_commit.id}:#{their_commit.id}"
+
+ expect(file_collection.send(:cache).namespace).to include(custom_namespace)
+ end
+ end
+
+ describe '#can_be_resolved_in_ui?' do
+ it 'returns true if conflicts for this collection can be resolved in the UI' do
+ expect(file_collection.can_be_resolved_in_ui?).to be true
+ end
+
+ it "returns false if conflicts for this collection can't be resolved in the UI" do
+ expect(file_collection).to receive(:files).and_raise(Gitlab::Git::Conflict::Resolver::ConflictSideMissing)
+
+ expect(file_collection.can_be_resolved_in_ui?).to be false
+ end
+
+ it 'caches the result' do
+ expect(file_collection).to receive(:files).twice.and_call_original
+
+ expect(file_collection.can_be_resolved_in_ui?).to be true
+
+ expect(file_collection).not_to receive(:files)
+
+ expect(file_collection.can_be_resolved_in_ui?).to be true
+ end
+ end
+
describe '#default_commit_message' do
it 'matches the format of the git CLI commit message' do
expect(file_collection.default_commit_message).to eq(<<EOM.chomp)
diff --git a/spec/lib/gitlab/contributions_calendar_spec.rb b/spec/lib/gitlab/contributions_calendar_spec.rb
index 49a179ba875..2c63f3b0455 100644
--- a/spec/lib/gitlab/contributions_calendar_spec.rb
+++ b/spec/lib/gitlab/contributions_calendar_spec.rb
@@ -11,7 +11,7 @@ describe Gitlab::ContributionsCalendar do
end
let(:public_project) do
- create(:project, :public) do |project|
+ create(:project, :public, :repository) do |project|
create(:project_member, user: contributor, project: project)
end
end
@@ -40,13 +40,13 @@ describe Gitlab::ContributionsCalendar do
described_class.new(contributor, current_user)
end
- def create_event(project, day, hour = 0)
+ def create_event(project, day, hour = 0, action = Event::CREATED, target_symbol = :issue)
@targets ||= {}
- @targets[project] ||= create(:issue, project: project, author: contributor)
+ @targets[project] ||= create(target_symbol, project: project, author: contributor)
Event.create!(
project: project,
- action: Event::CREATED,
+ action: action,
target: @targets[project],
author: contributor,
created_at: DateTime.new(day.year, day.month, day.day, hour)
@@ -71,6 +71,19 @@ describe Gitlab::ContributionsCalendar do
expect(calendar(contributor).activity_dates[today]).to eq(2)
end
+ it "counts the diff notes on merge request" do
+ create_event(public_project, today, 0, Event::COMMENTED, :diff_note_on_merge_request)
+
+ expect(calendar(contributor).activity_dates[today]).to eq(1)
+ end
+
+ it "counts the discussions on merge requests and issues" do
+ create_event(public_project, today, 0, Event::COMMENTED, :discussion_note_on_merge_request)
+ create_event(public_project, today, 2, Event::COMMENTED, :discussion_note_on_issue)
+
+ expect(calendar(contributor).activity_dates[today]).to eq(2)
+ end
+
context "when events fall under different dates depending on the time zone" do
before do
create_event(public_project, today, 1)
diff --git a/spec/lib/gitlab/data_builder/build_spec.rb b/spec/lib/gitlab/data_builder/build_spec.rb
index 91c43f2bdc0..ee91decafad 100644
--- a/spec/lib/gitlab/data_builder/build_spec.rb
+++ b/spec/lib/gitlab/data_builder/build_spec.rb
@@ -16,7 +16,7 @@ describe Gitlab::DataBuilder::Build do
it { expect(data[:build_status]).to eq(build.status) }
it { expect(data[:build_allow_failure]).to eq(false) }
it { expect(data[:project_id]).to eq(build.project.id) }
- it { expect(data[:project_name]).to eq(build.project.name_with_namespace) }
+ it { expect(data[:project_name]).to eq(build.project.full_name) }
context 'commit author_url' do
context 'when no commit present' do
diff --git a/spec/lib/gitlab/data_builder/pipeline_spec.rb b/spec/lib/gitlab/data_builder/pipeline_spec.rb
index f13041e498c..9ca960502c8 100644
--- a/spec/lib/gitlab/data_builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/data_builder/pipeline_spec.rb
@@ -26,6 +26,7 @@ describe Gitlab::DataBuilder::Pipeline do
it { expect(attributes[:tag]).to eq(pipeline.tag) }
it { expect(attributes[:id]).to eq(pipeline.id) }
it { expect(attributes[:status]).to eq(pipeline.status) }
+ it { expect(attributes[:detailed_status]).to eq('passed') }
it { expect(build_data).to be_a(Hash) }
it { expect(build_data[:id]).to eq(build.id) }
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index a6341cd509b..67d898e787e 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -500,4 +500,33 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
end
end
+
+ describe '#load_all_data!' do
+ let(:full_data) { 'abcd' }
+ let(:blob) { Gitlab::Git::Blob.new(name: 'test', size: 4, data: 'abc') }
+
+ subject { blob.load_all_data!(repository) }
+
+ it 'loads missing data' do
+ expect(Gitlab::GitalyClient).to receive(:migrate)
+ .with(:git_blob_load_all_data).and_return(full_data)
+
+ subject
+
+ expect(blob.data).to eq(full_data)
+ end
+
+ context 'with a fully loaded blob' do
+ let(:blob) { Gitlab::Git::Blob.new(name: 'test', size: 4, data: full_data) }
+
+ it "doesn't perform any loading" do
+ expect(Gitlab::GitalyClient).not_to receive(:migrate)
+ .with(:git_blob_load_all_data)
+
+ subject
+
+ expect(blob.data).to eq(full_data)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/git/branch_spec.rb b/spec/lib/gitlab/git/branch_spec.rb
index 708870060e7..a19155ed5b0 100644
--- a/spec/lib/gitlab/git/branch_spec.rb
+++ b/spec/lib/gitlab/git/branch_spec.rb
@@ -59,5 +59,69 @@ describe Gitlab::Git::Branch, seed_helper: true do
it { expect(branch.dereferenced_target.sha).to eq(SeedRepo::LastCommit::ID) }
end
+ context 'with active, stale and future branches' do
+ let(:repository) do
+ Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
+ end
+
+ let(:user) { create(:user) }
+ let(:committer) do
+ Gitlab::Git.committer_hash(email: user.email, name: user.name)
+ end
+ let(:params) do
+ parents = [repository.rugged.head.target]
+ tree = parents.first.tree
+
+ {
+ message: 'commit message',
+ author: committer,
+ committer: committer,
+ tree: tree,
+ parents: parents
+ }
+ 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 } }
+
+ before do
+ repository.create_branch('stale-1', stale_sha)
+ repository.create_branch('active-1', active_sha)
+ repository.create_branch('future-1', future_sha)
+ end
+
+ after do
+ ensure_seeds
+ end
+
+ describe 'examine if the branch is active or stale' do
+ let(:stale_branch) { repository.find_branch('stale-1') }
+ let(:active_branch) { repository.find_branch('active-1') }
+ let(:future_branch) { repository.find_branch('future-1') }
+
+ describe '#active?' do
+ it { expect(stale_branch.active?).to be_falsey }
+ it { expect(active_branch.active?).to be_truthy }
+ it { expect(future_branch.active?).to be_truthy }
+ end
+
+ describe '#stale?' do
+ it { expect(stale_branch.stale?).to be_truthy }
+ it { expect(active_branch.stale?).to be_falsey }
+ it { expect(future_branch.stale?).to be_falsey }
+ end
+
+ describe '#state' do
+ it { expect(stale_branch.state).to eq(:stale) }
+ it { expect(active_branch.state).to eq(:active) }
+ it { expect(future_branch.state).to eq(:active) }
+ end
+ end
+ end
+
it { expect(repository.branches.size).to eq(SeedRepo::Repo::BRANCHES.size) }
+
+ def create_commit
+ repository.create_commit(params.merge(committer: committer.merge(time: Time.now)))
+ end
end
diff --git a/spec/lib/gitlab/git/gitlab_projects_spec.rb b/spec/lib/gitlab/git/gitlab_projects_spec.rb
index f4b964e1ee9..45bcd730332 100644
--- a/spec/lib/gitlab/git/gitlab_projects_spec.rb
+++ b/spec/lib/gitlab/git/gitlab_projects_spec.rb
@@ -61,10 +61,11 @@ describe Gitlab::Git::GitlabProjects do
let(:remote_name) { 'remote-name' }
let(:branch_name) { 'master' }
let(:force) { false }
+ let(:prune) { true }
let(:tags) { true }
- let(:args) { { force: force, tags: tags }.merge(extra_args) }
+ let(:args) { { force: force, tags: tags, prune: prune }.merge(extra_args) }
let(:extra_args) { {} }
- let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --tags) }
+ let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --tags) }
subject { gl_projects.fetch_remote(remote_name, 600, args) }
@@ -97,7 +98,7 @@ describe Gitlab::Git::GitlabProjects do
context 'with --force' do
let(:force) { true }
- let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --force --tags) }
+ let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --force --tags) }
it 'executes the command with forced option' do
stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
@@ -108,7 +109,18 @@ describe Gitlab::Git::GitlabProjects do
context 'with --no-tags' do
let(:tags) { false }
- let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --no-tags) }
+ let(:cmd) { %W(git fetch #{remote_name} --quiet --prune --no-tags) }
+
+ it 'executes the command' do
+ stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
+
+ is_expected.to be_truthy
+ end
+ end
+
+ context 'with no prune' do
+ let(:prune) { false }
+ let(:cmd) { %W(git fetch #{remote_name} --quiet --tags) }
it 'executes the command' do
stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
diff --git a/spec/lib/gitlab/git/lfs_changes_spec.rb b/spec/lib/gitlab/git/lfs_changes_spec.rb
index c9007d7d456..d0dd8c6303f 100644
--- a/spec/lib/gitlab/git/lfs_changes_spec.rb
+++ b/spec/lib/gitlab/git/lfs_changes_spec.rb
@@ -7,34 +7,36 @@ describe Gitlab::Git::LfsChanges do
subject { described_class.new(project.repository, newrev) }
- describe 'new_pointers' do
- before do
- allow_any_instance_of(Gitlab::Git::RevList).to receive(:new_objects).and_yield([blob_object_id])
+ describe '#new_pointers' do
+ shared_examples 'new pointers' do
+ it 'filters new objects to find lfs pointers' do
+ expect(subject.new_pointers(not_in: []).first.id).to eq(blob_object_id)
+ end
+
+ it 'limits new_objects using object_limit' do
+ expect(subject.new_pointers(object_limit: 1)).to eq([])
+ end
end
- it 'uses rev-list to find new objects' do
- rev_list = double
- allow(Gitlab::Git::RevList).to receive(:new).and_return(rev_list)
-
- expect(rev_list).to receive(:new_objects).and_return([])
-
- subject.new_pointers
+ context 'with gitaly enabled' do
+ it_behaves_like 'new pointers'
end
- it 'filters new objects to find lfs pointers' do
- expect(Gitlab::Git::Blob).to receive(:batch_lfs_pointers).with(project.repository, [blob_object_id])
+ context 'with gitaly disabled', :skip_gitaly_mock do
+ it_behaves_like 'new pointers'
- subject.new_pointers(object_limit: 1)
- end
+ it 'uses rev-list to find new objects' do
+ rev_list = double
+ allow(Gitlab::Git::RevList).to receive(:new).and_return(rev_list)
- it 'limits new_objects using object_limit' do
- expect(Gitlab::Git::Blob).to receive(:batch_lfs_pointers).with(project.repository, [])
+ expect(rev_list).to receive(:new_objects).and_return([])
- subject.new_pointers(object_limit: 0)
+ subject.new_pointers
+ end
end
end
- describe 'all_pointers' do
+ describe '#all_pointers', :skip_gitaly_mock do
it 'uses rev-list to find all objects' do
rev_list = double
allow(Gitlab::Git::RevList).to receive(:new).and_return(rev_list)
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 25defb98b7c..52c9876cbb6 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -751,255 +751,263 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe "#log" do
- let(:commit_with_old_name) do
- Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id)
- end
- let(:commit_with_new_name) do
- Gitlab::Git::Commit.decorate(repository, @commit_with_new_name_id)
- end
- let(:rename_commit) do
- Gitlab::Git::Commit.decorate(repository, @rename_commit_id)
- end
-
- before(:context) do
- # Add new commits so that there's a renamed file in the commit history
- repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
- @commit_with_old_name_id = new_commit_edit_old_file(repo)
- @rename_commit_id = new_commit_move_file(repo)
- @commit_with_new_name_id = new_commit_edit_new_file(repo)
- end
-
- after(:context) do
- # Erase our commits so other tests get the original repo
- repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
- repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID)
- end
-
- context "where 'follow' == true" do
- let(:options) { { ref: "master", follow: true } }
+ shared_examples 'repository log' do
+ let(:commit_with_old_name) do
+ Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id)
+ end
+ let(:commit_with_new_name) do
+ Gitlab::Git::Commit.decorate(repository, @commit_with_new_name_id)
+ end
+ let(:rename_commit) do
+ Gitlab::Git::Commit.decorate(repository, @rename_commit_id)
+ end
- context "and 'path' is a directory" do
- it "does not follow renames" do
- log_commits = repository.log(options.merge(path: "encoding"))
+ before(:context) do
+ # Add new commits so that there's a renamed file in the commit history
+ repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
+ @commit_with_old_name_id = new_commit_edit_old_file(repo)
+ @rename_commit_id = new_commit_move_file(repo)
+ @commit_with_new_name_id = new_commit_edit_new_file(repo)
+ end
- aggregate_failures do
- expect(log_commits).to include(commit_with_new_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).not_to include(commit_with_old_name)
- end
- end
+ after(:context) do
+ # Erase our commits so other tests get the original repo
+ repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
+ repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID)
end
- context "and 'path' is a file that matches the new filename" do
- context 'without offset' do
- it "follows renames" do
- log_commits = repository.log(options.merge(path: "encoding/CHANGELOG"))
+ context "where 'follow' == true" do
+ let(:options) { { ref: "master", follow: true } }
+
+ context "and 'path' is a directory" do
+ it "does not follow renames" do
+ log_commits = repository.log(options.merge(path: "encoding"))
aggregate_failures do
expect(log_commits).to include(commit_with_new_name)
expect(log_commits).to include(rename_commit)
- expect(log_commits).to include(commit_with_old_name)
+ expect(log_commits).not_to include(commit_with_old_name)
end
end
end
- context 'with offset=1' do
- it "follows renames and skip the latest commit" do
- log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1))
+ context "and 'path' is a file that matches the new filename" do
+ context 'without offset' do
+ it "follows renames" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG"))
- aggregate_failures do
- expect(log_commits).not_to include(commit_with_new_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).to include(commit_with_old_name)
+ aggregate_failures do
+ expect(log_commits).to include(commit_with_new_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
end
end
- end
- context 'with offset=1', 'and limit=1' do
- it "follows renames, skip the latest commit and return only one commit" do
- log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1, limit: 1))
+ context 'with offset=1' do
+ it "follows renames and skip the latest commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1))
- expect(log_commits).to contain_exactly(rename_commit)
+ aggregate_failures do
+ expect(log_commits).not_to include(commit_with_new_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
+ end
end
- end
- context 'with offset=1', 'and limit=2' do
- it "follows renames, skip the latest commit and return only two commits" do
- log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1, limit: 2))
+ context 'with offset=1', 'and limit=1' do
+ it "follows renames, skip the latest commit and return only one commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1, limit: 1))
- aggregate_failures do
- expect(log_commits).to contain_exactly(rename_commit, commit_with_old_name)
+ expect(log_commits).to contain_exactly(rename_commit)
end
end
- end
- context 'with offset=2' do
- it "follows renames and skip the latest commit" do
- log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2))
+ context 'with offset=1', 'and limit=2' do
+ it "follows renames, skip the latest commit and return only two commits" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1, limit: 2))
- aggregate_failures do
- expect(log_commits).not_to include(commit_with_new_name)
- expect(log_commits).not_to include(rename_commit)
- expect(log_commits).to include(commit_with_old_name)
+ aggregate_failures do
+ expect(log_commits).to contain_exactly(rename_commit, commit_with_old_name)
+ end
end
end
- end
- context 'with offset=2', 'and limit=1' do
- it "follows renames, skip the two latest commit and return only one commit" do
- log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2, limit: 1))
+ context 'with offset=2' do
+ it "follows renames and skip the latest commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2))
- expect(log_commits).to contain_exactly(commit_with_old_name)
+ aggregate_failures do
+ expect(log_commits).not_to include(commit_with_new_name)
+ expect(log_commits).not_to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
+ end
+ end
+
+ context 'with offset=2', 'and limit=1' do
+ it "follows renames, skip the two latest commit and return only one commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2, limit: 1))
+
+ expect(log_commits).to contain_exactly(commit_with_old_name)
+ end
+ end
+
+ context 'with offset=2', 'and limit=2' do
+ it "follows renames, skip the two latest commit and return only one commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2, limit: 2))
+
+ aggregate_failures do
+ expect(log_commits).not_to include(commit_with_new_name)
+ expect(log_commits).not_to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
+ end
end
end
- context 'with offset=2', 'and limit=2' do
- it "follows renames, skip the two latest commit and return only one commit" do
- log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2, limit: 2))
+ context "and 'path' is a file that matches the old filename" do
+ it "does not follow renames" do
+ log_commits = repository.log(options.merge(path: "CHANGELOG"))
aggregate_failures do
expect(log_commits).not_to include(commit_with_new_name)
- expect(log_commits).not_to include(rename_commit)
+ expect(log_commits).to include(rename_commit)
expect(log_commits).to include(commit_with_old_name)
end
end
end
- end
- context "and 'path' is a file that matches the old filename" do
- it "does not follow renames" do
- log_commits = repository.log(options.merge(path: "CHANGELOG"))
+ context "unknown ref" do
+ it "returns an empty array" do
+ log_commits = repository.log(options.merge(ref: 'unknown'))
- aggregate_failures do
- expect(log_commits).not_to include(commit_with_new_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).to include(commit_with_old_name)
+ expect(log_commits).to eq([])
end
end
end
- context "unknown ref" do
- it "returns an empty array" do
- log_commits = repository.log(options.merge(ref: 'unknown'))
-
- expect(log_commits).to eq([])
- end
- end
- end
+ context "where 'follow' == false" do
+ options = { follow: false }
- context "where 'follow' == false" do
- options = { follow: false }
+ context "and 'path' is a directory" do
+ let(:log_commits) do
+ repository.log(options.merge(path: "encoding"))
+ end
- context "and 'path' is a directory" do
- let(:log_commits) do
- repository.log(options.merge(path: "encoding"))
+ it "does not follow renames" do
+ expect(log_commits).to include(commit_with_new_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).not_to include(commit_with_old_name)
+ end
end
- it "does not follow renames" do
- expect(log_commits).to include(commit_with_new_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).not_to include(commit_with_old_name)
- end
- end
+ context "and 'path' is a file that matches the new filename" do
+ let(:log_commits) do
+ repository.log(options.merge(path: "encoding/CHANGELOG"))
+ end
- context "and 'path' is a file that matches the new filename" do
- let(:log_commits) do
- repository.log(options.merge(path: "encoding/CHANGELOG"))
+ it "does not follow renames" do
+ expect(log_commits).to include(commit_with_new_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).not_to include(commit_with_old_name)
+ end
end
- it "does not follow renames" do
- expect(log_commits).to include(commit_with_new_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).not_to include(commit_with_old_name)
- end
- end
+ context "and 'path' is a file that matches the old filename" do
+ let(:log_commits) do
+ repository.log(options.merge(path: "CHANGELOG"))
+ end
- context "and 'path' is a file that matches the old filename" do
- let(:log_commits) do
- repository.log(options.merge(path: "CHANGELOG"))
+ it "does not follow renames" do
+ expect(log_commits).to include(commit_with_old_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).not_to include(commit_with_new_name)
+ end
end
- it "does not follow renames" do
- expect(log_commits).to include(commit_with_old_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).not_to include(commit_with_new_name)
+ context "and 'path' includes a directory that used to be a file" do
+ let(:log_commits) do
+ repository.log(options.merge(ref: "refs/heads/fix-blob-path", path: "files/testdir/file.txt"))
+ end
+
+ it "returns a list of commits" do
+ expect(log_commits.size).to eq(1)
+ end
end
end
- context "and 'path' includes a directory that used to be a file" do
- let(:log_commits) do
- repository.log(options.merge(ref: "refs/heads/fix-blob-path", path: "files/testdir/file.txt"))
- end
+ context "where provides 'after' timestamp" do
+ options = { after: Time.iso8601('2014-03-03T20:15:01+00:00') }
- it "returns a list of commits" do
- expect(log_commits.size).to eq(1)
+ it "should returns commits on or after that timestamp" do
+ commits = repository.log(options)
+
+ expect(commits.size).to be > 0
+ expect(commits).to satisfy do |commits|
+ commits.all? { |commit| commit.committed_date >= options[:after] }
+ end
end
end
- end
- context "where provides 'after' timestamp" do
- options = { after: Time.iso8601('2014-03-03T20:15:01+00:00') }
+ context "where provides 'before' timestamp" do
+ options = { before: Time.iso8601('2014-03-03T20:15:01+00:00') }
- it "should returns commits on or after that timestamp" do
- commits = repository.log(options)
+ it "should returns commits on or before that timestamp" do
+ commits = repository.log(options)
- expect(commits.size).to be > 0
- expect(commits).to satisfy do |commits|
- commits.all? { |commit| commit.committed_date >= options[:after] }
+ expect(commits.size).to be > 0
+ expect(commits).to satisfy do |commits|
+ commits.all? { |commit| commit.committed_date <= options[:before] }
+ end
end
end
- end
- context "where provides 'before' timestamp" do
- options = { before: Time.iso8601('2014-03-03T20:15:01+00:00') }
+ context 'when multiple paths are provided' do
+ let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } }
- it "should returns commits on or before that timestamp" do
- commits = repository.log(options)
-
- expect(commits.size).to be > 0
- expect(commits).to satisfy do |commits|
- commits.all? { |commit| commit.committed_date <= options[:before] }
+ def commit_files(commit)
+ commit.rugged_diff_from_parent.deltas.flat_map do |delta|
+ [delta.old_file[:path], delta.new_file[:path]].uniq.compact
+ end
end
- end
- end
- context 'when multiple paths are provided' do
- let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } }
+ it 'only returns commits matching at least one path' do
+ commits = repository.log(options)
- def commit_files(commit)
- commit.rugged_diff_from_parent.deltas.flat_map do |delta|
- [delta.old_file[:path], delta.new_file[:path]].uniq.compact
+ expect(commits.size).to be > 0
+ expect(commits).to satisfy do |commits|
+ commits.none? { |commit| (commit_files(commit) & options[:path]).empty? }
+ end
end
end
- it 'only returns commits matching at least one path' do
- commits = repository.log(options)
+ context 'limit validation' do
+ where(:limit) do
+ [0, nil, '', 'foo']
+ end
- expect(commits.size).to be > 0
- expect(commits).to satisfy do |commits|
- commits.none? { |commit| (commit_files(commit) & options[:path]).empty? }
+ with_them do
+ it { expect { repository.log(limit: limit) }.to raise_error(ArgumentError) }
end
end
- end
- context 'limit validation' do
- where(:limit) do
- [0, nil, '', 'foo']
- end
+ context 'with all' do
+ it 'returns a list of commits' do
+ commits = repository.log({ all: true, limit: 50 })
- with_them do
- it { expect { repository.log(limit: limit) }.to raise_error(ArgumentError) }
+ expect(commits.size).to eq(37)
+ end
end
end
- context 'with all' do
- let(:options) { { all: true, limit: 50 } }
-
- it 'returns a list of commits' do
- commits = repository.log(options)
+ context 'when Gitaly find_commits feature is enabled' do
+ it_behaves_like 'repository log'
+ end
- expect(commits.size).to eq(37)
- end
+ context 'when Gitaly find_commits feature is disabled', :disable_gitaly do
+ it_behaves_like 'repository log'
end
end
@@ -1136,14 +1144,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(repository.count_commits(options)).to eq(10)
end
end
- end
-
- context 'when Gitaly count_commits feature is enabled' do
- it_behaves_like 'extended commit counting'
- end
-
- context 'when Gitaly count_commits feature is disabled', :skip_gitaly_mock do
- it_behaves_like 'extended commit counting'
context "with all" do
it "returns the number of commits in the whole repository" do
@@ -1155,10 +1155,18 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'without all or ref being specified' do
it "raises an ArgumentError" do
- expect { repository.count_commits({}) }.to raise_error(ArgumentError, "Please specify a valid ref or set the 'all' attribute to true")
+ expect { repository.count_commits({}) }.to raise_error(ArgumentError)
end
end
end
+
+ context 'when Gitaly count_commits feature is enabled' do
+ it_behaves_like 'extended commit counting'
+ end
+
+ context 'when Gitaly count_commits feature is disabled', :disable_gitaly do
+ it_behaves_like 'extended commit counting'
+ end
end
describe '#autocrlf' do
diff --git a/spec/lib/gitlab/gitaly_client/blob_service_spec.rb b/spec/lib/gitlab/gitaly_client/blob_service_spec.rb
new file mode 100644
index 00000000000..a2770ef2fe4
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/blob_service_spec.rb
@@ -0,0 +1,60 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::BlobService do
+ let(:project) { create(:project, :repository) }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.disk_path + '.git' }
+ let(:repository) { project.repository }
+ let(:client) { described_class.new(repository) }
+
+ describe '#get_new_lfs_pointers' do
+ let(:revision) { 'master' }
+ let(:limit) { 5 }
+ let(:not_in) { ['branch-a', 'branch-b'] }
+ let(:expected_params) do
+ { revision: revision, limit: limit, not_in_refs: not_in, not_in_all: false }
+ end
+
+ subject { client.get_new_lfs_pointers(revision, limit, not_in) }
+
+ it 'sends a get_new_lfs_pointers message' do
+ expect_any_instance_of(Gitaly::BlobService::Stub)
+ .to receive(:get_new_lfs_pointers)
+ .with(gitaly_request_with_params(expected_params), kind_of(Hash))
+ .and_return([])
+
+ subject
+ end
+
+ context 'with not_in = :all' do
+ let(:not_in) { :all }
+ let(:expected_params) do
+ { revision: revision, limit: limit, not_in_refs: [], not_in_all: true }
+ end
+
+ it 'sends the correct message' do
+ expect_any_instance_of(Gitaly::BlobService::Stub)
+ .to receive(:get_new_lfs_pointers)
+ .with(gitaly_request_with_params(expected_params), kind_of(Hash))
+ .and_return([])
+
+ subject
+ end
+ end
+ end
+
+ describe '#get_all_lfs_pointers' do
+ let(:revision) { 'master' }
+
+ subject { client.get_all_lfs_pointers(revision) }
+
+ it 'sends a get_all_lfs_pointers message' do
+ expect_any_instance_of(Gitaly::BlobService::Stub)
+ .to receive(:get_all_lfs_pointers)
+ .with(gitaly_request_with_params(revision: revision), kind_of(Hash))
+ .and_return([])
+
+ subject
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
index c50e73cecfc..1c41dbcb9ef 100644
--- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -85,6 +85,20 @@ describe Gitlab::GitalyClient::RepositoryService do
end
end
+ describe '#fetch_remote' do
+ let(:ssh_auth) { double(:ssh_auth, ssh_import?: true, ssh_key_auth?: false, ssh_known_hosts: nil) }
+ let(:import_url) { 'ssh://example.com' }
+
+ it 'sends a fetch_remote_request message' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:fetch_remote)
+ .with(gitaly_request_with_params(no_prune: false), kind_of(Hash))
+ .and_return(double(value: true))
+
+ client.fetch_remote(import_url, ssh_auth: ssh_auth, forced: false, no_tags: false, timeout: 60)
+ end
+ end
+
describe '#rebase_in_progress?' do
let(:rebase_id) { 1 }
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 41a55027f4d..bece82e531a 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -277,6 +277,8 @@ project:
- fork_network
- custom_attributes
- lfs_file_locks
+- project_badges
+- source_of_merge_requests
award_emoji:
- awardable
- user
@@ -293,3 +295,5 @@ issue_assignees:
- assignee
lfs_file_locks:
- user
+project_badges:
+- project
diff --git a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb
index a93a921e459..4897d604bc1 100644
--- a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::AvatarRestorer do
include UploadHelpers
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
+ let(:shared) { project.import_export_shared }
let(:project) { create(:project) }
before do
diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
index 3fb5ddde8b5..f40d4bc2d08 100644
--- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::ImportExport::AvatarSaver do
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
+ let(:shared) { project.import_export_shared }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:project_with_avatar) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
let(:project) { create(:project) }
diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb
index 5cdc5138fda..58b9fb06cc5 100644
--- a/spec/lib/gitlab/import_export/file_importer_spec.rb
+++ b/spec/lib/gitlab/import_export/file_importer_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::ImportExport::FileImporter do
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
+ let(:shared) { Gitlab::ImportExport::Shared.new(nil) }
let(:export_path) { "#{Dir.tmpdir}/file_importer_spec" }
let(:valid_file) { "#{shared.export_path}/valid.json" }
let(:symlink_file) { "#{shared.export_path}/invalid.json" }
@@ -12,6 +12,7 @@ describe Gitlab::ImportExport::FileImporter do
stub_const('Gitlab::ImportExport::FileImporter::MAX_RETRIES', 0)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
allow_any_instance_of(Gitlab::ImportExport::CommandLineUtil).to receive(:untar_zxf).and_return(true)
+ allow_any_instance_of(Gitlab::ImportExport::Shared).to receive(:relative_archive_path).and_return('test')
allow(SecureRandom).to receive(:hex).and_return('abcd')
setup_files
end
diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb
index cfb15ee7e8b..17e06a6a83f 100644
--- a/spec/lib/gitlab/import_export/fork_spec.rb
+++ b/spec/lib/gitlab/import_export/fork_spec.rb
@@ -7,7 +7,7 @@ describe 'forked project import' do
let!(:project_with_repo) { create(:project, :repository, name: 'test-repo-restorer', path: 'test-repo-restorer') }
let!(:project) { create(:project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
+ let(:shared) { project.import_export_shared }
let(:forked_from_project) { create(:project, :repository) }
let(:forked_project) { fork_project(project_with_repo, nil, repository: true) }
let(:repo_saver) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) }
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index b6c1f0c81cb..62ef93f847a 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -14,8 +14,7 @@
"template": false,
"description": "",
"type": "ProjectLabel",
- "priorities": [
- ]
+ "priorities": []
},
{
"id": 3,
@@ -160,9 +159,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 352,
@@ -184,9 +181,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 353,
@@ -208,9 +203,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 354,
@@ -232,9 +225,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 355,
@@ -256,9 +247,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 356,
@@ -280,9 +269,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 357,
@@ -304,9 +291,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 358,
@@ -328,9 +313,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -395,9 +378,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 360,
@@ -419,9 +400,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 361,
@@ -443,9 +422,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 362,
@@ -467,9 +444,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 363,
@@ -491,9 +466,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 364,
@@ -515,9 +488,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 365,
@@ -539,9 +510,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 366,
@@ -563,9 +532,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -628,9 +595,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 368,
@@ -652,9 +617,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 369,
@@ -676,9 +639,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 370,
@@ -700,9 +661,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 371,
@@ -724,9 +683,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 372,
@@ -748,9 +705,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 373,
@@ -772,9 +727,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 374,
@@ -796,9 +749,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -840,9 +791,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 376,
@@ -864,9 +813,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 377,
@@ -888,9 +835,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 378,
@@ -912,9 +857,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 379,
@@ -936,9 +879,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 380,
@@ -960,9 +901,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 381,
@@ -984,9 +923,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 382,
@@ -1008,9 +945,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -1052,9 +987,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 384,
@@ -1076,9 +1009,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 385,
@@ -1100,9 +1031,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 386,
@@ -1124,9 +1053,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 387,
@@ -1148,9 +1075,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 388,
@@ -1172,9 +1097,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 389,
@@ -1196,9 +1119,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 390,
@@ -1220,9 +1141,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -1264,9 +1183,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 392,
@@ -1288,9 +1205,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 393,
@@ -1312,9 +1227,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 394,
@@ -1336,9 +1249,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 395,
@@ -1360,9 +1271,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 396,
@@ -1384,9 +1293,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 397,
@@ -1408,9 +1315,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 398,
@@ -1432,9 +1337,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -1476,9 +1379,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 400,
@@ -1500,9 +1401,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 401,
@@ -1524,9 +1423,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 402,
@@ -1548,9 +1445,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 403,
@@ -1572,9 +1467,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 404,
@@ -1596,9 +1489,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 405,
@@ -1620,9 +1511,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 406,
@@ -1644,9 +1533,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -1688,9 +1575,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 408,
@@ -1712,9 +1597,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 409,
@@ -1736,9 +1619,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 410,
@@ -1760,9 +1641,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 411,
@@ -1784,9 +1663,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 412,
@@ -1808,9 +1685,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 413,
@@ -1832,9 +1707,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 414,
@@ -1856,9 +1729,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -1900,9 +1771,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 416,
@@ -1924,9 +1793,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 417,
@@ -1948,9 +1815,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 418,
@@ -1972,9 +1837,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 419,
@@ -1996,9 +1859,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 420,
@@ -2020,9 +1881,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 421,
@@ -2044,9 +1903,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 422,
@@ -2068,9 +1925,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
},
@@ -2112,9 +1967,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 424,
@@ -2136,9 +1989,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 425,
@@ -2160,9 +2011,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 426,
@@ -2184,9 +2033,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 427,
@@ -2208,9 +2055,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 428,
@@ -2232,9 +2077,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 429,
@@ -2256,9 +2099,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 430,
@@ -2280,9 +2121,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
]
}
@@ -2378,12 +2217,8 @@
]
}
],
- "snippets": [
-
- ],
- "releases": [
-
- ],
+ "snippets": [],
+ "releases": [],
"project_members": [
{
"id": 36,
@@ -2515,9 +2350,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 672,
@@ -2539,9 +2372,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 673,
@@ -2563,9 +2394,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 674,
@@ -2587,9 +2416,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 675,
@@ -2611,9 +2438,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 676,
@@ -2635,9 +2460,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 677,
@@ -2659,9 +2482,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 678,
@@ -2683,9 +2504,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
@@ -2696,7 +2515,7 @@
"merge_request_diff_id": 27,
"relative_order": 0,
"sha": "bb5206fee213d983da88c47f9cf4cc6caf9c66dc",
- "message": "Feature conflcit added\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Feature conflcit added\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-08-06T08:35:52.000+02:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2708,7 +2527,7 @@
"merge_request_diff_id": 27,
"relative_order": 1,
"sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e",
- "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T10:01:38.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2720,7 +2539,7 @@
"merge_request_diff_id": 27,
"relative_order": 2,
"sha": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
- "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:57:31.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2732,7 +2551,7 @@
"merge_request_diff_id": 27,
"relative_order": 3,
"sha": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9",
- "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:54:21.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2744,7 +2563,7 @@
"merge_request_diff_id": 27,
"relative_order": 4,
"sha": "d14d6c0abdd253381df51a723d58691b2ee1ab08",
- "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:49:50.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2756,7 +2575,7 @@
"merge_request_diff_id": 27,
"relative_order": 5,
"sha": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8",
- "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:48:32.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2834,7 +2653,7 @@
{
"merge_request_diff_id": 27,
"relative_order": 5,
- "utf8_diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" =\u003e path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" =\u003e path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output \u003c\u003c stdout.read\n @cmd_output \u003c\u003c stderr.read\n",
+ "utf8_diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" => path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" => path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output << stdout.read\n @cmd_output << stderr.read\n",
"new_path": "files/ruby/popen.rb",
"old_path": "files/ruby/popen.rb",
"a_mode": "100644",
@@ -2958,9 +2777,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 680,
@@ -2982,9 +2799,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 681,
@@ -3006,9 +2821,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 682,
@@ -3030,9 +2843,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 683,
@@ -3054,9 +2865,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 684,
@@ -3078,9 +2887,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 685,
@@ -3102,9 +2909,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 686,
@@ -3126,9 +2931,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
@@ -3139,7 +2942,7 @@
"merge_request_diff_id": 26,
"sha": "0b4bc9a49b562e85de7cc9e834518ea6828729b9",
"relative_order": 0,
- "message": "Feature added\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Feature added\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:26:01.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -3237,9 +3040,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 778,
@@ -3261,9 +3062,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 779,
@@ -3285,9 +3084,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 780,
@@ -3309,9 +3106,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 781,
@@ -3333,9 +3128,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 782,
@@ -3357,9 +3150,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 783,
@@ -3381,9 +3172,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 784,
@@ -3405,9 +3194,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
@@ -3516,9 +3303,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 786,
@@ -3540,9 +3325,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 787,
@@ -3564,9 +3347,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 788,
@@ -3588,9 +3369,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 789,
@@ -3612,9 +3391,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 790,
@@ -3636,9 +3413,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 791,
@@ -3660,9 +3435,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 792,
@@ -3684,9 +3457,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
@@ -3877,7 +3648,7 @@
"merge_request_diff_id": 14,
"relative_order": 15,
"sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e",
- "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T10:01:38.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -3889,7 +3660,7 @@
"merge_request_diff_id": 14,
"relative_order": 16,
"sha": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
- "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:57:31.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -3901,7 +3672,7 @@
"merge_request_diff_id": 14,
"relative_order": 17,
"sha": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9",
- "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:54:21.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -3913,7 +3684,7 @@
"merge_request_diff_id": 14,
"relative_order": 18,
"sha": "d14d6c0abdd253381df51a723d58691b2ee1ab08",
- "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:49:50.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -3925,7 +3696,7 @@
"merge_request_diff_id": 14,
"relative_order": 19,
"sha": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8",
- "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:48:32.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -4016,7 +3787,7 @@
{
"merge_request_diff_id": 14,
"relative_order": 6,
- "utf8_diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\u003e\n+\u003csvg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n+ \u003c!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch --\u003e\n+ \u003ctitle\u003ewm\u003c/title\u003e\n+ \u003cdesc\u003eCreated with Sketch.\u003c/desc\u003e\n+ \u003cdefs\u003e\n+ \u003cpath id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"\u003e\u003c/path\u003e\n+ \u003c/defs\u003e\n+ \u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n+ \u003cpath d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\"\u003e\n+ \u003cg id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\"\u003e\n+ \u003cg id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\n+ \u003cpath d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g16\"\u003e\n+ \u003cg id=\"g18-Clipped\"\u003e\n+ \u003cmask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\"\u003e\n+ \u003cuse xlink:href=\"#path-1\"\u003e\u003c/use\u003e\n+ \u003c/mask\u003e\n+ \u003cg id=\"path22\"\u003e\u003c/g\u003e\n+ \u003cg id=\"g18\" mask=\"url(#mask-2)\"\u003e\n+ \u003cg transform=\"translate(382.736659, 312.879425)\"\u003e\n+ \u003cg id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\"\u003e\n+ \u003cpath d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\"\u003e\n+ \u003cpath d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\"\u003e\n+ \u003cpath d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\"\u003e\n+ \u003cpath d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cpath d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cpath d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\"\u003e\n+ \u003cpath d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\"\u003e\n+ \u003cpath d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path54\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\"\u003e\n+ \u003cpath d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cg id=\"path62\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\"\u003e\n+ \u003cpath d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path70\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\"\u003e\n+ \u003cpath d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cpath d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\"\u003e\n+ \u003cpath d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\"\u003e\n+ \u003cpath d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+\u003c/svg\u003e\n\\ No newline at end of file\n",
+ "utf8_diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n+<svg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->\n+ <title>wm</title>\n+ <desc>Created with Sketch.</desc>\n+ <defs>\n+ <path id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"></path>\n+ </defs>\n+ <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n+ <path d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\">\n+ <g id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\">\n+ <g id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\">\n+ <path d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"></path>\n+ </g>\n+ <g id=\"g16\">\n+ <g id=\"g18-Clipped\">\n+ <mask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\">\n+ <use xlink:href=\"#path-1\"></use>\n+ </mask>\n+ <g id=\"path22\"></g>\n+ <g id=\"g18\" mask=\"url(#mask-2)\">\n+ <g transform=\"translate(382.736659, 312.879425)\">\n+ <g id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\">\n+ <path d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\">\n+ <path d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\">\n+ <path d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\">\n+ <path d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <path d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <path d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\">\n+ <path d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\">\n+ <path d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path54\"></g>\n+ </g>\n+ <g id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\">\n+ <path d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <g id=\"path62\"></g>\n+ </g>\n+ <g id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\">\n+ <path d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path70\"></g>\n+ </g>\n+ <g id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\">\n+ <path d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <path d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\">\n+ <path d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\">\n+ <path d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+</svg>\n\\ No newline at end of file\n",
"new_path": "files/images/wm.svg",
"old_path": "files/images/wm.svg",
"a_mode": "0",
@@ -4042,7 +3813,7 @@
{
"merge_request_diff_id": 14,
"relative_order": 8,
- "utf8_diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" =\u003e path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" =\u003e path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output \u003c\u003c stdout.read\n @cmd_output \u003c\u003c stderr.read\n",
+ "utf8_diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" => path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" => path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output << stdout.read\n @cmd_output << stderr.read\n",
"new_path": "files/ruby/popen.rb",
"old_path": "files/ruby/popen.rb",
"a_mode": "100644",
@@ -4207,7 +3978,7 @@
},
"events": [
{
- "merge_request_diff_id": 14,
+ "merge_request_diff_id": 14,
"id": 529,
"target_type": "Note",
"target_id": 793,
@@ -4239,9 +4010,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 795,
@@ -4263,9 +4032,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 796,
@@ -4287,9 +4054,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 797,
@@ -4311,9 +4076,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 798,
@@ -4335,9 +4098,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 799,
@@ -4359,9 +4120,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 800,
@@ -4383,9 +4142,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
@@ -4603,7 +4360,7 @@
{
"merge_request_diff_id": 13,
"relative_order": 2,
- "utf8_diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\u003e\n+\u003csvg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n+ \u003c!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch --\u003e\n+ \u003ctitle\u003ewm\u003c/title\u003e\n+ \u003cdesc\u003eCreated with Sketch.\u003c/desc\u003e\n+ \u003cdefs\u003e\n+ \u003cpath id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"\u003e\u003c/path\u003e\n+ \u003c/defs\u003e\n+ \u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n+ \u003cpath d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\"\u003e\n+ \u003cg id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\"\u003e\n+ \u003cg id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\n+ \u003cpath d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g16\"\u003e\n+ \u003cg id=\"g18-Clipped\"\u003e\n+ \u003cmask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\"\u003e\n+ \u003cuse xlink:href=\"#path-1\"\u003e\u003c/use\u003e\n+ \u003c/mask\u003e\n+ \u003cg id=\"path22\"\u003e\u003c/g\u003e\n+ \u003cg id=\"g18\" mask=\"url(#mask-2)\"\u003e\n+ \u003cg transform=\"translate(382.736659, 312.879425)\"\u003e\n+ \u003cg id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\"\u003e\n+ \u003cpath d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\"\u003e\n+ \u003cpath d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\"\u003e\n+ \u003cpath d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\"\u003e\n+ \u003cpath d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cpath d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cpath d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\"\u003e\n+ \u003cpath d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\"\u003e\n+ \u003cpath d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path54\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\"\u003e\n+ \u003cpath d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cg id=\"path62\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\"\u003e\n+ \u003cpath d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path70\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\"\u003e\n+ \u003cpath d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cpath d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\"\u003e\n+ \u003cpath d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\"\u003e\n+ \u003cpath d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+\u003c/svg\u003e\n\\ No newline at end of file\n",
+ "utf8_diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n+<svg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->\n+ <title>wm</title>\n+ <desc>Created with Sketch.</desc>\n+ <defs>\n+ <path id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"></path>\n+ </defs>\n+ <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n+ <path d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\">\n+ <g id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\">\n+ <g id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\">\n+ <path d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"></path>\n+ </g>\n+ <g id=\"g16\">\n+ <g id=\"g18-Clipped\">\n+ <mask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\">\n+ <use xlink:href=\"#path-1\"></use>\n+ </mask>\n+ <g id=\"path22\"></g>\n+ <g id=\"g18\" mask=\"url(#mask-2)\">\n+ <g transform=\"translate(382.736659, 312.879425)\">\n+ <g id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\">\n+ <path d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\">\n+ <path d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\">\n+ <path d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\">\n+ <path d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <path d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <path d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\">\n+ <path d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\">\n+ <path d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path54\"></g>\n+ </g>\n+ <g id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\">\n+ <path d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <g id=\"path62\"></g>\n+ </g>\n+ <g id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\">\n+ <path d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path70\"></g>\n+ </g>\n+ <g id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\">\n+ <path d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <path d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\">\n+ <path d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\">\n+ <path d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+</svg>\n\\ No newline at end of file\n",
"new_path": "files/images/wm.svg",
"old_path": "files/images/wm.svg",
"a_mode": "0",
@@ -4740,9 +4497,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 802,
@@ -4764,9 +4519,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 803,
@@ -4788,9 +4541,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 804,
@@ -4812,9 +4563,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 805,
@@ -4836,9 +4585,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 806,
@@ -4860,9 +4607,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 807,
@@ -4884,9 +4629,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 808,
@@ -4908,9 +4651,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
@@ -5104,7 +4845,7 @@
{
"merge_request_diff_id": 12,
"relative_order": 2,
- "utf8_diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\u003e\n+\u003csvg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n+ \u003c!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch --\u003e\n+ \u003ctitle\u003ewm\u003c/title\u003e\n+ \u003cdesc\u003eCreated with Sketch.\u003c/desc\u003e\n+ \u003cdefs\u003e\n+ \u003cpath id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"\u003e\u003c/path\u003e\n+ \u003c/defs\u003e\n+ \u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n+ \u003cpath d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\"\u003e\n+ \u003cg id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\"\u003e\n+ \u003cg id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\n+ \u003cpath d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g16\"\u003e\n+ \u003cg id=\"g18-Clipped\"\u003e\n+ \u003cmask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\"\u003e\n+ \u003cuse xlink:href=\"#path-1\"\u003e\u003c/use\u003e\n+ \u003c/mask\u003e\n+ \u003cg id=\"path22\"\u003e\u003c/g\u003e\n+ \u003cg id=\"g18\" mask=\"url(#mask-2)\"\u003e\n+ \u003cg transform=\"translate(382.736659, 312.879425)\"\u003e\n+ \u003cg id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\"\u003e\n+ \u003cpath d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\"\u003e\n+ \u003cpath d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\"\u003e\n+ \u003cpath d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\"\u003e\n+ \u003cpath d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cpath d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cpath d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\"\u003e\n+ \u003cpath d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\"\u003e\n+ \u003cpath d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path54\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\"\u003e\n+ \u003cpath d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cg id=\"path62\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\"\u003e\n+ \u003cpath d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path70\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\"\u003e\n+ \u003cpath d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cpath d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\"\u003e\n+ \u003cpath d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\"\u003e\n+ \u003cpath d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+\u003c/svg\u003e\n\\ No newline at end of file\n",
+ "utf8_diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n+<svg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->\n+ <title>wm</title>\n+ <desc>Created with Sketch.</desc>\n+ <defs>\n+ <path id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"></path>\n+ </defs>\n+ <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n+ <path d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\">\n+ <g id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\">\n+ <g id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\">\n+ <path d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"></path>\n+ </g>\n+ <g id=\"g16\">\n+ <g id=\"g18-Clipped\">\n+ <mask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\">\n+ <use xlink:href=\"#path-1\"></use>\n+ </mask>\n+ <g id=\"path22\"></g>\n+ <g id=\"g18\" mask=\"url(#mask-2)\">\n+ <g transform=\"translate(382.736659, 312.879425)\">\n+ <g id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\">\n+ <path d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\">\n+ <path d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\">\n+ <path d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\">\n+ <path d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <path d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <path d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\">\n+ <path d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\">\n+ <path d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path54\"></g>\n+ </g>\n+ <g id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\">\n+ <path d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <g id=\"path62\"></g>\n+ </g>\n+ <g id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\">\n+ <path d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path70\"></g>\n+ </g>\n+ <g id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\">\n+ <path d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <path d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\">\n+ <path d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\">\n+ <path d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+</svg>\n\\ No newline at end of file\n",
"new_path": "files/images/wm.svg",
"old_path": "files/images/wm.svg",
"a_mode": "0",
@@ -5228,9 +4969,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 810,
@@ -5252,9 +4991,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 811,
@@ -5276,9 +5013,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 812,
@@ -5300,9 +5035,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 813,
@@ -5324,9 +5057,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 814,
@@ -5348,9 +5079,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 815,
@@ -5372,9 +5101,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 816,
@@ -5396,18 +5123,14 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
"id": 11,
"state": "empty",
- "merge_request_diff_commits": [
- ],
- "merge_request_diff_files": [
- ],
+ "merge_request_diff_commits": [],
+ "merge_request_diff_files": [],
"merge_request_id": 11,
"created_at": "2016-06-14T15:02:23.772Z",
"updated_at": "2016-06-14T15:02:23.833Z",
@@ -5482,9 +5205,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 818,
@@ -5506,9 +5227,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 819,
@@ -5530,9 +5249,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 820,
@@ -5554,9 +5271,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 821,
@@ -5578,9 +5293,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 822,
@@ -5602,9 +5315,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 823,
@@ -5626,9 +5337,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 824,
@@ -5650,9 +5359,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
@@ -5843,7 +5550,7 @@
"merge_request_diff_id": 10,
"relative_order": 16,
"sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e",
- "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T10:01:38.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -5855,7 +5562,7 @@
"merge_request_diff_id": 10,
"relative_order": 17,
"sha": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
- "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:57:31.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -5867,7 +5574,7 @@
"merge_request_diff_id": 10,
"relative_order": 18,
"sha": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9",
- "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:54:21.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -5879,7 +5586,7 @@
"merge_request_diff_id": 10,
"relative_order": 19,
"sha": "d14d6c0abdd253381df51a723d58691b2ee1ab08",
- "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:49:50.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -5891,7 +5598,7 @@
"merge_request_diff_id": 10,
"relative_order": 20,
"sha": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8",
- "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
+ "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"authored_date": "2014-02-27T09:48:32.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -5982,7 +5689,7 @@
{
"merge_request_diff_id": 10,
"relative_order": 6,
- "utf8_diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\u003e\n+\u003csvg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n+ \u003c!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch --\u003e\n+ \u003ctitle\u003ewm\u003c/title\u003e\n+ \u003cdesc\u003eCreated with Sketch.\u003c/desc\u003e\n+ \u003cdefs\u003e\n+ \u003cpath id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"\u003e\u003c/path\u003e\n+ \u003c/defs\u003e\n+ \u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n+ \u003cpath d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\"\u003e\n+ \u003cg id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\"\u003e\n+ \u003cg id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\n+ \u003cpath d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g16\"\u003e\n+ \u003cg id=\"g18-Clipped\"\u003e\n+ \u003cmask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\"\u003e\n+ \u003cuse xlink:href=\"#path-1\"\u003e\u003c/use\u003e\n+ \u003c/mask\u003e\n+ \u003cg id=\"path22\"\u003e\u003c/g\u003e\n+ \u003cg id=\"g18\" mask=\"url(#mask-2)\"\u003e\n+ \u003cg transform=\"translate(382.736659, 312.879425)\"\u003e\n+ \u003cg id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\"\u003e\n+ \u003cpath d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\"\u003e\n+ \u003cpath d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\"\u003e\n+ \u003cpath d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\"\u003e\n+ \u003cpath d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cpath d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cpath d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\"\u003e\n+ \u003cpath d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\"\u003e\n+ \u003cpath d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path54\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\"\u003e\n+ \u003cpath d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cg id=\"path62\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\"\u003e\n+ \u003cpath d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path70\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\"\u003e\n+ \u003cpath d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cpath d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\"\u003e\n+ \u003cpath d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\"\u003e\n+ \u003cpath d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+\u003c/svg\u003e\n\\ No newline at end of file\n",
+ "utf8_diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n+<svg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->\n+ <title>wm</title>\n+ <desc>Created with Sketch.</desc>\n+ <defs>\n+ <path id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"></path>\n+ </defs>\n+ <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n+ <path d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\">\n+ <g id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\">\n+ <g id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\">\n+ <path d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"></path>\n+ </g>\n+ <g id=\"g16\">\n+ <g id=\"g18-Clipped\">\n+ <mask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\">\n+ <use xlink:href=\"#path-1\"></use>\n+ </mask>\n+ <g id=\"path22\"></g>\n+ <g id=\"g18\" mask=\"url(#mask-2)\">\n+ <g transform=\"translate(382.736659, 312.879425)\">\n+ <g id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\">\n+ <path d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\">\n+ <path d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\">\n+ <path d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\">\n+ <path d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <path d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <path d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\">\n+ <path d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\">\n+ <path d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path54\"></g>\n+ </g>\n+ <g id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\">\n+ <path d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <g id=\"path62\"></g>\n+ </g>\n+ <g id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\">\n+ <path d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path70\"></g>\n+ </g>\n+ <g id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\">\n+ <path d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <path d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\">\n+ <path d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\">\n+ <path d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+</svg>\n\\ No newline at end of file\n",
"new_path": "files/images/wm.svg",
"old_path": "files/images/wm.svg",
"a_mode": "0",
@@ -6008,7 +5715,7 @@
{
"merge_request_diff_id": 10,
"relative_order": 8,
- "utf8_diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" =\u003e path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" =\u003e path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output \u003c\u003c stdout.read\n @cmd_output \u003c\u003c stderr.read\n",
+ "utf8_diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" => path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" => path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output << stdout.read\n @cmd_output << stderr.read\n",
"new_path": "files/ruby/popen.rb",
"old_path": "files/ruby/popen.rb",
"a_mode": "100644",
@@ -6171,9 +5878,7 @@
"author": {
"name": "User 4"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 826,
@@ -6195,9 +5900,7 @@
"author": {
"name": "User 3"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 827,
@@ -6219,9 +5922,7 @@
"author": {
"name": "User 0"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 828,
@@ -6243,9 +5944,7 @@
"author": {
"name": "Ottis Schuster II"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 829,
@@ -6267,9 +5966,7 @@
"author": {
"name": "Rhett Emmerich IV"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 830,
@@ -6291,9 +5988,7 @@
"author": {
"name": "Burdette Bernier"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 831,
@@ -6315,9 +6010,7 @@
"author": {
"name": "Ari Wintheiser"
},
- "events": [
-
- ]
+ "events": []
},
{
"id": 832,
@@ -6339,9 +6032,7 @@
"author": {
"name": "Administrator"
},
- "events": [
-
- ]
+ "events": []
}
],
"merge_request_diff": {
@@ -6953,9 +6644,7 @@
"updated_at": "2017-01-16T15:25:28.637Z"
}
],
- "deploy_keys": [
-
- ],
+ "deploy_keys": [],
"services": [
{
"id": 100,
@@ -6964,9 +6653,7 @@
"created_at": "2016-06-14T15:01:51.315Z",
"updated_at": "2016-06-14T15:01:51.315Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7008,9 +6695,7 @@
"created_at": "2016-06-14T15:01:51.289Z",
"updated_at": "2016-06-14T15:01:51.289Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7030,9 +6715,7 @@
"created_at": "2016-06-14T15:01:51.277Z",
"updated_at": "2016-06-14T15:01:51.277Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7052,9 +6735,7 @@
"created_at": "2016-06-14T15:01:51.267Z",
"updated_at": "2016-06-14T15:01:51.267Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7097,9 +6778,7 @@
"created_at": "2016-06-14T15:01:51.232Z",
"updated_at": "2016-06-14T15:01:51.232Z",
"active": true,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7141,9 +6820,7 @@
"created_at": "2016-06-14T15:01:51.202Z",
"updated_at": "2016-06-14T15:01:51.202Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7163,9 +6840,7 @@
"created_at": "2016-06-14T15:01:51.182Z",
"updated_at": "2016-06-14T15:01:51.182Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7185,9 +6860,7 @@
"created_at": "2016-06-14T15:01:51.166Z",
"updated_at": "2016-06-14T15:01:51.166Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7207,9 +6880,7 @@
"created_at": "2016-06-14T15:01:51.153Z",
"updated_at": "2016-06-14T15:01:51.153Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7229,9 +6900,7 @@
"created_at": "2016-06-14T15:01:51.139Z",
"updated_at": "2016-06-14T15:01:51.139Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7251,9 +6920,7 @@
"created_at": "2016-06-14T15:01:51.125Z",
"updated_at": "2016-06-14T15:01:51.125Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7273,9 +6940,7 @@
"created_at": "2016-06-14T15:01:51.113Z",
"updated_at": "2016-06-14T15:01:51.113Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7295,9 +6960,7 @@
"created_at": "2016-06-14T15:01:51.080Z",
"updated_at": "2016-06-14T15:01:51.080Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7317,9 +6980,7 @@
"created_at": "2016-06-14T15:01:51.067Z",
"updated_at": "2016-06-14T15:01:51.067Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7339,9 +7000,7 @@
"created_at": "2016-06-14T15:01:51.047Z",
"updated_at": "2016-06-14T15:01:51.047Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7361,9 +7020,7 @@
"created_at": "2016-06-14T15:01:51.031Z",
"updated_at": "2016-06-14T15:01:51.031Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7383,9 +7040,7 @@
"created_at": "2016-06-14T15:01:51.031Z",
"updated_at": "2016-06-14T15:01:51.031Z",
"active": false,
- "properties": {
-
- },
+ "properties": {},
"template": false,
"push_events": true,
"issues_events": true,
@@ -7399,9 +7054,7 @@
"type": "JenkinsDeprecatedService"
}
],
- "hooks": [
-
- ],
+ "hooks": [],
"protected_branches": [
{
"id": 1,
@@ -7475,5 +7128,25 @@
"key": "bar",
"value": "bar"
}
+ ],
+ "project_badges": [
+ {
+ "id": 1,
+ "created_at": "2017-10-19T15:36:23.466Z",
+ "updated_at": "2017-10-19T15:36:23.466Z",
+ "project_id": 5,
+ "type": "ProjectBadge",
+ "link_url": "http://www.example.com",
+ "image_url": "http://www.example.com"
+ },
+ {
+ "id": 2,
+ "created_at": "2017-10-19T15:36:23.466Z",
+ "updated_at": "2017-10-19T15:36:23.466Z",
+ "project_id": 5,
+ "type": "ProjectBadge",
+ "link_url": "http://www.example.com",
+ "image_url": "http://www.example.com"
+ }
]
}
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 d076007e4bc..f4e466d1296 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -7,9 +7,9 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
@user = create(:user)
RSpec::Mocks.with_temporary_scope do
- @shared = Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path')
- allow(@shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/')
@project = create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project')
+ @shared = @project.import_export_shared
+ allow(@shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/')
allow_any_instance_of(Repository).to receive(:fetch_ref).and_return(true)
allow_any_instance_of(Gitlab::Git::Repository).to receive(:branch_exists?).and_return(false)
@@ -129,6 +129,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
expect(@project.custom_attributes.count).to eq(2)
end
+ it 'has badges' do
+ expect(@project.project_badges.count).to eq(2)
+ end
+
it 'restores the correct service' do
expect(CustomIssueTrackerService.first).not_to be_nil
end
@@ -259,7 +263,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
context 'Light JSON' do
let(:user) { create(:user) }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') }
+ let(:shared) { project.import_export_shared }
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) }
let(:restored_project_json) { project_tree_restorer.restore }
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index 5804c45871e..3049491f0ae 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::ProjectTreeSaver do
describe 'saves the project tree into a json object' do
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
+ let(:shared) { project.import_export_shared }
let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:user) { create(:user) }
@@ -180,6 +180,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
expect(saved_project_json['custom_attributes'].count).to eq(2)
end
+ it 'has badges' do
+ expect(saved_project_json['project_badges'].count).to eq(2)
+ end
+
it 'does not complain about non UTF-8 characters in MR diff files' do
ActiveRecord::Base.connection.execute("UPDATE merge_request_diff_files SET diff = '---\n- :diff: !binary |-\n LS0tIC9kZXYvbnVsbAorKysgYi9pbWFnZXMvbnVjb3IucGRmCkBAIC0wLDAg\n KzEsMTY3OSBAQAorJVBERi0xLjUNJeLjz9MNCisxIDAgb2JqDTw8L01ldGFk\n YXR'")
@@ -288,6 +292,9 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
create(:project_custom_attribute, project: project)
create(:project_custom_attribute, project: project)
+ create(:project_badge, project: project)
+ create(:project_badge, project: project)
+
project
end
diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb
index e9f5273725d..1ef024d3078 100644
--- a/spec/lib/gitlab/import_export/reader_spec.rb
+++ b/spec/lib/gitlab/import_export/reader_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::ImportExport::Reader do
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: '') }
+ let(:shared) { Gitlab::ImportExport::Shared.new(nil) }
let(:test_config) { 'spec/support/import_export/import_export.yml' }
let(:project_tree_hash) do
{
diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
index c49af602a01..dc806d036ff 100644
--- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::ImportExport::RepoRestorer do
let!(:project_with_repo) { create(:project, :repository, name: 'test-repo-restorer', path: 'test-repo-restorer') }
let!(:project) { create(:project) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
+ let(:shared) { project.import_export_shared }
let(:bundler) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) }
let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) }
let(:restorer) do
diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb
index 44f972fe530..187ec8fcfa2 100644
--- a/spec/lib/gitlab/import_export/repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::ImportExport::RepoSaver do
let(:user) { create(:user) }
let!(:project) { create(:project, :public, name: 'searchable_project') }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
+ let(:shared) { project.import_export_shared }
let(:bundler) { described_class.new(project: project, shared: shared) }
before do
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index feaab6673cd..0b938892da5 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -168,6 +168,7 @@ MergeRequest:
- last_edited_by_id
- head_pipeline_id
- discussion_locked
+- allow_maintainer_to_push
MergeRequestDiff:
- id
- state
@@ -536,3 +537,12 @@ LfsFileLock:
- user_id
- project_id
- created_at
+Badge:
+- id
+- link_url
+- image_url
+- project_id
+- group_id
+- created_at
+- updated_at
+- type
diff --git a/spec/lib/gitlab/import_export/uploads_restorer_spec.rb b/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
index 8a3a244be21..acef97459b8 100644
--- a/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::UploadsRestorer do
describe 'bundle a project Git repo' do
let(:export_path) { "#{Dir.tmpdir}/uploads_saver_spec" }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
+ let(:shared) { project.import_export_shared }
before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
diff --git a/spec/lib/gitlab/import_export/uploads_saver_spec.rb b/spec/lib/gitlab/import_export/uploads_saver_spec.rb
index 177036c109b..1304d8fabfc 100644
--- a/spec/lib/gitlab/import_export/uploads_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/uploads_saver_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::ImportExport::UploadsSaver do
describe 'bundle a project Git repo' do
let(:export_path) { "#{Dir.tmpdir}/uploads_saver_spec" }
let(:file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
+ let(:shared) { project.import_export_shared }
before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
diff --git a/spec/lib/gitlab/import_export/version_checker_spec.rb b/spec/lib/gitlab/import_export/version_checker_spec.rb
index e7d50f75682..49d857d9483 100644
--- a/spec/lib/gitlab/import_export/version_checker_spec.rb
+++ b/spec/lib/gitlab/import_export/version_checker_spec.rb
@@ -2,12 +2,13 @@ require 'spec_helper'
include ImportExport::CommonUtil
describe Gitlab::ImportExport::VersionChecker do
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: '') }
+ let(:shared) { Gitlab::ImportExport::Shared.new(nil) }
describe 'bundle a project Git repo' do
let(:version) { Gitlab::ImportExport.version }
before do
+ allow_any_instance_of(Gitlab::ImportExport::Shared).to receive(:relative_archive_path).and_return('')
allow(File).to receive(:open).and_return(version)
end
diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
index 1d1e7e7f89a..d2bd8ccdf3f 100644
--- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::ImportExport::WikiRepoSaver do
let(:user) { create(:user) }
let!(:project) { create(:project, :public, name: 'searchable_project') }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
+ let(:shared) { project.import_export_shared }
let(:wiki_bundler) { described_class.new(project: project, shared: shared) }
let!(:project_wiki) { ProjectWiki.new(project, user) }
diff --git a/spec/lib/gitlab/import_export/wiki_restorer_spec.rb b/spec/lib/gitlab/import_export/wiki_restorer_spec.rb
index 81b654e9c5f..5c01ee0ebb8 100644
--- a/spec/lib/gitlab/import_export/wiki_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_restorer_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::ImportExport::WikiRestorer do
let!(:project_without_wiki) { create(:project) }
let!(:project) { create(:project) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) }
+ let(:shared) { project.import_export_shared }
let(:bundler) { Gitlab::ImportExport::WikiRepoSaver.new(project: project_with_wiki, shared: shared) }
let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) }
let(:restorer) do
diff --git a/spec/lib/gitlab/middleware/read_only_spec.rb b/spec/lib/gitlab/middleware/read_only_spec.rb
index 07ba11b93a3..39ec2f37a83 100644
--- a/spec/lib/gitlab/middleware/read_only_spec.rb
+++ b/spec/lib/gitlab/middleware/read_only_spec.rb
@@ -11,15 +11,17 @@ describe Gitlab::Middleware::ReadOnly do
RSpec::Matchers.define :disallow_request do
match do |middleware|
- flash = middleware.send(:rack_flash)
- flash['alert'] && flash['alert'].include?('You cannot do writing operations')
+ alert = middleware.env['rack.session'].to_hash
+ .dig('flash', 'flashes', 'alert')
+
+ alert&.include?('You cannot perform write operations')
end
end
RSpec::Matchers.define :disallow_request_in_json do
match do |response|
json_response = JSON.parse(response.body)
- response.body.include?('You cannot do writing operations') && json_response.key?('message')
+ response.body.include?('You cannot perform write operations') && json_response.key?('message')
end
end
@@ -34,10 +36,25 @@ describe Gitlab::Middleware::ReadOnly do
rack.to_app
end
- subject { described_class.new(fake_app) }
+ let(:observe_env) do
+ Module.new do
+ attr_reader :env
+
+ def call(env)
+ @env = env
+ super
+ end
+ end
+ end
let(:request) { Rack::MockRequest.new(rack_stack) }
+ subject do
+ described_class.new(fake_app).tap do |app|
+ app.extend(observe_env)
+ end
+ end
+
context 'normal requests to a read-only Gitlab instance' do
let(:fake_app) { lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['OK']] } }
diff --git a/spec/lib/gitlab/middleware/release_env_spec.rb b/spec/lib/gitlab/middleware/release_env_spec.rb
new file mode 100644
index 00000000000..5e3aa877409
--- /dev/null
+++ b/spec/lib/gitlab/middleware/release_env_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+
+describe Gitlab::Middleware::ReleaseEnv do
+ let(:inner_app) { double(:app, call: 'yay') }
+ let(:app) { described_class.new(inner_app) }
+ let(:env) { { 'action_controller.instance' => 'something' } }
+
+ describe '#call' do
+ it 'calls the app and clears the env' do
+ result = app.call(env)
+
+ expect(result).to eq('yay')
+ expect(env).to be_empty
+ end
+ end
+end
diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb
index 0697cb2def6..c7169717fc1 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
@@ -7,7 +7,7 @@ describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do
include_examples 'additional metrics query' do
let(:deployment) { create(:deployment, environment: environment) }
- let(:query_params) { [environment.id, deployment.id] }
+ let(:query_params) { [deployment.id] }
it 'queries using specific time' do
expect(client).to receive(:query_range).with(anything,
diff --git a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
index 84dc31d9732..ffe3ad85baa 100644
--- a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
+++ b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
@@ -31,7 +31,7 @@ describe Gitlab::Prometheus::Queries::DeploymentQuery do
expect(client).to receive(:query).with('avg(rate(container_cpu_usage_seconds_total{container_name!="POD",environment="environment-slug"}[30m])) * 100',
time: stop_time)
- expect(subject.query(environment.id, deployment.id)).to eq(memory_values: nil, memory_before: nil, memory_after: nil,
- cpu_values: nil, cpu_before: nil, cpu_after: nil)
+ expect(subject.query(deployment.id)).to eq(memory_values: nil, memory_before: nil, memory_after: nil,
+ cpu_values: nil, cpu_before: nil, cpu_after: nil)
end
end
diff --git a/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb b/spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb
index c95719eff1d..420218a695a 100644
--- a/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb
+++ b/spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Prometheus::Queries::MatchedMetricsQuery do
+describe Gitlab::Prometheus::Queries::MatchedMetricQuery do
include Prometheus::MetricBuilders
let(:metric_group_class) { Gitlab::Prometheus::MetricGroup }
diff --git a/spec/lib/gitlab/repository_cache_adapter_spec.rb b/spec/lib/gitlab/repository_cache_adapter_spec.rb
new file mode 100644
index 00000000000..85971f2a7ef
--- /dev/null
+++ b/spec/lib/gitlab/repository_cache_adapter_spec.rb
@@ -0,0 +1,76 @@
+require 'spec_helper'
+
+describe Gitlab::RepositoryCacheAdapter do
+ let(:project) { create(:project, :repository) }
+ let(:repository) { project.repository }
+ let(:cache) { repository.send(:cache) }
+
+ describe '#cache_method_output', :use_clean_rails_memory_store_caching do
+ let(:fallback) { 10 }
+
+ context 'with a non-existing repository' do
+ let(:project) { create(:project) } # No repository
+
+ subject do
+ repository.cache_method_output(:cats, fallback: fallback) do
+ repository.cats_call_stub
+ end
+ end
+
+ it 'returns the fallback value' do
+ expect(subject).to eq(fallback)
+ end
+
+ it 'avoids calling the original method' do
+ expect(repository).not_to receive(:cats_call_stub)
+
+ subject
+ end
+ end
+
+ context 'with a method throwing a non-existing-repository error' do
+ subject do
+ repository.cache_method_output(:cats, fallback: fallback) do
+ raise Gitlab::Git::Repository::NoRepository
+ end
+ end
+
+ it 'returns the fallback value' do
+ expect(subject).to eq(fallback)
+ end
+
+ it 'does not cache the data' do
+ subject
+
+ expect(repository.instance_variable_defined?(:@cats)).to eq(false)
+ expect(cache.exist?(:cats)).to eq(false)
+ end
+ end
+
+ context 'with an existing repository' do
+ it 'caches the output' do
+ object = double
+
+ expect(object).to receive(:number).once.and_return(10)
+
+ 2.times do
+ val = repository.cache_method_output(:cats) { object.number }
+
+ expect(val).to eq(10)
+ end
+
+ expect(repository.send(:cache).exist?(:cats)).to eq(true)
+ expect(repository.instance_variable_get(:@cats)).to eq(10)
+ end
+ end
+ end
+
+ describe '#expire_method_caches' do
+ it 'expires the caches of the given methods' do
+ expect(cache).to receive(:expire).with(:readme)
+ expect(cache).to receive(:expire).with(:gitignore)
+
+ repository.expire_method_caches(%i(readme gitignore))
+ end
+ end
+end
diff --git a/spec/lib/gitlab/repository_cache_spec.rb b/spec/lib/gitlab/repository_cache_spec.rb
new file mode 100644
index 00000000000..fc259cf1208
--- /dev/null
+++ b/spec/lib/gitlab/repository_cache_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Gitlab::RepositoryCache do
+ let(:backend) { double('backend').as_null_object }
+ let(:project) { create(:project) }
+ let(:repository) { project.repository }
+ let(:namespace) { "#{repository.full_path}:#{project.id}" }
+ let(:cache) { described_class.new(repository, backend: backend) }
+
+ describe '#cache_key' do
+ subject { cache.cache_key(:foo) }
+
+ it 'includes the namespace' do
+ expect(subject).to eq "foo:#{namespace}"
+ end
+
+ context 'with a given namespace' do
+ let(:extra_namespace) { 'my:data' }
+ let(:cache) do
+ described_class.new(repository, extra_namespace: extra_namespace,
+ backend: backend)
+ end
+
+ it 'includes the full namespace' do
+ expect(subject).to eq "foo:#{namespace}:#{extra_namespace}"
+ end
+ end
+ end
+
+ describe '#expire' do
+ it 'expires the given key from the cache' do
+ cache.expire(:foo)
+ expect(backend).to have_received(:delete).with("foo:#{namespace}")
+ end
+ end
+
+ describe '#fetch' do
+ it 'fetches the given key from the cache' do
+ cache.fetch(:bar)
+ expect(backend).to have_received(:fetch).with("bar:#{namespace}")
+ end
+
+ it 'accepts a block' do
+ p = -> {}
+
+ cache.fetch(:baz, &p)
+ expect(backend).to have_received(:fetch).with("baz:#{namespace}", &p)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 4506cbc3982..56b45d8da3c 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -508,8 +508,8 @@ describe Gitlab::Shell do
end
shared_examples 'fetch_remote' do |gitaly_on|
- def fetch_remote(ssh_auth = nil)
- gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', ssh_auth: ssh_auth)
+ def fetch_remote(ssh_auth = nil, prune = true)
+ gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', ssh_auth: ssh_auth, prune: prune)
end
def expect_gitlab_projects(fail = false, options = {})
@@ -555,27 +555,33 @@ describe Gitlab::Shell do
end
it 'returns true when the command succeeds' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
expect(fetch_remote).to be_truthy
end
+ it 'returns true when the command succeeds' do
+ expect_call(false, force: false, tags: true, prune: false)
+
+ expect(fetch_remote(nil, false)).to be_truthy
+ end
+
it 'raises an exception when the command fails' do
- expect_call(true, force: false, tags: true)
+ expect_call(true, force: false, tags: true, prune: true)
expect { fetch_remote }.to raise_error(Gitlab::Shell::Error)
end
it 'allows forced and no_tags to be changed' do
- expect_call(false, force: true, tags: false)
+ expect_call(false, force: true, tags: false, prune: true)
- result = gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', forced: true, no_tags: true)
+ result = gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', forced: true, no_tags: true, prune: true)
expect(result).to be_truthy
end
context 'SSH auth' do
it 'passes the SSH key if specified' do
- expect_call(false, force: false, tags: true, ssh_key: 'foo')
+ expect_call(false, force: false, tags: true, prune: true, ssh_key: 'foo')
ssh_auth = build_ssh_auth(ssh_key_auth?: true, ssh_private_key: 'foo')
@@ -583,7 +589,7 @@ describe Gitlab::Shell do
end
it 'does not pass an empty SSH key' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
ssh_auth = build_ssh_auth(ssh_key_auth: true, ssh_private_key: '')
@@ -591,7 +597,7 @@ describe Gitlab::Shell do
end
it 'does not pass the key unless SSH key auth is to be used' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
ssh_auth = build_ssh_auth(ssh_key_auth: false, ssh_private_key: 'foo')
@@ -599,7 +605,7 @@ describe Gitlab::Shell do
end
it 'passes the known_hosts data if specified' do
- expect_call(false, force: false, tags: true, known_hosts: 'foo')
+ expect_call(false, force: false, tags: true, prune: true, known_hosts: 'foo')
ssh_auth = build_ssh_auth(ssh_known_hosts: 'foo')
@@ -607,7 +613,7 @@ describe Gitlab::Shell do
end
it 'does not pass empty known_hosts data' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
ssh_auth = build_ssh_auth(ssh_known_hosts: '')
@@ -615,7 +621,7 @@ describe Gitlab::Shell do
end
it 'does not pass known_hosts data unless SSH is to be used' do
- expect_call(false, force: false, tags: true)
+ expect_call(false, force: false, tags: true, prune: true)
ssh_auth = build_ssh_auth(ssh_import?: false, ssh_known_hosts: 'foo')
@@ -642,7 +648,7 @@ describe Gitlab::Shell do
it 'passes the correct params to the gitaly service' do
expect(repository.gitaly_repository_client).to receive(:fetch_remote)
- .with(remote_name, ssh_auth: ssh_auth, forced: true, no_tags: true, timeout: timeout)
+ .with(remote_name, ssh_auth: ssh_auth, forced: true, no_tags: true, prune: true, timeout: timeout)
subject
end
diff --git a/spec/lib/gitlab/string_placeholder_replacer_spec.rb b/spec/lib/gitlab/string_placeholder_replacer_spec.rb
new file mode 100644
index 00000000000..7a03ea4154c
--- /dev/null
+++ b/spec/lib/gitlab/string_placeholder_replacer_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe Gitlab::StringPlaceholderReplacer do
+ describe '.render_url' do
+ it 'returns the nil if the string is blank' do
+ expect(described_class.replace_string_placeholders(nil, /whatever/)).to be_blank
+ end
+
+ it 'returns the string if the placeholder regex' do
+ expect(described_class.replace_string_placeholders('whatever')).to eq 'whatever'
+ end
+
+ it 'returns the string if no block given' do
+ expect(described_class.replace_string_placeholders('whatever', /whatever/)).to eq 'whatever'
+ end
+
+ context 'when all params are valid' do
+ let(:string) { '%{path}/%{id}/%{branch}' }
+ let(:regex) { /(path|id)/ }
+
+ it 'replaces each placeholders with the block result' do
+ result = described_class.replace_string_placeholders(string, regex) do |arg|
+ 'WHATEVER'
+ end
+
+ expect(result).to eq 'WHATEVER/WHATEVER/%{branch}'
+ end
+
+ it 'does not replace the placeholder if the block result is nil' do
+ result = described_class.replace_string_placeholders(string, regex) do |arg|
+ arg == 'path' ? nil : 'WHATEVER'
+ end
+
+ expect(result).to eq '%{path}/WHATEVER/%{branch}'
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/string_regex_marker_spec.rb b/spec/lib/gitlab/string_regex_marker_spec.rb
index d715f9bd641..37b1298b962 100644
--- a/spec/lib/gitlab/string_regex_marker_spec.rb
+++ b/spec/lib/gitlab/string_regex_marker_spec.rb
@@ -2,17 +2,36 @@ require 'spec_helper'
describe Gitlab::StringRegexMarker do
describe '#mark' do
- let(:raw) { %{"name": "AFNetworking"} }
- let(:rich) { %{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"AFNetworking"</span>}.html_safe }
- subject do
- described_class.new(raw, rich).mark(/"[^"]+":\s*"(?<name>[^"]+)"/, group: :name) do |text, left:, right:|
- %{<a href="#">#{text}</a>}
+ context 'with a single occurrence' do
+ let(:raw) { %{"name": "AFNetworking"} }
+ let(:rich) { %{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"AFNetworking"</span>}.html_safe }
+
+ subject do
+ described_class.new(raw, rich).mark(/"[^"]+":\s*"(?<name>[^"]+)"/, group: :name) do |text, left:, right:|
+ %{<a href="#">#{text}</a>}
+ end
+ end
+
+ it 'marks the match' do
+ expect(subject).to eq(%{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"<a href="#">AFNetworking</a>"</span>})
+ expect(subject).to be_html_safe
end
end
- it 'marks the inline diffs' do
- expect(subject).to eq(%{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"<a href="#">AFNetworking</a>"</span>})
- expect(subject).to be_html_safe
+ context 'with multiple occurrences' do
+ let(:raw) { %{a <b> <c> d} }
+ let(:rich) { %{a &lt;b&gt; &lt;c&gt; d}.html_safe }
+
+ subject do
+ described_class.new(raw, rich).mark(/<[a-z]>/) do |text, left:, right:|
+ %{<strong>#{text}</strong>}
+ end
+ end
+
+ it 'marks the matches' do
+ expect(subject).to eq(%{a <strong>&lt;b&gt;</strong> <strong>&lt;c&gt;</strong> d})
+ expect(subject).to be_html_safe
+ end
end
end
end
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index 7280acb6c82..40c8286b1b9 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Gitlab::UserAccess do
+ include ProjectForksHelper
+
let(:access) { described_class.new(user, project: project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
@@ -118,6 +120,39 @@ describe Gitlab::UserAccess do
end
end
+ describe 'allowing pushes to maintainers of forked projects' do
+ let(:canonical_project) { create(:project, :public, :repository) }
+ let(:project) { fork_project(canonical_project, create(:user), repository: true) }
+
+ before do
+ create(
+ :merge_request,
+ target_project: canonical_project,
+ source_project: project,
+ source_branch: 'awesome-feature',
+ allow_maintainer_to_push: true
+ )
+ end
+
+ it 'allows users that have push access to the canonical project to push to the MR branch' do
+ canonical_project.add_developer(user)
+
+ expect(access.can_push_to_branch?('awesome-feature')).to be_truthy
+ end
+
+ it 'does not allow the user to push to other branches' do
+ canonical_project.add_developer(user)
+
+ expect(access.can_push_to_branch?('master')).to be_falsey
+ end
+
+ it 'does not allow the user to push if he does not have push access to the canonical project' do
+ canonical_project.add_guest(user)
+
+ expect(access.can_push_to_branch?('awesome-feature')).to be_falsey
+ end
+ end
+
describe 'merge to protected branch if allowed for developers' do
before do
@branch = create :protected_branch, :developers_can_merge, project: project
diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb
index bda239b7871..71a743495a2 100644
--- a/spec/lib/gitlab/utils_spec.rb
+++ b/spec/lib/gitlab/utils_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Utils do
- delegate :to_boolean, :boolean_to_yes_no, :slugify, :random_string, :which, to: :described_class
+ delegate :to_boolean, :boolean_to_yes_no, :slugify, :random_string, :which, :ensure_array_from_string, to: :described_class
describe '.slugify' do
{
@@ -83,4 +83,18 @@ describe Gitlab::Utils do
expect(which('sh', 'PATH' => '/bin')).to eq('/bin/sh')
end
end
+
+ describe '.ensure_array_from_string' do
+ it 'returns the same array if given one' do
+ arr = ['a', 4, true, { test: 1 }]
+
+ expect(ensure_array_from_string(arr)).to eq(arr)
+ end
+
+ it 'turns comma-separated strings into arrays' do
+ str = 'seven, eight, 9, 10'
+
+ expect(ensure_array_from_string(str)).to eq(%w[seven eight 9 10])
+ end
+ end
end
diff --git a/spec/lib/gitlab/verify/job_artifacts_spec.rb b/spec/lib/gitlab/verify/job_artifacts_spec.rb
new file mode 100644
index 00000000000..ec490bdfde2
--- /dev/null
+++ b/spec/lib/gitlab/verify/job_artifacts_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe Gitlab::Verify::JobArtifacts do
+ include GitlabVerifyHelpers
+
+ it_behaves_like 'Gitlab::Verify::BatchVerifier subclass' do
+ let!(:objects) { create_list(:ci_job_artifact, 3, :archive) }
+ end
+
+ describe '#run_batches' do
+ let(:failures) { collect_failures }
+ let(:failure) { failures[artifact] }
+
+ let!(:artifact) { create(:ci_job_artifact, :archive, :correct_checksum) }
+
+ it 'passes artifacts with the correct file' do
+ expect(failures).to eq({})
+ end
+
+ it 'fails artifacts with a missing file' do
+ FileUtils.rm_f(artifact.file.path)
+
+ expect(failures.keys).to contain_exactly(artifact)
+ expect(failure).to be_a(Errno::ENOENT)
+ expect(failure.to_s).to include(artifact.file.path)
+ end
+
+ it 'fails artifacts with a mismatched checksum' do
+ File.truncate(artifact.file.path, 0)
+
+ expect(failures.keys).to contain_exactly(artifact)
+ expect(failure.to_s).to include('Checksum mismatch')
+ end
+ end
+end
diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb
index e638ad7a2c9..3c8206031cf 100644
--- a/spec/lib/mattermost/team_spec.rb
+++ b/spec/lib/mattermost/team_spec.rb
@@ -64,4 +64,108 @@ describe Mattermost::Team do
end
end
end
+
+ describe '#create' do
+ subject { described_class.new(nil).create(name: "devteam", display_name: "Dev Team", type: "O") }
+
+ context 'for a new team' do
+ let(:response) do
+ {
+ "id" => "cuojfcetjty7tb4pxe47pwpndo",
+ "create_at" => 1517688728701,
+ "update_at" => 1517688728701,
+ "delete_at" => 0,
+ "display_name" => "Dev Team",
+ "name" => "devteam",
+ "description" => "",
+ "email" => "admin@example.com",
+ "type" => "O",
+ "company_name" => "",
+ "allowed_domains" => "",
+ "invite_id" => "7mp9d3ayaj833ymmkfnid8js6w",
+ "allow_open_invite" => false
+ }
+ end
+
+ before do
+ stub_request(:post, "http://mattermost.example.com/api/v3/teams/create")
+ .to_return(
+ status: 200,
+ body: response.to_json,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
+
+ it 'returns the new team' do
+ is_expected.to eq(response)
+ end
+ end
+
+ context 'for existing team' do
+ before do
+ stub_request(:post, 'http://mattermost.example.com/api/v3/teams/create')
+ .to_return(
+ status: 400,
+ headers: { 'Content-Type' => 'application/json' },
+ body: {
+ id: "store.sql_team.save.domain_exists.app_error",
+ message: "A team with that name already exists",
+ detailed_error: "",
+ request_id: "1hsb5bxs97r8bdggayy7n9gxaw",
+ status_code: 400
+ }.to_json
+ )
+ end
+
+ it 'raises an error with message' do
+ expect { subject }.to raise_error(Mattermost::Error, 'A team with that name already exists')
+ end
+ end
+ end
+
+ describe '#delete' do
+ subject { described_class.new(nil).destroy(team_id: "cuojfcetjty7tb4pxe47pwpndo") }
+
+ context 'for an existing team' do
+ let(:response) do
+ {
+ "status" => "OK"
+ }
+ end
+
+ before do
+ stub_request(:delete, "http://mattermost.example.com/api/v4/teams/cuojfcetjty7tb4pxe47pwpndo")
+ .to_return(
+ status: 200,
+ body: response.to_json,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
+
+ it 'returns team status' do
+ is_expected.to eq(response)
+ end
+ end
+
+ context 'for an unknown team' do
+ before do
+ stub_request(:delete, "http://mattermost.example.com/api/v4/teams/cuojfcetjty7tb4pxe47pwpndo")
+ .to_return(
+ status: 404,
+ body: {
+ id: "store.sql_team.get.find.app_error",
+ message: "We couldn't find the existing team",
+ detailed_error: "",
+ request_id: "my114ab5nbnui8c9pes4kz8mza",
+ status_code: 404
+ }.to_json,
+ headers: { 'Content-Type' => 'application/json' }
+ )
+ end
+
+ it 'raises an error with message' do
+ expect { subject }.to raise_error(Mattermost::Error, "We couldn't find the existing team")
+ end
+ end
+ end
end
diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb
deleted file mode 100644
index 8b0c7254b5e..00000000000
--- a/spec/lib/repository_cache_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'spec_helper'
-
-describe RepositoryCache do
- let(:project) { create(:project) }
- let(:backend) { double('backend').as_null_object }
- let(:cache) { described_class.new('example', project.id, backend) }
-
- describe '#cache_key' do
- it 'includes the namespace' do
- expect(cache.cache_key(:foo)).to eq "foo:example:#{project.id}"
- end
- end
-
- describe '#expire' do
- it 'expires the given key from the cache' do
- cache.expire(:foo)
- expect(backend).to have_received(:delete).with("foo:example:#{project.id}")
- end
- end
-
- describe '#fetch' do
- it 'fetches the given key from the cache' do
- cache.fetch(:bar)
- expect(backend).to have_received(:fetch).with("bar:example:#{project.id}")
- end
-
- it 'accepts a block' do
- p = -> {}
-
- cache.fetch(:baz, &p)
- expect(backend).to have_received(:fetch).with("baz:example:#{project.id}", &p)
- end
- end
-end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index bcbb9287199..83c33797bbc 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -457,7 +457,7 @@ describe Notify do
it 'has the correct subject and body' do
is_expected.to have_subject("#{project.name} | Project was moved")
- is_expected.to have_html_escaped_body_text project.name_with_namespace
+ is_expected.to have_html_escaped_body_text project.full_name
is_expected.to have_body_text(project.ssh_url_to_repo)
end
end
@@ -483,8 +483,8 @@ describe Notify do
to_emails = subject.header[:to].addrs.map(&:address)
expect(to_emails).to eq([recipient.notification_email])
- is_expected.to have_subject "Request to join the #{project.name_with_namespace} project"
- is_expected.to have_html_escaped_body_text project.name_with_namespace
+ is_expected.to have_subject "Request to join the #{project.full_name} project"
+ is_expected.to have_html_escaped_body_text project.full_name
is_expected.to have_body_text project_project_members_url(project)
is_expected.to have_body_text project_member.human_access
end
@@ -503,8 +503,8 @@ describe Notify do
it_behaves_like "a user cannot unsubscribe through footer link"
it 'contains all the useful information' do
- is_expected.to have_subject "Access to the #{project.name_with_namespace} project was denied"
- is_expected.to have_html_escaped_body_text project.name_with_namespace
+ is_expected.to have_subject "Access to the #{project.full_name} project was denied"
+ is_expected.to have_html_escaped_body_text project.full_name
is_expected.to have_body_text project.web_url
end
end
@@ -520,8 +520,8 @@ describe Notify do
it_behaves_like "a user cannot unsubscribe through footer link"
it 'contains all the useful information' do
- is_expected.to have_subject "Access to the #{project.name_with_namespace} project was granted"
- is_expected.to have_html_escaped_body_text project.name_with_namespace
+ is_expected.to have_subject "Access to the #{project.full_name} project was granted"
+ is_expected.to have_html_escaped_body_text project.full_name
is_expected.to have_body_text project.web_url
is_expected.to have_body_text project_member.human_access
end
@@ -550,8 +550,8 @@ describe Notify do
it_behaves_like "a user cannot unsubscribe through footer link"
it 'contains all the useful information' do
- is_expected.to have_subject "Invitation to join the #{project.name_with_namespace} project"
- is_expected.to have_html_escaped_body_text project.name_with_namespace
+ is_expected.to have_subject "Invitation to join the #{project.full_name} project"
+ is_expected.to have_html_escaped_body_text project.full_name
is_expected.to have_body_text project.web_url
is_expected.to have_body_text project_member.human_access
is_expected.to have_body_text project_member.invite_token
@@ -575,7 +575,7 @@ describe Notify do
it 'contains all the useful information' do
is_expected.to have_subject 'Invitation accepted'
- is_expected.to have_html_escaped_body_text project.name_with_namespace
+ is_expected.to have_html_escaped_body_text project.full_name
is_expected.to have_body_text project.web_url
is_expected.to have_body_text project_member.invite_email
is_expected.to have_html_escaped_body_text invited_user.name
@@ -598,7 +598,7 @@ describe Notify do
it 'contains all the useful information' do
is_expected.to have_subject 'Invitation declined'
- is_expected.to have_html_escaped_body_text project.name_with_namespace
+ is_expected.to have_html_escaped_body_text project.full_name
is_expected.to have_body_text project.web_url
is_expected.to have_body_text project_member.invite_email
end
diff --git a/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb b/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb
new file mode 100644
index 00000000000..c18ae3b76d3
--- /dev/null
+++ b/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb
@@ -0,0 +1,66 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20180306074045_migrate_create_trace_artifact_sidekiq_queue.rb')
+
+describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
+ include Gitlab::Database::MigrationHelpers
+
+ context 'when there are jobs in the queues' do
+ it 'correctly migrates queue when migrating up' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'pipeline_default:create_trace_artifact').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
+
+ described_class.new.up
+
+ expect(sidekiq_queue_length('pipeline_default:create_trace_artifact')).to eq 0
+ expect(sidekiq_queue_length('pipeline_background:archive_trace')).to eq 2
+ end
+ end
+
+ it 'does not affect other queues under the same namespace' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
+
+ described_class.new.up
+
+ expect(sidekiq_queue_length('pipeline_default:build_coverage')).to eq 1
+ expect(sidekiq_queue_length('pipeline_default:build_trace_sections')).to eq 1
+ expect(sidekiq_queue_length('pipeline_default:pipeline_metrics')).to eq 1
+ expect(sidekiq_queue_length('pipeline_default:pipeline_notification')).to eq 1
+ expect(sidekiq_queue_length('pipeline_default:update_head_pipeline_for_merge_request')).to eq 1
+ end
+ end
+
+ it 'correctly migrates queue when migrating down' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
+
+ described_class.new.down
+
+ expect(sidekiq_queue_length('pipeline_default:create_trace_artifact')).to eq 1
+ expect(sidekiq_queue_length('pipeline_background:archive_trace')).to eq 0
+ end
+ end
+ end
+
+ context 'when there are no jobs in the queues' do
+ it 'does not raise error when migrating up' do
+ expect { described_class.new.up }.not_to raise_error
+ end
+
+ it 'does not raise error when migrating down' do
+ expect { described_class.new.down }.not_to raise_error
+ end
+ end
+
+ def stubbed_worker(queue:)
+ Class.new do
+ include Sidekiq::Worker
+ sidekiq_options queue: queue
+ end
+ end
+end
diff --git a/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb b/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb
new file mode 100644
index 00000000000..5e3b20ab4a8
--- /dev/null
+++ b/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb
@@ -0,0 +1,64 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20180307012445_migrate_update_head_pipeline_for_merge_request_sidekiq_queue.rb')
+
+describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis do
+ include Gitlab::Database::MigrationHelpers
+
+ context 'when there are jobs in the queues' do
+ it 'correctly migrates queue when migrating up' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
+
+ described_class.new.up
+
+ expect(sidekiq_queue_length('pipeline_default:update_head_pipeline_for_merge_request')).to eq 0
+ expect(sidekiq_queue_length('pipeline_processing:update_head_pipeline_for_merge_request')).to eq 2
+ end
+ end
+
+ it 'does not affect other queues under the same namespace' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
+ stubbed_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
+
+ described_class.new.up
+
+ expect(sidekiq_queue_length('pipeline_default:build_coverage')).to eq 1
+ expect(sidekiq_queue_length('pipeline_default:build_trace_sections')).to eq 1
+ expect(sidekiq_queue_length('pipeline_default:pipeline_metrics')).to eq 1
+ expect(sidekiq_queue_length('pipeline_default:pipeline_notification')).to eq 1
+ end
+ end
+
+ it 'correctly migrates queue when migrating down' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
+
+ described_class.new.down
+
+ expect(sidekiq_queue_length('pipeline_default:update_head_pipeline_for_merge_request')).to eq 1
+ expect(sidekiq_queue_length('pipeline_processing:update_head_pipeline_for_merge_request')).to eq 0
+ end
+ end
+ end
+
+ context 'when there are no jobs in the queues' do
+ it 'does not raise error when migrating up' do
+ expect { described_class.new.up }.not_to raise_error
+ end
+
+ it 'does not raise error when migrating down' do
+ expect { described_class.new.down }.not_to raise_error
+ end
+ end
+
+ def stubbed_worker(queue:)
+ Class.new do
+ include Sidekiq::Worker
+ sidekiq_options queue: queue
+ end
+ end
+end
diff --git a/spec/models/badge_spec.rb b/spec/models/badge_spec.rb
new file mode 100644
index 00000000000..33dc19e3432
--- /dev/null
+++ b/spec/models/badge_spec.rb
@@ -0,0 +1,94 @@
+require 'spec_helper'
+
+describe Badge do
+ let(:placeholder_url) { 'http://www.example.com/%{project_path}/%{project_id}/%{default_branch}/%{commit_sha}' }
+
+ describe 'validations' do
+ # Requires the let variable url_sym
+ shared_examples 'placeholder url' do
+ let(:badge) { build(:badge) }
+
+ it 'allows url with http protocol' do
+ badge[url_sym] = 'http://www.example.com'
+
+ expect(badge).to be_valid
+ end
+
+ it 'allows url with https protocol' do
+ badge[url_sym] = 'https://www.example.com'
+
+ expect(badge).to be_valid
+ end
+
+ it 'cannot be empty' do
+ badge[url_sym] = ''
+
+ expect(badge).not_to be_valid
+ end
+
+ it 'cannot be nil' do
+ badge[url_sym] = nil
+
+ expect(badge).not_to be_valid
+ end
+
+ it 'accept badges placeholders' do
+ badge[url_sym] = placeholder_url
+
+ expect(badge).to be_valid
+ end
+
+ it 'sanitize url' do
+ badge[url_sym] = 'javascript:alert(1)'
+
+ expect(badge).not_to be_valid
+ end
+ end
+
+ context 'link_url format' do
+ let(:url_sym) { :link_url }
+
+ it_behaves_like 'placeholder url'
+ end
+
+ context 'image_url format' do
+ let(:url_sym) { :image_url }
+
+ it_behaves_like 'placeholder url'
+ end
+ end
+
+ shared_examples 'rendered_links' do
+ it 'should use the project information to populate the url placeholders' do
+ stub_project_commit_info(project)
+
+ expect(badge.public_send("rendered_#{method}", project)).to eq "http://www.example.com/#{project.full_path}/#{project.id}/master/whatever"
+ end
+
+ it 'returns the url if the project used is nil' do
+ expect(badge.public_send("rendered_#{method}", nil)).to eq placeholder_url
+ end
+
+ def stub_project_commit_info(project)
+ allow(project).to receive(:commit).and_return(double('Commit', sha: 'whatever'))
+ allow(project).to receive(:default_branch).and_return('master')
+ end
+ end
+
+ context 'methods' do
+ let(:badge) { build(:badge, link_url: placeholder_url, image_url: placeholder_url) }
+ let!(:project) { create(:project) }
+
+ context '#rendered_link_url' do
+ let(:method) { :link_url }
+
+ it_behaves_like 'rendered_links'
+ end
+
+ context '#rendered_image_url' do
+ let(:method) { :image_url }
+
+ it_behaves_like 'rendered_links'
+ end
+ end
+end
diff --git a/spec/models/badges/group_badge_spec.rb b/spec/models/badges/group_badge_spec.rb
new file mode 100644
index 00000000000..ed7f83d0489
--- /dev/null
+++ b/spec/models/badges/group_badge_spec.rb
@@ -0,0 +1,11 @@
+require 'spec_helper'
+
+describe GroupBadge do
+ describe 'associations' do
+ it { is_expected.to belong_to(:group) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:group) }
+ end
+end
diff --git a/spec/models/badges/project_badge_spec.rb b/spec/models/badges/project_badge_spec.rb
new file mode 100644
index 00000000000..0e1a8159cb6
--- /dev/null
+++ b/spec/models/badges/project_badge_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe ProjectBadge do
+ let(:placeholder_url) { 'http://www.example.com/%{project_path}/%{project_id}/%{default_branch}/%{commit_sha}' }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:project) }
+ end
+
+ shared_examples 'rendered_links' do
+ it 'should use the badge project information to populate the url placeholders' do
+ stub_project_commit_info(project)
+
+ expect(badge.public_send("rendered_#{method}")).to eq "http://www.example.com/#{project.full_path}/#{project.id}/master/whatever"
+ end
+
+ def stub_project_commit_info(project)
+ allow(project).to receive(:commit).and_return(double('Commit', sha: 'whatever'))
+ allow(project).to receive(:default_branch).and_return('master')
+ end
+ end
+
+ context 'methods' do
+ let(:badge) { build(:project_badge, link_url: placeholder_url, image_url: placeholder_url) }
+ let!(:project) { badge.project }
+
+ context '#rendered_link_url' do
+ let(:method) { :link_url }
+
+ it_behaves_like 'rendered_links'
+ end
+
+ context '#rendered_image_url' do
+ let(:method) { :image_url }
+
+ it_behaves_like 'rendered_links'
+ end
+ end
+end
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index df8a508e021..2905b58066b 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -22,11 +22,11 @@ describe Clusters::Applications::Prometheus do
end
end
- describe '#proxy_client' do
+ describe '#prometheus_client' do
context 'cluster is nil' do
it 'returns nil' do
expect(subject.cluster).to be_nil
- expect(subject.proxy_client).to be_nil
+ expect(subject.prometheus_client).to be_nil
end
end
@@ -35,7 +35,7 @@ describe Clusters::Applications::Prometheus do
subject { create(:clusters_applications_prometheus, cluster: cluster) }
it 'returns nil' do
- expect(subject.proxy_client).to be_nil
+ expect(subject.prometheus_client).to be_nil
end
end
@@ -63,15 +63,15 @@ describe Clusters::Applications::Prometheus do
end
it 'creates proxy prometheus rest client' do
- expect(subject.proxy_client).to be_instance_of(RestClient::Resource)
+ expect(subject.prometheus_client).to be_instance_of(RestClient::Resource)
end
it 'creates proper url' do
- expect(subject.proxy_client.url).to eq('http://example.com/api/v1/proxy/namespaces/gitlab-managed-apps/service/prometheus-prometheus-server:80')
+ expect(subject.prometheus_client.url).to eq('http://example.com/api/v1/proxy/namespaces/gitlab-managed-apps/service/prometheus-prometheus-server:80')
end
it 'copies options and headers from kube client to proxy client' do
- expect(subject.proxy_client.options).to eq(kube_client.rest_client.options.merge(headers: kube_client.headers))
+ expect(subject.prometheus_client.options).to eq(kube_client.rest_client.options.merge(headers: kube_client.headers))
end
end
end
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index 612a3c8e413..a574779e39d 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -34,6 +34,8 @@ describe Clusters::Applications::Runner do
is_expected.to include('checkInterval')
is_expected.to include('rbac')
is_expected.to include('runners')
+ is_expected.to include('privileged: true')
+ is_expected.to include('image: ubuntu:16.04')
is_expected.to include('resources')
is_expected.to include("runnerToken: #{ci_runner.token}")
is_expected.to include("gitlabUrl: #{Gitlab::Routing.url_helpers.root_url}")
@@ -65,5 +67,33 @@ describe Clusters::Applications::Runner do
expect(gitlab_runner.runner).not_to be_nil
end
end
+
+ context 'with duplicated values on vendor/runner/values.yaml' do
+ let(:values) do
+ {
+ "concurrent" => 4,
+ "checkInterval" => 3,
+ "rbac" => {
+ "create" => false
+ },
+ "clusterWideAccess" => false,
+ "runners" => {
+ "privileged" => false,
+ "image" => "ubuntu:16.04",
+ "builds" => {},
+ "services" => {},
+ "helpers" => {}
+ }
+ }
+ end
+
+ before do
+ allow(gitlab_runner).to receive(:chart_values).and_return(values)
+ end
+
+ it 'should overwrite values.yaml' do
+ is_expected.to include("privileged: #{gitlab_runner.privileged}")
+ end
+ end
end
end
diff --git a/spec/models/concerns/prometheus_adapter_spec.rb b/spec/models/concerns/prometheus_adapter_spec.rb
new file mode 100644
index 00000000000..f4b9c57e71a
--- /dev/null
+++ b/spec/models/concerns/prometheus_adapter_spec.rb
@@ -0,0 +1,121 @@
+require 'spec_helper'
+
+describe PrometheusAdapter, :use_clean_rails_memory_store_caching do
+ include PrometheusHelpers
+ include ReactiveCachingHelpers
+
+ class TestClass
+ include PrometheusAdapter
+ end
+
+ let(:project) { create(:prometheus_project) }
+ let(:service) { project.prometheus_service }
+
+ let(:described_class) { TestClass }
+ let(:environment_query) { Gitlab::Prometheus::Queries::EnvironmentQuery }
+
+ describe '#query' do
+ describe 'environment' do
+ let(:environment) { build_stubbed(:environment, slug: 'env-slug') }
+
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ context 'with valid data' do
+ subject { service.query(:environment, environment) }
+
+ before do
+ stub_reactive_cache(service, prometheus_data, environment_query, environment.id)
+ end
+
+ it 'returns reactive data' do
+ is_expected.to eq(prometheus_metrics_data)
+ end
+ end
+ end
+
+ describe 'matched_metrics' do
+ let(:matched_metrics_query) { Gitlab::Prometheus::Queries::MatchedMetricQuery }
+ let(:prometheus_client_wrapper) { double(:prometheus_client_wrapper, label_values: nil) }
+
+ context 'with valid data' do
+ subject { service.query(:matched_metrics) }
+
+ before do
+ allow(service).to receive(:prometheus_client_wrapper).and_return(prometheus_client_wrapper)
+ synchronous_reactive_cache(service)
+ end
+
+ it 'returns reactive data' do
+ expect(subject[:success]).to be_truthy
+ expect(subject[:data]).to eq([])
+ end
+ end
+ end
+
+ describe 'deployment' do
+ let(:deployment) { build_stubbed(:deployment) }
+ let(:deployment_query) { Gitlab::Prometheus::Queries::DeploymentQuery }
+
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ context 'with valid data' do
+ subject { service.query(:deployment, deployment) }
+
+ before do
+ stub_reactive_cache(service, prometheus_data, deployment_query, deployment.id)
+ end
+
+ it 'returns reactive data' do
+ expect(subject).to eq(prometheus_metrics_data)
+ end
+ end
+ end
+ end
+
+ describe '#calculate_reactive_cache' do
+ let(:environment) { create(:environment, slug: 'env-slug') }
+ before do
+ service.manual_configuration = true
+ service.active = true
+ end
+
+ subject do
+ service.calculate_reactive_cache(environment_query.name, environment.id)
+ end
+
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ context 'when service is inactive' do
+ before do
+ service.active = false
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when Prometheus responds with valid data' do
+ before do
+ stub_all_prometheus_requests(environment.slug)
+ end
+
+ it { expect(subject.to_json).to eq(prometheus_data.to_json) }
+ it { expect(subject.to_json).to eq(prometheus_data.to_json) }
+ end
+
+ [404, 500].each do |status|
+ context "when Prometheus responds with #{status}" do
+ before do
+ stub_all_prometheus_requests(environment.slug, status: status, body: "QUERY FAILED!")
+ end
+
+ it { is_expected.to eq(success: false, result: %(#{status} - "QUERY FAILED!")) }
+ end
+ end
+ end
+end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index ba8aa13d5ad..ac30cd27e0c 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -64,6 +64,7 @@ describe Deployment do
describe '#metrics' do
let(:deployment) { create(:deployment) }
+ let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
subject { deployment.metrics }
@@ -76,17 +77,16 @@ describe Deployment do
{
success: true,
metrics: {},
- last_update: 42,
- deployment_time: 1494408956
+ last_update: 42
}
end
before do
- allow(deployment.project).to receive_message_chain(:monitoring_service, :deployment_metrics)
- .with(any_args).and_return(simple_metrics)
+ allow(deployment).to receive(:prometheus_adapter).and_return(prometheus_adapter)
+ allow(prometheus_adapter).to receive(:query).with(:deployment, deployment).and_return(simple_metrics)
end
- it { is_expected.to eq(simple_metrics) }
+ it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.created_at.to_i })) }
end
end
@@ -109,11 +109,11 @@ describe Deployment do
}
end
- let(:prometheus_service) { double('prometheus_service') }
+ let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
before do
- allow(project).to receive(:prometheus_service).and_return(prometheus_service)
- allow(prometheus_service).to receive(:additional_deployment_metrics).and_return(simple_metrics)
+ allow(deployment).to receive(:prometheus_adapter).and_return(prometheus_adapter)
+ allow(prometheus_adapter).to receive(:query).with(:additional_metrics_deployment, deployment).and_return(simple_metrics)
end
it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.created_at.to_i })) }
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 6f24a039998..412eca4a56b 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Environment do
- set(:project) { create(:project) }
+ let(:project) { create(:project) }
subject(:environment) { create(:environment, project: project) }
it { is_expected.to belong_to(:project) }
@@ -142,15 +142,15 @@ describe Environment do
let(:commit) { project.commit.parent }
it 'returns deployment id for the environment' do
- expect(environment.first_deployment_for(commit)).to eq deployment1
+ expect(environment.first_deployment_for(commit.id)).to eq deployment1
end
it 'return nil when no deployment is found' do
- expect(environment.first_deployment_for(head_commit)).to eq nil
+ expect(environment.first_deployment_for(head_commit.id)).to eq nil
end
it 'returns a UTF-8 ref' do
- expect(environment.first_deployment_for(commit).ref).to be_utf8
+ expect(environment.first_deployment_for(commit.id).ref).to be_utf8
end
end
@@ -452,8 +452,8 @@ describe Environment do
end
it 'returns the metrics from the deployment service' do
- expect(project.monitoring_service)
- .to receive(:environment_metrics).with(environment)
+ expect(environment.prometheus_adapter)
+ .to receive(:query).with(:environment, environment)
.and_return(:fake_metrics)
is_expected.to eq(:fake_metrics)
@@ -508,12 +508,12 @@ describe Environment do
context 'when the environment has additional metrics' do
before do
- allow(environment).to receive(:has_additional_metrics?).and_return(true)
+ allow(environment).to receive(:has_metrics?).and_return(true)
end
it 'returns the additional metrics from the deployment service' do
- expect(project.prometheus_service).to receive(:additional_environment_metrics)
- .with(environment)
+ expect(environment.prometheus_adapter).to receive(:query)
+ .with(:additional_metrics_environment, environment)
.and_return(:fake_metrics)
is_expected.to eq(:fake_metrics)
@@ -522,46 +522,13 @@ describe Environment do
context 'when the environment does not have metrics' do
before do
- allow(environment).to receive(:has_additional_metrics?).and_return(false)
+ allow(environment).to receive(:has_metrics?).and_return(false)
end
it { is_expected.to be_nil }
end
end
- describe '#has_additional_metrics??' do
- subject { environment.has_additional_metrics? }
-
- context 'when the enviroment is available' do
- context 'with a deployment service' do
- let(:project) { create(:prometheus_project) }
-
- context 'and a deployment' do
- let!(:deployment) { create(:deployment, environment: environment) }
- it { is_expected.to be_truthy }
- end
-
- context 'but no deployments' do
- it { is_expected.to be_falsy }
- end
- end
-
- context 'without a monitoring service' do
- it { is_expected.to be_falsy }
- end
- end
-
- context 'when the environment is unavailable' do
- let(:project) { create(:prometheus_project) }
-
- before do
- environment.stop
- end
-
- it { is_expected.to be_falsy }
- end
- end
-
describe '#slug' do
it "is automatically generated" do
expect(environment.slug).not_to be_nil
@@ -654,4 +621,12 @@ describe Environment do
end
end
end
+
+ describe '#prometheus_adapter' do
+ it 'calls prometheus adapter service' do
+ expect_any_instance_of(Prometheus::AdapterService).to receive(:prometheus_adapter)
+
+ subject.prometheus_adapter
+ end
+ end
end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 67f49348acb..8ea92410022 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -49,6 +49,22 @@ describe Event do
end
end
end
+
+ describe 'after_create :track_user_interacted_projects' do
+ let(:event) { build(:push_event, project: project, author: project.owner) }
+
+ it 'passes event to UserInteractedProject.track' do
+ expect(UserInteractedProject).to receive(:available?).and_return(true)
+ expect(UserInteractedProject).to receive(:track).with(event)
+ event.save
+ end
+
+ it 'does not call UserInteractedProject.track if its not yet available' do
+ expect(UserInteractedProject).to receive(:available?).and_return(false)
+ expect(UserInteractedProject).not_to receive(:track)
+ event.save
+ end
+ end
end
describe "Push event" do
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 4f16b73ef38..abfc0896a41 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -18,6 +18,7 @@ describe Group do
it { is_expected.to have_many(:uploads).dependent(:destroy) }
it { is_expected.to have_one(:chat_team) }
it { is_expected.to have_many(:custom_attributes).class_name('GroupCustomAttribute') }
+ it { is_expected.to have_many(:badges).class_name('GroupBadge') }
describe '#members & #requesters' do
let(:requester) { create(:user) }
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 3e46fa36375..b8b0e63f92e 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -45,14 +45,6 @@ describe ProjectMember do
let(:project) { owner.project }
let(:master) { create(:project_member, project: project) }
- let(:owner_todos) { (0...2).map { create(:todo, user: owner.user, project: project) } }
- let(:master_todos) { (0...3).map { create(:todo, user: master.user, project: project) } }
-
- before do
- owner_todos
- master_todos
- end
-
it "creates an expired event when left due to expiry" do
expired = create(:project_member, project: project, expires_at: Time.now - 6.days)
expired.destroy
@@ -63,21 +55,6 @@ describe ProjectMember do
master.destroy
expect(Event.recent.first.action).to eq(Event::LEFT)
end
-
- it "destroys itself and delete associated todos" do
- expect(owner.user.todos.size).to eq(2)
- expect(master.user.todos.size).to eq(3)
- expect(Todo.count).to eq(5)
-
- master_todo_ids = master_todos.map(&:id)
- master.destroy
-
- expect(owner.user.todos.size).to eq(2)
- expect(Todo.count).to eq(2)
- master_todo_ids.each do |id|
- expect(Todo.exists?(id)).to eq(false)
- end
- end
end
describe '.import_team' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 243eeddc7a8..7986aa31e16 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -2084,4 +2084,82 @@ describe MergeRequest do
it_behaves_like 'checking whether a rebase is in progress'
end
end
+
+ describe '#allow_maintainer_to_push' do
+ let(:merge_request) do
+ build(:merge_request, source_branch: 'fixes', allow_maintainer_to_push: true)
+ end
+
+ it 'is false when pushing by a maintainer is not possible' do
+ expect(merge_request).to receive(:maintainer_push_possible?) { false }
+
+ expect(merge_request.allow_maintainer_to_push).to be_falsy
+ end
+
+ it 'is true when pushing by a maintainer is possible' do
+ expect(merge_request).to receive(:maintainer_push_possible?) { true }
+
+ expect(merge_request.allow_maintainer_to_push).to be_truthy
+ end
+ end
+
+ describe '#maintainer_push_possible?' do
+ let(:merge_request) do
+ build(:merge_request, source_branch: 'fixes')
+ end
+
+ before do
+ allow(ProtectedBranch).to receive(:protected?) { false }
+ end
+
+ it 'does not allow maintainer to push if the source project is the same as the target' do
+ merge_request.target_project = merge_request.source_project = create(:project, :public)
+
+ expect(merge_request.maintainer_push_possible?).to be_falsy
+ end
+
+ it 'allows maintainer to push when both source and target are public' do
+ merge_request.target_project = build(:project, :public)
+ merge_request.source_project = build(:project, :public)
+
+ expect(merge_request.maintainer_push_possible?).to be_truthy
+ end
+
+ it 'is not available for protected branches' do
+ merge_request.target_project = build(:project, :public)
+ merge_request.source_project = build(:project, :public)
+
+ expect(ProtectedBranch).to receive(:protected?)
+ .with(merge_request.source_project, 'fixes')
+ .and_return(true)
+
+ expect(merge_request.maintainer_push_possible?).to be_falsy
+ end
+ end
+
+ describe '#can_allow_maintainer_to_push?' do
+ let(:target_project) { create(:project, :public) }
+ let(:source_project) { fork_project(target_project) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ source_branch: 'fixes',
+ target_project: target_project)
+ end
+ let(:user) { create(:user) }
+
+ before do
+ allow(merge_request).to receive(:maintainer_push_possible?) { true }
+ end
+
+ it 'is false if the user does not have push access to the source project' do
+ expect(merge_request.can_allow_maintainer_to_push?(user)).to be_falsy
+ end
+
+ it 'is true when the user has push access to the source project' do
+ source_project.add_developer(user)
+
+ expect(merge_request.can_allow_maintainer_to_push?(user)).to be_truthy
+ end
+ end
end
diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb
index 04440d890aa..e66109fd98f 100644
--- a/spec/models/project_services/asana_service_spec.rb
+++ b/spec/models/project_services/asana_service_spec.rb
@@ -47,7 +47,7 @@ describe AsanaService do
it 'calls Asana service to create a story' do
data = create_data_for_commits('Message from commit. related to #123456')
- expected_message = "#{data[:user_name]} pushed to branch #{data[:ref]} of #{project.name_with_namespace} ( #{data[:commits][0][:url]} ): #{data[:commits][0][:message]}"
+ expected_message = "#{data[:user_name]} pushed to branch #{data[:ref]} of #{project.full_name} ( #{data[:commits][0][:url]} ): #{data[:commits][0][:message]}"
d1 = double('Asana::Task')
expect(d1).to receive(:add_comment).with(text: expected_message)
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index 23db29cb541..3e2a166cdd6 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -29,7 +29,7 @@ describe HipchatService do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:api_url) { 'https://hipchat.example.com/v2/room/123456/notification?auth_token=verySecret' }
- let(:project_name) { project.name_with_namespace.gsub(/\s/, '') }
+ let(:project_name) { project.full_name.gsub(/\s/, '') }
let(:token) { 'verySecret' }
let(:server_url) { 'https://hipchat.example.com'}
let(:push_sample_data) do
@@ -303,7 +303,7 @@ describe HipchatService do
message = hipchat.__send__(:create_pipeline_message, data)
project_url = project.web_url
- project_name = project.name_with_namespace.gsub(/\s/, '')
+ project_name = project.full_name.gsub(/\s/, '')
pipeline_attributes = data[:object_attributes]
ref = pipeline_attributes[:ref]
ref_type = pipeline_attributes[:tag] ? 'tag' : 'branch'
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 748c366efca..54ef0be67ff 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -166,7 +166,6 @@ describe JiraService do
# Creates comment
expect(WebMock).to have_requested(:post, @comment_url)
-
# Creates Remote Link in JIRA issue fields
expect(WebMock).to have_requested(:post, @remote_link_url).with(
body: hash_including(
@@ -174,7 +173,7 @@ describe JiraService do
object: {
url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/#{merge_request.diff_head_sha}",
title: "GitLab: Solved by commit #{merge_request.diff_head_sha}.",
- icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
+ icon: { title: "GitLab", url16x16: "http://localhost/favicon.ico" },
status: { resolved: true }
}
)
diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb
index 522cf15f3ba..a5bdf9a9337 100644
--- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb
+++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb
@@ -31,10 +31,10 @@ describe MattermostSlashCommandsService do
url: 'http://trigger.url',
icon_url: 'http://icon.url/icon.png',
auto_complete: true,
- auto_complete_desc: "Perform common operations on: #{project.name_with_namespace}",
+ auto_complete_desc: "Perform common operations on: #{project.full_name}",
auto_complete_hint: '[help]',
- description: "Perform common operations on: #{project.name_with_namespace}",
- display_name: "GitLab / #{project.name_with_namespace}",
+ description: "Perform common operations on: #{project.full_name}",
+ display_name: "GitLab / #{project.full_name}",
method: 'P',
username: 'GitLab'
}.to_json)
diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb
index 6693e5783a5..7afb1b4a8e3 100644
--- a/spec/models/project_services/prometheus_service_spec.rb
+++ b/spec/models/project_services/prometheus_service_spec.rb
@@ -6,7 +6,6 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do
let(:project) { create(:prometheus_project) }
let(:service) { project.prometheus_service }
- let(:environment_query) { Gitlab::Prometheus::Queries::EnvironmentQuery }
describe "Associations" do
it { is_expected.to belong_to :project }
@@ -55,197 +54,31 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do
end
end
- describe '#environment_metrics' do
- let(:environment) { build_stubbed(:environment, slug: 'env-slug') }
-
- around do |example|
- Timecop.freeze { example.run }
- end
-
- context 'with valid data' do
- subject { service.environment_metrics(environment) }
-
- before do
- stub_reactive_cache(service, prometheus_data, environment_query, environment.id)
- end
-
- it 'returns reactive data' do
- is_expected.to eq(prometheus_metrics_data)
- end
- end
- end
-
- describe '#matched_metrics' do
- let(:matched_metrics_query) { Gitlab::Prometheus::Queries::MatchedMetricsQuery }
- let(:client) { double(:client, label_values: nil) }
-
- context 'with valid data' do
- subject { service.matched_metrics }
-
- before do
- allow(service).to receive(:client).and_return(client)
- synchronous_reactive_cache(service)
- end
-
- it 'returns reactive data' do
- expect(subject[:success]).to be_truthy
- expect(subject[:data]).to eq([])
- end
- end
- end
-
- describe '#deployment_metrics' do
- let(:deployment) { build_stubbed(:deployment) }
- let(:deployment_query) { Gitlab::Prometheus::Queries::DeploymentQuery }
-
- around do |example|
- Timecop.freeze { example.run }
- end
-
- context 'with valid data' do
- subject { service.deployment_metrics(deployment) }
- let(:fake_deployment_time) { 10 }
-
- before do
- stub_reactive_cache(service, prometheus_data, deployment_query, deployment.environment.id, deployment.id)
- end
-
- it 'returns reactive data' do
- expect(deployment).to receive(:created_at).and_return(fake_deployment_time)
-
- expect(subject).to eq(prometheus_metrics_data.merge(deployment_time: fake_deployment_time))
- end
- end
- end
-
- describe '#calculate_reactive_cache' do
- let(:environment) { create(:environment, slug: 'env-slug') }
- before do
- service.manual_configuration = true
- service.active = true
- end
-
- subject do
- service.calculate_reactive_cache(environment_query.name, environment.id)
- end
-
- around do |example|
- Timecop.freeze { example.run }
- end
-
- context 'when service is inactive' do
- before do
- service.active = false
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'when Prometheus responds with valid data' do
- before do
- stub_all_prometheus_requests(environment.slug)
- end
-
- it { expect(subject.to_json).to eq(prometheus_data.to_json) }
- it { expect(subject.to_json).to eq(prometheus_data.to_json) }
- end
-
- [404, 500].each do |status|
- context "when Prometheus responds with #{status}" do
- before do
- stub_all_prometheus_requests(environment.slug, status: status, body: "QUERY FAILED!")
- end
-
- it { is_expected.to eq(success: false, result: %(#{status} - "QUERY FAILED!")) }
- end
- end
- end
-
- describe '#client' do
+ describe '#prometheus_client' do
context 'manual configuration is enabled' do
let(:api_url) { 'http://some_url' }
+
before do
+ subject.active = true
subject.manual_configuration = true
subject.api_url = api_url
end
- it 'returns simple rest client from api_url' do
- expect(subject.client).to be_instance_of(Gitlab::PrometheusClient)
- expect(subject.client.rest_client.url).to eq(api_url)
+ it 'returns rest client from api_url' do
+ expect(subject.prometheus_client.url).to eq(api_url)
end
end
context 'manual configuration is disabled' do
- let!(:cluster_for_all) { create(:cluster, environment_scope: '*', projects: [project]) }
- let!(:cluster_for_dev) { create(:cluster, environment_scope: 'dev', projects: [project]) }
-
- let!(:prometheus_for_dev) { create(:clusters_applications_prometheus, :installed, cluster: cluster_for_dev) }
- let(:proxy_client) { double('proxy_client') }
+ let(:api_url) { 'http://some_url' }
before do
- service.manual_configuration = false
- end
-
- context 'with cluster for all environments with prometheus installed' do
- let!(:prometheus_for_all) { create(:clusters_applications_prometheus, :installed, cluster: cluster_for_all) }
-
- context 'without environment supplied' do
- it 'returns client handling all environments' do
- expect(service).to receive(:client_from_cluster).with(cluster_for_all).and_return(proxy_client).twice
-
- expect(service.client).to be_instance_of(Gitlab::PrometheusClient)
- expect(service.client.rest_client).to eq(proxy_client)
- end
- end
-
- context 'with dev environment supplied' do
- let!(:environment) { create(:environment, project: project, name: 'dev') }
-
- it 'returns dev cluster client' do
- expect(service).to receive(:client_from_cluster).with(cluster_for_dev).and_return(proxy_client).twice
-
- expect(service.client(environment.id)).to be_instance_of(Gitlab::PrometheusClient)
- expect(service.client(environment.id).rest_client).to eq(proxy_client)
- end
- end
-
- context 'with prod environment supplied' do
- let!(:environment) { create(:environment, project: project, name: 'prod') }
-
- it 'returns dev cluster client' do
- expect(service).to receive(:client_from_cluster).with(cluster_for_all).and_return(proxy_client).twice
-
- expect(service.client(environment.id)).to be_instance_of(Gitlab::PrometheusClient)
- expect(service.client(environment.id).rest_client).to eq(proxy_client)
- end
- end
+ subject.manual_configuration = false
+ subject.api_url = api_url
end
- context 'with cluster for all environments without prometheus installed' do
- context 'without environment supplied' do
- it 'raises PrometheusClient::Error because cluster was not found' do
- expect { service.client }.to raise_error(Gitlab::PrometheusClient::Error, /couldn't find cluster with Prometheus installed/)
- end
- end
-
- context 'with dev environment supplied' do
- let!(:environment) { create(:environment, project: project, name: 'dev') }
-
- it 'returns dev cluster client' do
- expect(service).to receive(:client_from_cluster).with(cluster_for_dev).and_return(proxy_client).twice
-
- expect(service.client(environment.id)).to be_instance_of(Gitlab::PrometheusClient)
- expect(service.client(environment.id).rest_client).to eq(proxy_client)
- end
- end
-
- context 'with prod environment supplied' do
- let!(:environment) { create(:environment, project: project, name: 'prod') }
-
- it 'raises PrometheusClient::Error because cluster was not found' do
- expect { service.client }.to raise_error(Gitlab::PrometheusClient::Error, /couldn't find cluster with Prometheus installed/)
- end
- end
+ it 'no client provided' do
+ expect(subject.prometheus_client).to be_nil
end
end
end
@@ -284,7 +117,7 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do
end
end
- describe '#synchronize_service_state! before_save callback' do
+ describe '#synchronize_service_state before_save callback' do
context 'no clusters with prometheus are installed' do
context 'when service is inactive' do
before do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index f4faec9e52a..e970cd7dfdb 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Project do
+ include ProjectForksHelper
+
describe 'associations' do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
@@ -80,6 +82,7 @@ describe Project do
it { is_expected.to have_many(:members_and_requesters) }
it { is_expected.to have_many(:clusters) }
it { is_expected.to have_many(:custom_attributes).class_name('ProjectCustomAttribute') }
+ it { is_expected.to have_many(:project_badges).class_name('ProjectBadge') }
it { is_expected.to have_many(:lfs_file_locks) }
context 'after initialized' do
@@ -517,6 +520,20 @@ describe Project do
it 'returns the project\'s last update date if it has no events' do
expect(project.last_activity_date).to eq(project.updated_at)
end
+
+ it 'returns the most recent timestamp' do
+ project.update_attributes(updated_at: nil,
+ last_activity_at: timestamp,
+ last_repository_updated_at: timestamp - 1.hour)
+
+ expect(project.last_activity_date).to eq(timestamp)
+
+ project.update_attributes(updated_at: timestamp,
+ last_activity_at: timestamp - 1.hour,
+ last_repository_updated_at: nil)
+
+ expect(project.last_activity_date).to eq(timestamp)
+ end
end
end
@@ -3331,4 +3348,135 @@ describe Project do
end.not_to raise_error # Sidekiq::Worker::EnqueueFromTransactionError
end
end
+
+ describe '#badges' do
+ let(:project_group) { create(:group) }
+ let(:project) { create(:project, path: 'avatar', namespace: project_group) }
+
+ before do
+ create_list(:project_badge, 2, project: project)
+ create(:group_badge, group: project_group)
+ end
+
+ it 'returns the project and the project group badges' do
+ create(:group_badge, group: create(:group))
+
+ expect(Badge.count).to eq 4
+ expect(project.badges.count).to eq 3
+ end
+
+ if Group.supports_nested_groups?
+ context 'with nested_groups' do
+ let(:parent_group) { create(:group) }
+
+ before do
+ create_list(:group_badge, 2, group: project_group)
+ project_group.update(parent: parent_group)
+ end
+
+ it 'returns the project and the project nested groups badges' do
+ expect(project.badges.count).to eq 5
+ end
+ end
+ end
+ end
+
+ context 'with cross project merge requests' do
+ let(:user) { create(:user) }
+ let(:target_project) { create(:project, :repository) }
+ let(:project) { fork_project(target_project, nil, repository: true) }
+ let!(:merge_request) do
+ create(
+ :merge_request,
+ target_project: target_project,
+ target_branch: 'target-branch',
+ source_project: project,
+ source_branch: 'awesome-feature-1',
+ allow_maintainer_to_push: true
+ )
+ end
+
+ before do
+ target_project.add_developer(user)
+ end
+
+ describe '#merge_requests_allowing_push_to_user' do
+ it 'returns open merge requests for which the user has developer access to the target project' do
+ expect(project.merge_requests_allowing_push_to_user(user)).to include(merge_request)
+ end
+
+ it 'does not include closed merge requests' do
+ merge_request.close
+
+ expect(project.merge_requests_allowing_push_to_user(user)).to be_empty
+ end
+
+ it 'does not include merge requests for guest users' do
+ guest = create(:user)
+ target_project.add_guest(guest)
+
+ expect(project.merge_requests_allowing_push_to_user(guest)).to be_empty
+ end
+
+ it 'does not include the merge request for other users' do
+ other_user = create(:user)
+
+ expect(project.merge_requests_allowing_push_to_user(other_user)).to be_empty
+ end
+
+ it 'is empty when no user is passed' do
+ expect(project.merge_requests_allowing_push_to_user(nil)).to be_empty
+ end
+ end
+
+ describe '#branch_allows_maintainer_push?' do
+ it 'allows access if the user can merge the merge request' do
+ expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1'))
+ .to be_truthy
+ end
+
+ it 'does not allow guest users access' do
+ guest = create(:user)
+ target_project.add_guest(guest)
+
+ expect(project.branch_allows_maintainer_push?(guest, 'awesome-feature-1'))
+ .to be_falsy
+ end
+
+ it 'does not allow access to branches for which the merge request was closed' do
+ create(:merge_request, :closed,
+ target_project: target_project,
+ target_branch: 'target-branch',
+ source_project: project,
+ source_branch: 'rejected-feature-1',
+ allow_maintainer_to_push: true)
+
+ expect(project.branch_allows_maintainer_push?(user, 'rejected-feature-1'))
+ .to be_falsy
+ end
+
+ it 'does not allow access if the user cannot merge the merge request' do
+ create(:protected_branch, :masters_can_push, project: target_project, name: 'target-branch')
+
+ expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1'))
+ .to be_falsy
+ end
+
+ it 'caches the result' do
+ control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') }
+
+ expect { 3.times { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') } }
+ .not_to exceed_query_limit(control)
+ end
+
+ context 'when the requeststore is active', :request_store do
+ it 'only queries per project across instances' do
+ control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') }
+
+ expect { 2.times { described_class.find(project.id).branch_allows_maintainer_push?(user, 'awesome-feature-1') } }
+ .not_to exceed_query_limit(control).with_threshold(2)
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 1e7671476f1..8b4b5873704 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -14,13 +14,13 @@ describe ProjectWiki do
it { is_expected.to delegate_method(:repository_storage_path).to :project }
it { is_expected.to delegate_method(:hashed_storage?).to :project }
- describe "#path_with_namespace" do
+ describe "#full_path" do
it "returns the project path with namespace with the .wiki extension" do
- expect(subject.path_with_namespace).to eq(project.full_path + '.wiki')
+ expect(subject.full_path).to eq(project.full_path + '.wiki')
end
it 'returns the same value as #full_path' do
- expect(subject.path_with_namespace).to eq(subject.full_path)
+ expect(subject.full_path).to eq(subject.full_path)
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 38653e18306..5bc972bca14 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1004,7 +1004,7 @@ describe Repository do
end
end
- context 'with Gitaly disabled', :skip_gitaly_mock do
+ context 'with Gitaly disabled', :disable_gitaly do
context 'when pre hooks were successful' do
it 'runs without errors' do
hook = double(trigger: [true, nil])
@@ -1447,7 +1447,6 @@ describe Repository do
it 'expires the caches for an empty repository' do
allow(repository).to receive(:empty?).and_return(true)
- expect(cache).to receive(:expire).with(:empty?)
expect(cache).to receive(:expire).with(:has_visible_content?)
repository.expire_emptiness_caches
@@ -1456,7 +1455,6 @@ describe Repository do
it 'does not expire the cache for a non-empty repository' do
allow(repository).to receive(:empty?).and_return(false)
- expect(cache).not_to receive(:expire).with(:empty?)
expect(cache).not_to receive(:expire).with(:has_visible_content?)
repository.expire_emptiness_caches
@@ -1896,7 +1894,7 @@ describe Repository do
it_behaves_like 'adding tag'
end
- context 'when Gitaly operation_user_add_tag feature is disabled', :skip_gitaly_mock do
+ context 'when Gitaly operation_user_add_tag feature is disabled', :disable_gitaly do
it_behaves_like 'adding tag'
it 'passes commit SHA to pre-receive and update hooks and tag SHA to post-receive hook' do
@@ -1955,7 +1953,7 @@ describe Repository do
end
end
- context 'with gitaly disabled', :skip_gitaly_mock do
+ context 'with gitaly disabled', :disable_gitaly do
it_behaves_like "user deleting a branch"
let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
@@ -2171,15 +2169,6 @@ describe Repository do
end
end
- describe '#expire_method_caches' do
- it 'expires the caches of the given methods' do
- expect_any_instance_of(RepositoryCache).to receive(:expire).with(:readme)
- expect_any_instance_of(RepositoryCache).to receive(:expire).with(:gitignore)
-
- repository.expire_method_caches(%i(readme gitignore))
- end
- end
-
describe '#expire_all_method_caches' do
it 'expires the caches of all methods' do
expect(repository).to receive(:expire_method_caches)
@@ -2325,66 +2314,6 @@ describe Repository do
end
end
- describe '#cache_method_output', :use_clean_rails_memory_store_caching do
- let(:fallback) { 10 }
-
- context 'with a non-existing repository' do
- let(:project) { create(:project) } # No repository
-
- subject do
- repository.cache_method_output(:cats, fallback: fallback) do
- repository.cats_call_stub
- end
- end
-
- it 'returns the fallback value' do
- expect(subject).to eq(fallback)
- end
-
- it 'avoids calling the original method' do
- expect(repository).not_to receive(:cats_call_stub)
-
- subject
- end
- end
-
- context 'with a method throwing a non-existing-repository error' do
- subject do
- repository.cache_method_output(:cats, fallback: fallback) do
- raise Gitlab::Git::Repository::NoRepository
- end
- end
-
- it 'returns the fallback value' do
- expect(subject).to eq(fallback)
- end
-
- it 'does not cache the data' do
- subject
-
- expect(repository.instance_variable_defined?(:@cats)).to eq(false)
- expect(repository.send(:cache).exist?(:cats)).to eq(false)
- end
- end
-
- context 'with an existing repository' do
- it 'caches the output' do
- object = double
-
- expect(object).to receive(:number).once.and_return(10)
-
- 2.times do
- val = repository.cache_method_output(:cats) { object.number }
-
- expect(val).to eq(10)
- end
-
- expect(repository.send(:cache).exist?(:cats)).to eq(true)
- expect(repository.instance_variable_get(:@cats)).to eq(10)
- end
- end
- end
-
describe '#refresh_method_caches' do
it 'refreshes the caches of the given types' do
expect(repository).to receive(:expire_method_caches)
diff --git a/spec/models/user_interacted_project_spec.rb b/spec/models/user_interacted_project_spec.rb
new file mode 100644
index 00000000000..cb4bb3372d4
--- /dev/null
+++ b/spec/models/user_interacted_project_spec.rb
@@ -0,0 +1,60 @@
+require 'spec_helper'
+
+describe UserInteractedProject do
+ describe '.track' do
+ subject { described_class.track(event) }
+ let(:event) { build(:event) }
+
+ Event::ACTIONS.each do |action|
+ context "for all actions (event types)" do
+ let(:event) { build(:event, action: action) }
+ it 'creates a record' do
+ expect { subject }.to change { described_class.count }.from(0).to(1)
+ end
+ end
+ end
+
+ it 'sets project accordingly' do
+ subject
+ expect(described_class.first.project).to eq(event.project)
+ end
+
+ it 'sets user accordingly' do
+ subject
+ expect(described_class.first.user).to eq(event.author)
+ end
+
+ it 'only creates a record once per user/project' do
+ expect do
+ subject
+ described_class.track(event)
+ end.to change { described_class.count }.from(0).to(1)
+ end
+
+ describe 'with an event without a project' do
+ let(:event) { build(:event, project: nil) }
+
+ it 'ignores the event' do
+ expect { subject }.not_to change { described_class.count }
+ end
+ end
+ end
+
+ describe '.available?' do
+ before do
+ described_class.instance_variable_set('@available_flag', nil)
+ end
+
+ it 'checks schema version and properly caches positive result' do
+ expect(ActiveRecord::Migrator).to receive(:current_version).and_return(described_class::REQUIRED_SCHEMA_VERSION - 1 - rand(1000))
+ expect(described_class.available?).to be_falsey
+ expect(ActiveRecord::Migrator).to receive(:current_version).and_return(described_class::REQUIRED_SCHEMA_VERSION + rand(1000))
+ expect(described_class.available?).to be_truthy
+ expect(ActiveRecord::Migrator).not_to receive(:current_version)
+ expect(described_class.available?).to be_truthy # cached response
+ end
+ end
+
+ it { is_expected.to validate_presence_of(:project_id) }
+ it { is_expected.to validate_presence_of(:user_id) }
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 00b5226d874..5680eb24985 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -27,7 +27,6 @@ describe User do
it { is_expected.to have_many(:keys).dependent(:destroy) }
it { is_expected.to have_many(:deploy_keys).dependent(:destroy) }
it { is_expected.to have_many(:events).dependent(:destroy) }
- it { is_expected.to have_many(:recent_events).class_name('Event') }
it { is_expected.to have_many(:issues).dependent(:destroy) }
it { is_expected.to have_many(:notes).dependent(:destroy) }
it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 129344f105f..ea76e604153 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -308,4 +308,41 @@ describe ProjectPolicy do
it_behaves_like 'project policies as master'
it_behaves_like 'project policies as owner'
it_behaves_like 'project policies as admin'
+
+ context 'when a public project has merge requests allowing access' do
+ include ProjectForksHelper
+ let(:user) { create(:user) }
+ let(:target_project) { create(:project, :public) }
+ let(:project) { fork_project(target_project) }
+ let!(:merge_request) do
+ create(
+ :merge_request,
+ target_project: target_project,
+ source_project: project,
+ allow_maintainer_to_push: true
+ )
+ end
+ let(:maintainer_abilities) do
+ %w(create_build update_build create_pipeline update_pipeline)
+ end
+
+ subject { described_class.new(user, project) }
+
+ it 'does not allow pushing code' do
+ expect_disallowed(*maintainer_abilities)
+ end
+
+ it 'allows pushing if the user is a member with push access to the target project' do
+ target_project.add_developer(user)
+
+ expect_allowed(*maintainer_abilities)
+ end
+
+ it 'dissallows abilities to a maintainer if the merge request was closed' do
+ target_project.add_developer(user)
+ merge_request.close!
+
+ expect_disallowed(*maintainer_abilities)
+ end
+ end
end
diff --git a/spec/requests/api/badges_spec.rb b/spec/requests/api/badges_spec.rb
new file mode 100644
index 00000000000..ae64a9ca162
--- /dev/null
+++ b/spec/requests/api/badges_spec.rb
@@ -0,0 +1,367 @@
+require 'spec_helper'
+
+describe API::Badges do
+ let(:master) { create(:user, username: 'master_user') }
+ let(:developer) { create(:user) }
+ let(:access_requester) { create(:user) }
+ let(:stranger) { create(:user) }
+ let(:project_group) { create(:group) }
+ let(:project) { setup_project }
+ let!(:group) { setup_group }
+
+ shared_context 'source helpers' do
+ def get_source(source_type)
+ source_type == 'project' ? project : group
+ end
+ end
+
+ shared_examples 'GET /:sources/:id/badges' do |source_type|
+ include_context 'source helpers'
+
+ let(:source) { get_source(source_type) }
+
+ context "with :sources == #{source_type.pluralize}" do
+ it_behaves_like 'a 404 response when source is private' do
+ let(:route) { get api("/#{source_type.pluralize}/#{source.id}/badges", stranger) }
+ end
+
+ %i[master developer access_requester stranger].each do |type|
+ context "when authenticated as a #{type}" do
+ it 'returns 200' do
+ user = public_send(type)
+ badges_count = source_type == 'project' ? 3 : 2
+
+ get api("/#{source_type.pluralize}/#{source.id}/badges", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(badges_count)
+ end
+ end
+ end
+
+ it 'avoids N+1 queries' do
+ # Establish baseline
+ get api("/#{source_type.pluralize}/#{source.id}/badges", master)
+
+ control = ActiveRecord::QueryRecorder.new do
+ get api("/#{source_type.pluralize}/#{source.id}/badges", master)
+ end
+
+ project.add_developer(create(:user))
+
+ expect do
+ get api("/#{source_type.pluralize}/#{source.id}/badges", master)
+ end.not_to exceed_query_limit(control)
+ end
+ end
+ end
+
+ shared_examples 'GET /:sources/:id/badges/:badge_id' do |source_type|
+ include_context 'source helpers'
+
+ let(:source) { get_source(source_type) }
+
+ context "with :sources == #{source_type.pluralize}" do
+ it_behaves_like 'a 404 response when source is private' do
+ let(:route) { get api("/#{source_type.pluralize}/#{source.id}/badges/#{developer.id}", stranger) }
+ end
+
+ context 'when authenticated as a non-member' do
+ %i[master developer access_requester stranger].each do |type|
+ let(:badge) { source.badges.first }
+
+ context "as a #{type}" do
+ it 'returns 200' do
+ user = public_send(type)
+
+ get api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['id']).to eq(badge.id)
+ expect(json_response['link_url']).to eq(badge.link_url)
+ expect(json_response['rendered_link_url']).to eq(badge.rendered_link_url)
+ expect(json_response['image_url']).to eq(badge.image_url)
+ expect(json_response['rendered_image_url']).to eq(badge.rendered_image_url)
+ expect(json_response['kind']).to eq source_type
+ end
+ end
+ end
+ end
+ end
+ end
+
+ shared_examples 'POST /:sources/:id/badges' do |source_type|
+ include_context 'source helpers'
+
+ let(:source) { get_source(source_type) }
+ let(:example_url) { 'http://www.example.com' }
+ let(:example_url2) { 'http://www.example1.com' }
+
+ context "with :sources == #{source_type.pluralize}" do
+ it_behaves_like 'a 404 response when source is private' do
+ let(:route) do
+ post api("/#{source_type.pluralize}/#{source.id}/badges", stranger),
+ link_url: example_url, image_url: example_url2
+ end
+ end
+
+ context 'when authenticated as a non-member or member with insufficient rights' do
+ %i[access_requester stranger developer].each do |type|
+ context "as a #{type}" do
+ it 'returns 403' do
+ user = public_send(type)
+
+ post api("/#{source_type.pluralize}/#{source.id}/badges", user),
+ link_url: example_url, image_url: example_url2
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+ end
+ end
+
+ context 'when authenticated as a master/owner' do
+ it 'creates a new badge' do
+ expect do
+ post api("/#{source_type.pluralize}/#{source.id}/badges", master),
+ link_url: example_url, image_url: example_url2
+
+ expect(response).to have_gitlab_http_status(201)
+ end.to change { source.badges.count }.by(1)
+
+ expect(json_response['link_url']).to eq(example_url)
+ expect(json_response['image_url']).to eq(example_url2)
+ expect(json_response['kind']).to eq source_type
+ end
+ end
+
+ it 'returns 400 when link_url is not given' do
+ post api("/#{source_type.pluralize}/#{source.id}/badges", master),
+ link_url: example_url
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'returns 400 when image_url is not given' do
+ post api("/#{source_type.pluralize}/#{source.id}/badges", master),
+ image_url: example_url2
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'returns 400 when link_url or image_url is not valid' do
+ post api("/#{source_type.pluralize}/#{source.id}/badges", master),
+ link_url: 'whatever', image_url: 'whatever'
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+ end
+
+ shared_examples 'PUT /:sources/:id/badges/:badge_id' do |source_type|
+ include_context 'source helpers'
+
+ let(:source) { get_source(source_type) }
+
+ context "with :sources == #{source_type.pluralize}" do
+ let(:badge) { source.badges.first }
+ let(:example_url) { 'http://www.example.com' }
+ let(:example_url2) { 'http://www.example1.com' }
+
+ it_behaves_like 'a 404 response when source is private' do
+ let(:route) do
+ put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", stranger),
+ link_url: example_url
+ end
+ end
+
+ context 'when authenticated as a non-member or member with insufficient rights' do
+ %i[access_requester stranger developer].each do |type|
+ context "as a #{type}" do
+ it 'returns 403' do
+ user = public_send(type)
+
+ put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", user),
+ link_url: example_url
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+ end
+ end
+
+ context 'when authenticated as a master/owner' do
+ it 'updates the member' do
+ put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", master),
+ link_url: example_url, image_url: example_url2
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['link_url']).to eq(example_url)
+ expect(json_response['image_url']).to eq(example_url2)
+ expect(json_response['kind']).to eq source_type
+ end
+ end
+
+ it 'returns 400 when link_url or image_url is not valid' do
+ put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", master),
+ link_url: 'whatever', image_url: 'whatever'
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+ end
+
+ shared_examples 'DELETE /:sources/:id/badges/:badge_id' do |source_type|
+ include_context 'source helpers'
+
+ let(:source) { get_source(source_type) }
+
+ context "with :sources == #{source_type.pluralize}" do
+ let(:badge) { source.badges.first }
+
+ it_behaves_like 'a 404 response when source is private' do
+ let(:route) { delete api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", stranger) }
+ end
+
+ context 'when authenticated as a non-member or member with insufficient rights' do
+ %i[access_requester developer stranger].each do |type|
+ context "as a #{type}" do
+ it 'returns 403' do
+ user = public_send(type)
+
+ delete api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", user)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+ end
+ end
+
+ context 'when authenticated as a master/owner' do
+ it 'deletes the badge' do
+ expect do
+ delete api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", master)
+
+ expect(response).to have_gitlab_http_status(204)
+ end.to change { source.badges.count }.by(-1)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) { api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", master) }
+ end
+ end
+
+ it 'returns 404 if badge does not exist' do
+ delete api("/#{source_type.pluralize}/#{source.id}/badges/123", master)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+
+ shared_examples 'GET /:sources/:id/badges/render' do |source_type|
+ include_context 'source helpers'
+
+ let(:source) { get_source(source_type) }
+ let(:example_url) { 'http://www.example.com' }
+ let(:example_url2) { 'http://www.example1.com' }
+
+ context "with :sources == #{source_type.pluralize}" do
+ it_behaves_like 'a 404 response when source is private' do
+ let(:route) do
+ get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=#{example_url}&image_url=#{example_url2}", stranger)
+ end
+ end
+
+ context 'when authenticated as a non-member or member with insufficient rights' do
+ %i[access_requester stranger developer].each do |type|
+ context "as a #{type}" do
+ it 'returns 403' do
+ user = public_send(type)
+
+ get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=#{example_url}&image_url=#{example_url2}", user)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+ end
+ end
+
+ context 'when authenticated as a master/owner' do
+ it 'gets the rendered badge values' do
+ get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=#{example_url}&image_url=#{example_url2}", master)
+
+ expect(response).to have_gitlab_http_status(200)
+
+ expect(json_response.keys).to contain_exactly('link_url', 'rendered_link_url', 'image_url', 'rendered_image_url')
+ expect(json_response['link_url']).to eq(example_url)
+ expect(json_response['image_url']).to eq(example_url2)
+ expect(json_response['rendered_link_url']).to eq(example_url)
+ expect(json_response['rendered_image_url']).to eq(example_url2)
+ end
+ end
+
+ it 'returns 400 when link_url is not given' do
+ get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=#{example_url}", master)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'returns 400 when image_url is not given' do
+ get api("/#{source_type.pluralize}/#{source.id}/badges/render?image_url=#{example_url}", master)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'returns 400 when link_url or image_url is not valid' do
+ get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=whatever&image_url=whatever", master)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+ end
+
+ context 'when deleting a badge' do
+ context 'and the source is a project' do
+ it 'cannot delete badges owned by the project group' do
+ delete api("/projects/#{project.id}/badges/#{project_group.badges.first.id}", master)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+ end
+
+ describe 'Endpoints' do
+ %w(project group).each do |source_type|
+ it_behaves_like 'GET /:sources/:id/badges', source_type
+ it_behaves_like 'GET /:sources/:id/badges/:badge_id', source_type
+ it_behaves_like 'GET /:sources/:id/badges/render', source_type
+ it_behaves_like 'POST /:sources/:id/badges', source_type
+ it_behaves_like 'PUT /:sources/:id/badges/:badge_id', source_type
+ it_behaves_like 'DELETE /:sources/:id/badges/:badge_id', source_type
+ end
+ end
+
+ def setup_project
+ create(:project, :public, :access_requestable, creator_id: master.id, namespace: project_group) do |project|
+ project.add_developer(developer)
+ project.add_master(master)
+ project.request_access(access_requester)
+ project.project_badges << build(:project_badge, project: project)
+ project.project_badges << build(:project_badge, project: project)
+ project_group.badges << build(:group_badge, group: group)
+ end
+ end
+
+ def setup_group
+ create(:group, :public, :access_requestable) do |group|
+ group.add_developer(developer)
+ group.add_owner(master)
+ group.request_access(access_requester)
+ group.badges << build(:group_badge, group: group)
+ group.badges << build(:group_badge, group: group)
+ end
+ end
+end
diff --git a/spec/requests/api/discussions_spec.rb b/spec/requests/api/discussions_spec.rb
new file mode 100644
index 00000000000..4a44b219a67
--- /dev/null
+++ b/spec/requests/api/discussions_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe API::Discussions do
+ let(:user) { create(:user) }
+ let!(:project) { create(:project, :public, namespace: user.namespace) }
+ let(:private_user) { create(:user) }
+
+ before do
+ project.add_reporter(user)
+ end
+
+ context "when noteable is an Issue" do
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:issue_note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: user) }
+
+ it_behaves_like "discussions API", 'projects', 'issues', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { issue }
+ let(:note) { issue_note }
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ let!(:snippet) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet_note) { create(:discussion_note_on_snippet, noteable: snippet, project: project, author: user) }
+
+ it_behaves_like "discussions API", 'projects', 'snippets', 'id' do
+ let(:parent) { project }
+ let(:noteable) { snippet }
+ let(:note) { snippet_note }
+ end
+ end
+end
diff --git a/spec/requests/api/group_boards_spec.rb b/spec/requests/api/group_boards_spec.rb
new file mode 100644
index 00000000000..894c94688ba
--- /dev/null
+++ b/spec/requests/api/group_boards_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+describe API::GroupBoards do
+ set(:user) { create(:user) }
+ set(:non_member) { create(:user) }
+ set(:guest) { create(:user) }
+ set(:admin) { create(:user, :admin) }
+ set(:board_parent) { create(:group, :public) }
+
+ before do
+ board_parent.add_owner(user)
+ end
+
+ set(:project) { create(:project, :public, namespace: board_parent ) }
+
+ set(:dev_label) do
+ create(:group_label, title: 'Development', color: '#FFAABB', group: board_parent)
+ end
+
+ set(:test_label) do
+ create(:group_label, title: 'Testing', color: '#FFAACC', group: board_parent)
+ end
+
+ set(:ux_label) do
+ create(:group_label, title: 'UX', color: '#FF0000', group: board_parent)
+ end
+
+ set(:dev_list) do
+ create(:list, label: dev_label, position: 1)
+ end
+
+ set(:test_list) do
+ create(:list, label: test_label, position: 2)
+ end
+
+ set(:milestone) { create(:milestone, group: board_parent) }
+ set(:board_label) { create(:group_label, group: board_parent) }
+
+ set(:board) { create(:board, group: board_parent, lists: [dev_list, test_list]) }
+
+ it_behaves_like 'group and project boards', "/groups/:id/boards", false
+
+ describe 'POST /groups/:id/boards/lists' do
+ let(:url) { "/groups/#{board_parent.id}/boards/#{board.id}/lists" }
+
+ it 'does not create lists for child project labels' do
+ project_label = create(:label, project: project)
+
+ post api(url, user), label_id: project_label.id
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 827f4c04324..ca0aac87ba9 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -335,21 +335,8 @@ describe API::Internal do
end
context "git push" do
- context "gitaly disabled", :disable_gitaly do
- it "has the correct payload" do
- push(key, project)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
- expect(json_response["gl_repository"]).to eq("project-#{project.id}")
- expect(json_response["gitaly"]).to be_nil
- expect(user).not_to have_an_activity_record
- end
- end
-
- context "gitaly enabled" do
- it "has the correct payload" do
+ context 'project as namespace/project' do
+ it do
push(key, project)
expect(response).to have_gitlab_http_status(200)
@@ -365,17 +352,6 @@ describe API::Internal do
expect(user).not_to have_an_activity_record
end
end
-
- context 'project as namespace/project' do
- it do
- push(key, project)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
- expect(json_response["gl_repository"]).to eq("project-#{project.id}")
- end
- end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 484322752c0..3764aec0c71 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -616,6 +616,25 @@ describe API::MergeRequests do
expect(json_response['changes_count']).to eq('5+')
end
end
+
+ context 'for forked projects' do
+ let(:user2) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
+ let(:forked_project) { fork_project(project, user2, repository: true) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: forked_project,
+ target_project: project,
+ source_branch: 'fixes',
+ allow_maintainer_to_push: true)
+ end
+
+ it 'includes the `allow_maintainer_to_push` field' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user)
+
+ expect(json_response['allow_maintainer_to_push']).to be_truthy
+ end
+ end
end
describe 'GET /projects/:id/merge_requests/:merge_request_iid/participants' do
@@ -815,6 +834,7 @@ describe API::MergeRequests do
context 'forked projects' do
let!(:user2) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
let!(:forked_project) { fork_project(project, user2, repository: true) }
let!(:unrelated_project) { create(:project, namespace: create(:user).namespace, creator_id: user2.id) }
@@ -872,6 +892,14 @@ describe API::MergeRequests do
expect(response).to have_gitlab_http_status(400)
end
+ it 'allows setting `allow_maintainer_to_push`' do
+ post api("/projects/#{forked_project.id}/merge_requests", user2),
+ title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master",
+ author: user2, target_project_id: project.id, allow_maintainer_to_push: true
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['allow_maintainer_to_push']).to be_truthy
+ end
+
context 'when target_branch and target_project_id is specified' do
let(:params) do
{ title: 'Test merge_request',
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 981c9c27325..dd568c24c72 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -3,117 +3,86 @@ require 'spec_helper'
describe API::Notes do
let(:user) { create(:user) }
let!(:project) { create(:project, :public, namespace: user.namespace) }
- let!(:issue) { create(:issue, project: project, author: user) }
- let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
- let!(:snippet) { create(:project_snippet, project: project, author: user) }
- let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
- let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
- let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
-
- # For testing the cross-reference of a private issue in a public issue
let(:private_user) { create(:user) }
- let(:private_project) do
- create(:project, namespace: private_user.namespace)
- .tap { |p| p.add_master(private_user) }
- end
- let(:private_issue) { create(:issue, project: private_project) }
-
- let(:ext_proj) { create(:project, :public) }
- let(:ext_issue) { create(:issue, project: ext_proj) }
-
- let!(:cross_reference_note) do
- create :note,
- noteable: ext_issue, project: ext_proj,
- note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
- system: true
- end
before do
project.add_reporter(user)
end
- describe "GET /projects/:id/noteable/:noteable_id/notes" do
- context "when noteable is an Issue" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: issue, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
+ context "when noteable is an Issue" do
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
+ it_behaves_like "noteable API", 'projects', 'issues', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { issue }
+ let(:note) { issue_note }
+ end
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes??order_by=updated_at&sort=asc", user)
+ context 'when user does not have access to create noteable' do
+ let(:private_issue) { create(:issue, project: create(:project, :private)) }
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
+ ##
+ # We are posting to project user has access to, but we use issue id
+ # from a different project, see #15577
+ #
+ before do
+ post api("/projects/#{private_issue.project.id}/issues/#{private_issue.iid}/notes", user),
+ body: 'Hi!'
+ end
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
+ it 'responds with resource not found error' do
+ expect(response.status).to eq 404
end
- it "returns an array of issue notes" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
+ it 'does not create new note' do
+ expect(private_issue.notes.reload).to be_empty
+ end
+ end
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(issue_note.note)
+ context "when referencing other project" do
+ # For testing the cross-reference of a private issue in a public project
+ let(:private_project) do
+ create(:project, namespace: private_user.namespace)
+ .tap { |p| p.add_master(private_user) }
end
+ let(:private_issue) { create(:issue, project: private_project) }
- it "returns a 404 error when issue id not found" do
- get api("/projects/#{project.id}/issues/12345/notes", user)
+ let(:ext_proj) { create(:project, :public) }
+ let(:ext_issue) { create(:issue, project: ext_proj) }
- expect(response).to have_gitlab_http_status(404)
+ let!(:cross_reference_note) do
+ create :note,
+ noteable: ext_issue, project: ext_proj,
+ note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
+ system: true
end
- context "and current user cannot view the notes" do
- it "returns an empty array" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response).to be_empty
- end
+ describe "GET /projects/:id/noteable/:noteable_id/notes" do
+ context "current user cannot view the notes" do
+ it "returns an empty array" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
- context "and issue is confidential" do
- before do
- ext_issue.update_attributes(confidential: true)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response).to be_empty
end
- it "returns 404" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
+ context "issue is confidential" do
+ before do
+ ext_issue.update_attributes(confidential: true)
+ end
- expect(response).to have_gitlab_http_status(404)
+ it "returns 404" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
- context "and current user can view the note" do
+ context "current user can view the note" do
it "returns an empty array" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", private_user)
@@ -124,172 +93,29 @@ describe API::Notes do
end
end
end
- end
-
- context "when noteable is a Snippet" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: snippet, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes??order_by=updated_at&sort=asc", user)
+ describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
+ context "current user cannot view the notes" do
+ it "returns a 404 error" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", user)
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
- end
- it "returns an array of snippet notes" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(snippet_note.note)
- end
-
- it "returns a 404 error when snippet id not found" do
- get api("/projects/#{project.id}/snippets/42/notes", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it "returns 404 when not authorized" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", private_user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context "when noteable is a Merge Request" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: merge_request, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes??order_by=updated_at&sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
- end
- it "returns an array of merge_requests notes" do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(merge_request_note.note)
- end
-
- it "returns a 404 error if merge request id not found" do
- get api("/projects/#{project.id}/merge_requests/4444/notes", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it "returns 404 when not authorized" do
- get api("/projects/#{project.id}/merge_requests/4444/notes", private_user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
- end
-
- describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
- context "when noteable is an Issue" do
- it "returns an issue note by id" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq(issue_note.note)
- end
-
- it "returns a 404 error if issue note not found" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- context "and current user cannot view the note" do
- it "returns a 404 error" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- context "when issue is confidential" do
- before do
- issue.update_attributes(confidential: true)
+ expect(response).to have_gitlab_http_status(404)
end
- it "returns 404" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user)
+ context "when issue is confidential" do
+ before do
+ issue.update_attributes(confidential: true)
+ end
- expect(response).to have_gitlab_http_status(404)
+ it "returns 404" do
+ get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
- context "and current user can view the note" do
+ context "current user can view the note" do
it "returns an issue note by id" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", private_user)
@@ -299,132 +125,27 @@ describe API::Notes do
end
end
end
-
- context "when noteable is a Snippet" do
- it "returns a snippet note by id" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq(snippet_note.note)
- end
-
- it "returns a 404 error if snippet note not found" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
end
- describe "POST /projects/:id/noteable/:noteable_id/notes" do
- context "when noteable is an Issue" do
- it "creates a new issue note" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- end
-
- it "returns a 400 bad request error if body not given" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
-
- it "returns a 401 unauthorized error if user not authenticated" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes"), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(401)
- end
-
- context 'when an admin or owner makes the request' do
- it 'accepts the creation date to be set' do
- creation_time = 2.weeks.ago
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user),
- body: 'hi!', created_at: creation_time
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
- end
- end
-
- context 'when the user is posting an award emoji on an issue created by someone else' do
- let(:issue2) { create(:issue, project: project) }
-
- it 'creates a new issue note' do
- post api("/projects/#{project.id}/issues/#{issue2.iid}/notes", user), body: ':+1:'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq(':+1:')
- end
- end
-
- context 'when the user is posting an award emoji on his/her own issue' do
- it 'creates a new issue note' do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: ':+1:'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq(':+1:')
- end
- end
- end
-
- context "when noteable is a Snippet" do
- it "creates a new snippet note" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
+ context "when noteable is a Snippet" do
+ let!(:snippet) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- end
-
- it "returns a 400 bad request error if body not given" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
-
- it "returns a 401 unauthorized error if user not authenticated" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(401)
- end
+ it_behaves_like "noteable API", 'projects', 'snippets', 'id' do
+ let(:parent) { project }
+ let(:noteable) { snippet }
+ let(:note) { snippet_note }
end
+ end
- context 'when user does not have access to read the noteable' do
- it 'responds with 404' do
- project = create(:project, :private) { |p| p.add_guest(user) }
- issue = create(:issue, :confidential, project: project)
-
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user),
- body: 'Foo'
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context 'when user does not have access to create noteable' do
- let(:private_issue) { create(:issue, project: create(:project, :private)) }
-
- ##
- # We are posting to project user has access to, but we use issue id
- # from a different project, see #15577
- #
- before do
- post api("/projects/#{private_issue.project.id}/issues/#{private_issue.iid}/notes", user),
- body: 'Hi!'
- end
-
- it 'responds with resource not found error' do
- expect(response.status).to eq 404
- end
+ context "when noteable is a Merge Request" do
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
+ let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
- it 'does not create new note' do
- expect(private_issue.notes.reload).to be_empty
- end
+ it_behaves_like "noteable API", 'projects', 'merge_requests', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { merge_request }
+ let(:note) { merge_request_note }
end
context 'when the merge request discussion is locked' do
@@ -461,145 +182,4 @@ describe API::Notes do
end
end
end
-
- describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do
- it "creates an activity event when an issue note is created" do
- expect(Event).to receive(:create!)
-
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: 'hi!'
- end
- end
-
- describe 'PUT /projects/:id/noteable/:noteable_id/notes/:note_id' do
- context 'when noteable is an Issue' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user),
- body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 400 bad request error if body not given' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
- end
-
- context 'when noteable is a Snippet' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/12345", user), body: "Hello!"
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context 'when noteable is a Merge Request' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/"\
- "notes/#{merge_request_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/"\
- "notes/12345", user), body: "Hello!"
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
- end
-
- describe 'DELETE /projects/:id/noteable/:noteable_id/notes/:note_id' do
- context 'when noteable is an Issue' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", user) }
- end
- end
-
- context 'when noteable is a Snippet' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user) }
- end
- end
-
- context 'when noteable is a Merge Request' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/#{merge_request_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/#{merge_request_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes/#{merge_request_note.id}", user) }
- end
- end
- end
end
diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb
index 025165622b7..dc3a116c060 100644
--- a/spec/requests/api/pages_domains_spec.rb
+++ b/spec/requests/api/pages_domains_spec.rb
@@ -16,7 +16,7 @@ describe API::PagesDomains do
let(:route) { "/projects/#{project.id}/pages/domains" }
let(:route_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain.domain}" }
- let(:route_domain_path) { "/projects/#{project.path_with_namespace.gsub('/', '%2F')}/pages/domains/#{pages_domain.domain}" }
+ let(:route_domain_path) { "/projects/#{project.full_path.gsub('/', '%2F')}/pages/domains/#{pages_domain.domain}" }
let(:route_secure_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain_secure.domain}" }
let(:route_expired_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain_expired.domain}" }
let(:route_vacant_domain) { "/projects/#{project.id}/pages/domains/www.vacant-domain.test" }
diff --git a/spec/requests/api/project_export_spec.rb b/spec/requests/api/project_export_spec.rb
new file mode 100644
index 00000000000..fbed527963f
--- /dev/null
+++ b/spec/requests/api/project_export_spec.rb
@@ -0,0 +1,290 @@
+require 'spec_helper'
+
+describe API::ProjectExport do
+ set(:project) { create(:project) }
+ set(:project_none) { create(:project) }
+ set(:project_started) { create(:project) }
+ set(:project_finished) { create(:project) }
+ set(:user) { create(:user) }
+ set(:admin) { create(:admin) }
+
+ let(:path) { "/projects/#{project.id}/export" }
+ let(:path_none) { "/projects/#{project_none.id}/export" }
+ let(:path_started) { "/projects/#{project_started.id}/export" }
+ let(:path_finished) { "/projects/#{project_finished.id}/export" }
+
+ let(:download_path) { "/projects/#{project.id}/export/download" }
+ let(:download_path_none) { "/projects/#{project_none.id}/export/download" }
+ let(:download_path_started) { "/projects/#{project_started.id}/export/download" }
+ let(:download_path_finished) { "/projects/#{project_finished.id}/export/download" }
+
+ let(:export_path) { "#{Dir.tmpdir}/project_export_spec" }
+
+ before do
+ allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
+
+ # simulate exporting work directory
+ FileUtils.mkdir_p File.join(project_started.export_path, 'securerandom-hex')
+
+ # simulate exported
+ FileUtils.mkdir_p project_finished.export_path
+ FileUtils.touch File.join(project_finished.export_path, '_export.tar.gz')
+ end
+
+ after do
+ FileUtils.rm_rf(export_path, secure: true)
+ end
+
+ shared_examples_for 'when project export is disabled' do
+ before do
+ stub_application_setting(project_export_enabled?: false)
+ end
+
+ it_behaves_like '404 response'
+ end
+
+ describe 'GET /projects/:project_id/export' do
+ shared_examples_for 'get project export status not found' do
+ it_behaves_like '404 response' do
+ let(:request) { get api(path, user) }
+ end
+ end
+
+ shared_examples_for 'get project export status denied' do
+ it_behaves_like '403 response' do
+ let(:request) { get api(path, user) }
+ end
+ end
+
+ shared_examples_for 'get project export status ok' do
+ it 'is none' do
+ get api(path_none, user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/project/export_status')
+ expect(json_response['export_status']).to eq('none')
+ end
+
+ it 'is started' do
+ get api(path_started, user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/project/export_status')
+ expect(json_response['export_status']).to eq('started')
+ end
+
+ it 'is finished' do
+ get api(path_finished, user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/project/export_status')
+ expect(json_response['export_status']).to eq('finished')
+ end
+ end
+
+ it_behaves_like 'when project export is disabled' do
+ let(:request) { get api(path, admin) }
+ end
+
+ context 'when project export is enabled' do
+ context 'when user is an admin' do
+ let(:user) { admin }
+
+ it_behaves_like 'get project export status ok'
+ end
+
+ context 'when user is a master' do
+ before do
+ project.add_master(user)
+ project_none.add_master(user)
+ project_started.add_master(user)
+ project_finished.add_master(user)
+ end
+
+ it_behaves_like 'get project export status ok'
+ end
+
+ context 'when user is a developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'get project export status denied'
+ end
+
+ context 'when user is a reporter' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it_behaves_like 'get project export status denied'
+ end
+
+ context 'when user is a guest' do
+ before do
+ project.add_guest(user)
+ end
+
+ it_behaves_like 'get project export status denied'
+ end
+
+ context 'when user is not a member' do
+ it_behaves_like 'get project export status not found'
+ end
+ end
+ end
+
+ describe 'GET /projects/:project_id/export/download' do
+ shared_examples_for 'get project export download not found' do
+ it_behaves_like '404 response' do
+ let(:request) { get api(download_path, user) }
+ end
+ end
+
+ shared_examples_for 'get project export download denied' do
+ it_behaves_like '403 response' do
+ let(:request) { get api(download_path, user) }
+ end
+ end
+
+ shared_examples_for 'get project export download' do
+ it_behaves_like '404 response' do
+ let(:request) { get api(download_path_none, user) }
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) { get api(download_path_started, user) }
+ end
+
+ it 'downloads' do
+ get api(download_path_finished, user)
+
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+
+ it_behaves_like 'when project export is disabled' do
+ let(:request) { get api(download_path, admin) }
+ end
+
+ context 'when project export is enabled' do
+ context 'when user is an admin' do
+ let(:user) { admin }
+
+ it_behaves_like 'get project export download'
+ end
+
+ context 'when user is a master' do
+ before do
+ project.add_master(user)
+ project_none.add_master(user)
+ project_started.add_master(user)
+ project_finished.add_master(user)
+ end
+
+ it_behaves_like 'get project export download'
+ end
+
+ context 'when user is a developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'get project export download denied'
+ end
+
+ context 'when user is a reporter' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it_behaves_like 'get project export download denied'
+ end
+
+ context 'when user is a guest' do
+ before do
+ project.add_guest(user)
+ end
+
+ it_behaves_like 'get project export download denied'
+ end
+
+ context 'when user is not a member' do
+ it_behaves_like 'get project export download not found'
+ end
+ end
+ end
+
+ describe 'POST /projects/:project_id/export' do
+ shared_examples_for 'post project export start not found' do
+ it_behaves_like '404 response' do
+ let(:request) { post api(path, user) }
+ end
+ end
+
+ shared_examples_for 'post project export start denied' do
+ it_behaves_like '403 response' do
+ let(:request) { post api(path, user) }
+ end
+ end
+
+ shared_examples_for 'post project export start' do
+ it 'starts' do
+ post api(path, user)
+
+ expect(response).to have_gitlab_http_status(202)
+ end
+ end
+
+ it_behaves_like 'when project export is disabled' do
+ let(:request) { post api(path, admin) }
+ end
+
+ context 'when project export is enabled' do
+ context 'when user is an admin' do
+ let(:user) { admin }
+
+ it_behaves_like 'post project export start'
+ end
+
+ context 'when user is a master' do
+ before do
+ project.add_master(user)
+ project_none.add_master(user)
+ project_started.add_master(user)
+ project_finished.add_master(user)
+ end
+
+ it_behaves_like 'post project export start'
+ end
+
+ context 'when user is a developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'post project export start denied'
+ end
+
+ context 'when user is a reporter' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it_behaves_like 'post project export start denied'
+ end
+
+ context 'when user is a guest' do
+ before do
+ project.add_guest(user)
+ end
+
+ it_behaves_like 'post project export start denied'
+ end
+
+ context 'when user is not a member' do
+ it_behaves_like 'post project export start not found'
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 72cafac3f90..95c23726a79 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -698,10 +698,10 @@ describe API::Runner do
end
end
- context 'when tace is given' do
+ context 'when trace is given' do
it 'creates a trace artifact' do
allow(BuildFinishedWorker).to receive(:perform_async).with(job.id) do
- CreateTraceArtifactWorker.new.perform(job.id)
+ ArchiveTraceWorker.new.perform(job.id)
end
update_job(state: 'success', trace: 'BUILD TRACE UPDATED')
@@ -1100,11 +1100,13 @@ describe API::Runner do
context 'posts artifacts file and metadata file' do
let!(:artifacts) { file_upload }
+ let!(:artifacts_sha256) { Digest::SHA256.file(artifacts.path).hexdigest }
let!(:metadata) { file_upload2 }
let(:stored_artifacts_file) { job.reload.artifacts_file.file }
let(:stored_metadata_file) { job.reload.artifacts_metadata.file }
let(:stored_artifacts_size) { job.reload.artifacts_size }
+ let(:stored_artifacts_sha256) { job.reload.job_artifacts_archive.file_sha256 }
before do
post(api("/jobs/#{job.id}/artifacts"), post_data, headers_with_token)
@@ -1114,6 +1116,7 @@ describe API::Runner do
let(:post_data) do
{ 'file.path' => artifacts.path,
'file.name' => artifacts.original_filename,
+ 'file.sha256' => artifacts_sha256,
'metadata.path' => metadata.path,
'metadata.name' => metadata.original_filename }
end
@@ -1123,6 +1126,7 @@ describe API::Runner do
expect(stored_artifacts_file.original_filename).to eq(artifacts.original_filename)
expect(stored_metadata_file.original_filename).to eq(metadata.original_filename)
expect(stored_artifacts_size).to eq(72821)
+ expect(stored_artifacts_sha256).to eq(artifacts_sha256)
end
end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 0467e0251b3..6dbbb1ad7bb 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -795,9 +795,9 @@ describe 'Git HTTP requests' do
let(:path) { 'doesnt/exist.git' }
before do
- allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true)
- allow(Gitlab::Auth::LDAP::Authentication).to receive(:login).and_return(nil)
- allow(Gitlab::Auth::LDAP::Authentication).to receive(:login).with(user.username, user.password).and_return(user)
+ allow(Gitlab::Auth::OAuth::Provider).to receive(:enabled?).and_return(true)
+ allow_any_instance_of(Gitlab::Auth::LDAP::Authentication).to receive(:login).and_return(nil)
+ allow_any_instance_of(Gitlab::Auth::LDAP::Authentication).to receive(:login).with(user.username, user.password).and_return(user)
end
it_behaves_like 'pulls require Basic HTTP Authentication'
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 56d025f0176..9345671a1a7 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -9,7 +9,7 @@ require 'spec_helper'
# user_calendar_activities GET /u/:username/calendar_activities(.:format)
describe UsersController, "routing" do
it "to #show" do
- allow_any_instance_of(UserUrlConstrainer).to receive(:matches?).and_return(true)
+ allow_any_instance_of(::Constraints::UserUrlConstrainer).to receive(:matches?).and_return(true)
expect(get("/User")).to route_to('users#show', username: 'User')
end
@@ -210,7 +210,7 @@ describe Profiles::KeysController, "routing" do
# get all the ssh-keys of a user
it "to #get_keys" do
- allow_any_instance_of(UserUrlConstrainer).to receive(:matches?).and_return(true)
+ allow_any_instance_of(::Constraints::UserUrlConstrainer).to receive(:matches?).and_return(true)
expect(get("/foo.keys")).to route_to('profiles/keys#get_keys', username: 'foo')
end
diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb
index 80a271ba7fb..d2072198d83 100644
--- a/spec/serializers/merge_request_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_widget_entity_spec.rb
@@ -147,9 +147,9 @@ describe MergeRequestWidgetEntity do
allow(resource).to receive(:diff_head_sha) { 'sha' }
end
- context 'when no diff head commit' do
+ context 'when diff head commit is empty' do
it 'returns nil' do
- allow(resource).to receive(:diff_head_commit) { nil }
+ allow(resource).to receive(:diff_head_sha) { '' }
expect(subject[:diff_head_sha]).to be_nil
end
@@ -157,8 +157,6 @@ describe MergeRequestWidgetEntity do
context 'when diff head commit present' do
it 'returns diff head commit short id' do
- allow(resource).to receive(:diff_head_commit) { double }
-
expect(subject[:diff_head_sha]).to eq('sha')
end
end
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 9128280eb5a..290eeae828e 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -172,7 +172,7 @@ describe Auth::ContainerRegistryAuthenticationService do
end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:*" }
+ { scope: "repository:#{project.full_path}:*" }
end
it_behaves_like 'an inaccessible'
@@ -200,7 +200,7 @@ describe Auth::ContainerRegistryAuthenticationService do
end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:*" }
+ { scope: "repository:#{project.full_path}:*" }
end
it_behaves_like 'an inaccessible'
@@ -239,7 +239,7 @@ describe Auth::ContainerRegistryAuthenticationService do
end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:*" }
+ { scope: "repository:#{project.full_path}:*" }
end
it_behaves_like 'an inaccessible'
@@ -270,7 +270,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'disallow anyone to delete images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:*" }
+ { scope: "repository:#{project.full_path}:*" }
end
it_behaves_like 'an inaccessible'
@@ -311,7 +311,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'disallow anyone to delete images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:*" }
+ { scope: "repository:#{project.full_path}:*" }
end
it_behaves_like 'an inaccessible'
@@ -323,7 +323,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'disallow anyone to pull or push images' do
let(:current_user) { create(:user, external: true) }
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{project.full_path}:pull,push" }
end
it_behaves_like 'an inaccessible'
@@ -333,7 +333,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'disallow anyone to delete images' do
let(:current_user) { create(:user, external: true) }
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:*" }
+ { scope: "repository:#{project.full_path}:*" }
end
it_behaves_like 'an inaccessible'
@@ -359,7 +359,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'allow to delete images' do
let(:current_params) do
- { scope: "repository:#{current_project.path_with_namespace}:*" }
+ { scope: "repository:#{current_project.full_path}:*" }
end
it_behaves_like 'a deletable' do
@@ -398,7 +398,7 @@ describe Auth::ContainerRegistryAuthenticationService do
context 'disallow to delete images' do
let(:current_params) do
- { scope: "repository:#{current_project.path_with_namespace}:*" }
+ { scope: "repository:#{current_project.full_path}:*" }
end
it_behaves_like 'an inaccessible' do
diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb
index db51a524e79..a715261cd6c 100644
--- a/spec/services/boards/create_service_spec.rb
+++ b/spec/services/boards/create_service_spec.rb
@@ -2,34 +2,20 @@ require 'spec_helper'
describe Boards::CreateService do
describe '#execute' do
- let(:project) { create(:project) }
+ context 'when board parent is a project' do
+ let(:parent) { create(:project) }
- subject(:service) { described_class.new(project, double) }
+ subject(:service) { described_class.new(parent, double) }
- context 'when project does not have a board' do
- it 'creates a new board' do
- expect { service.execute }.to change(Board, :count).by(1)
- end
-
- it 'creates the default lists' do
- board = service.execute
-
- expect(board.lists.size).to eq 2
- expect(board.lists.first).to be_backlog
- expect(board.lists.last).to be_closed
- end
+ it_behaves_like 'boards create service'
end
- context 'when project has a board' do
- before do
- create(:board, project: project)
- end
+ context 'when board parent is a group' do
+ let(:parent) { create(:group) }
- it 'does not create a new board' do
- expect(service).to receive(:can_create_board?) { false }
+ subject(:service) { described_class.new(parent, double) }
- expect { service.execute }.not_to change(project.boards, :count)
- end
+ it_behaves_like 'boards create service'
end
end
end
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index ff5733b7064..b4efa3e44b6 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -2,98 +2,103 @@ require 'spec_helper'
describe Boards::Issues::ListService do
describe '#execute' do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:board) { create(:board, project: project) }
-
- let(:bug) { create(:label, project: project, name: 'Bug') }
- let(:development) { create(:label, project: project, name: 'Development') }
- let(:testing) { create(:label, project: project, name: 'Testing') }
- let(:p1) { create(:label, title: 'P1', project: project, priority: 1) }
- let(:p2) { create(:label, title: 'P2', project: project, priority: 2) }
- let(:p3) { create(:label, title: 'P3', project: project, priority: 3) }
-
- let!(:backlog) { create(:backlog_list, board: board) }
- let!(:list1) { create(:list, board: board, label: development, position: 0) }
- let!(:list2) { create(:list, board: board, label: testing, position: 1) }
- let!(:closed) { create(:closed_list, board: board) }
-
- let!(:opened_issue1) { create(:labeled_issue, project: project, labels: [bug]) }
- let!(:opened_issue2) { create(:labeled_issue, project: project, labels: [p2]) }
- let!(:reopened_issue1) { create(:issue, :opened, project: project) }
-
- let!(:list1_issue1) { create(:labeled_issue, project: project, labels: [p2, development]) }
- let!(:list1_issue2) { create(:labeled_issue, project: project, labels: [development]) }
- let!(:list1_issue3) { create(:labeled_issue, project: project, labels: [development, p1]) }
- let!(:list2_issue1) { create(:labeled_issue, project: project, labels: [testing]) }
-
- let!(:closed_issue1) { create(:labeled_issue, :closed, project: project, labels: [bug]) }
- let!(:closed_issue2) { create(:labeled_issue, :closed, project: project, labels: [p3]) }
- let!(:closed_issue3) { create(:issue, :closed, project: project) }
- let!(:closed_issue4) { create(:labeled_issue, :closed, project: project, labels: [p1]) }
- let!(:closed_issue5) { create(:labeled_issue, :closed, project: project, labels: [development]) }
-
- before do
- project.add_developer(user)
- end
-
- it 'delegates search to IssuesFinder' do
- params = { board_id: board.id, id: list1.id }
-
- expect_any_instance_of(IssuesFinder).to receive(:execute).once.and_call_original
+ context 'when parent is a project' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:board) { create(:board, project: project) }
+
+ let(:m1) { create(:milestone, project: project) }
+ let(:m2) { create(:milestone, project: project) }
+
+ let(:bug) { create(:label, project: project, name: 'Bug') }
+ let(:development) { create(:label, project: project, name: 'Development') }
+ let(:testing) { create(:label, project: project, name: 'Testing') }
+ let(:p1) { create(:label, title: 'P1', project: project, priority: 1) }
+ let(:p2) { create(:label, title: 'P2', project: project, priority: 2) }
+ let(:p3) { create(:label, title: 'P3', project: project, priority: 3) }
+
+ let!(:backlog) { create(:backlog_list, board: board) }
+ let!(:list1) { create(:list, board: board, label: development, position: 0) }
+ let!(:list2) { create(:list, board: board, label: testing, position: 1) }
+ let!(:closed) { create(:closed_list, board: board) }
+
+ let!(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
+ let!(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2]) }
+ let!(:reopened_issue1) { create(:issue, :opened, project: project, title: 'Issue 3' ) }
+
+ let!(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, development]) }
+ let!(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
+ let!(:list1_issue3) { create(:labeled_issue, project: project, milestone: m1, labels: [development, p1]) }
+ let!(:list2_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [testing]) }
+
+ let!(:closed_issue1) { create(:labeled_issue, :closed, project: project, labels: [bug]) }
+ let!(:closed_issue2) { create(:labeled_issue, :closed, project: project, labels: [p3]) }
+ let!(:closed_issue3) { create(:issue, :closed, project: project) }
+ let!(:closed_issue4) { create(:labeled_issue, :closed, project: project, labels: [p1]) }
+ let!(:closed_issue5) { create(:labeled_issue, :closed, project: project, labels: [development]) }
+
+ let(:parent) { project }
+
+ before do
+ project.add_developer(user)
+ end
- described_class.new(project, user, params).execute
+ it_behaves_like 'issues list service'
end
- context 'issues are ordered by priority' do
- it 'returns opened issues when list_id is missing' do
- params = { board_id: board.id }
-
- issues = described_class.new(project, user, params).execute
-
- expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1]
- end
+ context 'when parent is a group' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project) { create(:project, :empty_repo, namespace: group) }
+ let(:project1) { create(:project, :empty_repo, namespace: group) }
+ let(:board) { create(:board, group: group) }
- it 'returns opened issues when listing issues from Backlog' do
- params = { board_id: board.id, id: backlog.id }
+ let(:m1) { create(:milestone, group: group) }
+ let(:m2) { create(:milestone, group: group) }
- issues = described_class.new(project, user, params).execute
+ let(:bug) { create(:group_label, group: group, name: 'Bug') }
+ let(:development) { create(:group_label, group: group, name: 'Development') }
+ let(:testing) { create(:group_label, group: group, name: 'Testing') }
- expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1]
- end
+ let(:p1) { create(:group_label, title: 'P1', group: group) }
+ let(:p2) { create(:group_label, title: 'P2', group: group) }
+ let(:p3) { create(:group_label, title: 'P3', group: group) }
- it 'returns closed issues when listing issues from Closed' do
- params = { board_id: board.id, id: closed.id }
+ let(:p1_project) { create(:label, title: 'P1_project', project: project, priority: 1) }
+ let(:p2_project) { create(:label, title: 'P2_project', project: project, priority: 2) }
+ let(:p3_project) { create(:label, title: 'P3_project', project: project, priority: 3) }
- issues = described_class.new(project, user, params).execute
+ let(:p1_project1) { create(:label, title: 'P1_project1', project: project1, priority: 1) }
+ let(:p2_project1) { create(:label, title: 'P2_project1', project: project1, priority: 2) }
+ let(:p3_project1) { create(:label, title: 'P3_project1', project: project1, priority: 3) }
- expect(issues).to eq [closed_issue4, closed_issue2, closed_issue5, closed_issue3, closed_issue1]
- end
+ let!(:backlog) { create(:backlog_list, board: board) }
+ let!(:list1) { create(:list, board: board, label: development, position: 0) }
+ let!(:list2) { create(:list, board: board, label: testing, position: 1) }
+ let!(:closed) { create(:closed_list, board: board) }
- it 'returns opened issues that have label list applied when listing issues from a label list' do
- params = { board_id: board.id, id: list1.id }
+ let!(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
+ let!(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2, p2_project]) }
+ let!(:reopened_issue1) { create(:issue, state: 'opened', project: project, title: 'Issue 3', closed_at: Time.now ) }
- issues = described_class.new(project, user, params).execute
+ let!(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, p2_project, development]) }
+ let!(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
+ let!(:list1_issue3) { create(:labeled_issue, project: project1, milestone: m1, labels: [development, p1, p1_project1]) }
+ let!(:list2_issue1) { create(:labeled_issue, project: project1, milestone: m1, labels: [testing]) }
- expect(issues).to eq [list1_issue3, list1_issue1, list1_issue2]
- end
- end
+ let!(:closed_issue1) { create(:labeled_issue, :closed, project: project, labels: [bug]) }
+ let!(:closed_issue2) { create(:labeled_issue, :closed, project: project, labels: [p3, p3_project]) }
+ let!(:closed_issue3) { create(:issue, :closed, project: project1) }
+ let!(:closed_issue4) { create(:labeled_issue, :closed, project: project1, labels: [p1, p1_project1]) }
+ let!(:closed_issue5) { create(:labeled_issue, :closed, project: project1, labels: [development]) }
- context 'with list that does not belong to the board' do
- it 'raises an error' do
- list = create(:list)
- service = described_class.new(project, user, board_id: board.id, id: list.id)
+ let(:parent) { group }
- expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound)
+ before do
+ group.add_developer(user)
end
- end
-
- context 'with invalid list id' do
- it 'raises an error' do
- service = described_class.new(project, user, board_id: board.id, id: nil)
- expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound)
- end
+ it_behaves_like 'issues list service'
end
end
end
diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb
index 280e411683e..0a6b6d880d3 100644
--- a/spec/services/boards/issues/move_service_spec.rb
+++ b/spec/services/boards/issues/move_service_spec.rb
@@ -2,108 +2,53 @@ require 'spec_helper'
describe Boards::Issues::MoveService do
describe '#execute' do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:board1) { create(:board, project: project) }
-
- let(:bug) { create(:label, project: project, name: 'Bug') }
- let(:development) { create(:label, project: project, name: 'Development') }
- let(:testing) { create(:label, project: project, name: 'Testing') }
-
- let!(:list1) { create(:list, board: board1, label: development, position: 0) }
- let!(:list2) { create(:list, board: board1, label: testing, position: 1) }
- let!(:closed) { create(:closed_list, board: board1) }
-
- before do
- project.add_developer(user)
- end
-
- context 'when moving an issue between lists' do
- let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) }
- let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list2.id } }
-
- it 'delegates the label changes to Issues::UpdateService' do
- expect_any_instance_of(Issues::UpdateService).to receive(:execute).with(issue).once
-
- described_class.new(project, user, params).execute(issue)
- end
-
- it 'removes the label from the list it came from and adds the label of the list it goes to' do
- described_class.new(project, user, params).execute(issue)
-
- expect(issue.reload.labels).to contain_exactly(bug, testing)
- end
- end
-
- context 'when moving to closed' do
+ context 'when parent is a project' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:board1) { create(:board, project: project) }
let(:board2) { create(:board, project: project) }
+
+ let(:bug) { create(:label, project: project, name: 'Bug') }
+ let(:development) { create(:label, project: project, name: 'Development') }
+ let(:testing) { create(:label, project: project, name: 'Testing') }
let(:regression) { create(:label, project: project, name: 'Regression') }
- let!(:list3) { create(:list, board: board2, label: regression, position: 1) }
- let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression]) }
- let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: closed.id } }
+ let!(:list1) { create(:list, board: board1, label: development, position: 0) }
+ let!(:list2) { create(:list, board: board1, label: testing, position: 1) }
+ let!(:closed) { create(:closed_list, board: board1) }
- it 'delegates the close proceedings to Issues::CloseService' do
- expect_any_instance_of(Issues::CloseService).to receive(:execute).with(issue).once
+ let(:parent) { project }
- described_class.new(project, user, params).execute(issue)
+ before do
+ parent.add_developer(user)
end
- it 'removes all list-labels from project boards and close the issue' do
- described_class.new(project, user, params).execute(issue)
- issue.reload
-
- expect(issue.labels).to contain_exactly(bug)
- expect(issue).to be_closed
- end
+ it_behaves_like 'issues move service'
end
- context 'when moving from closed' do
- let(:issue) { create(:labeled_issue, :closed, project: project, labels: [bug]) }
- let(:params) { { board_id: board1.id, from_list_id: closed.id, to_list_id: list2.id } }
-
- it 'delegates the re-open proceedings to Issues::ReopenService' do
- expect_any_instance_of(Issues::ReopenService).to receive(:execute).with(issue).once
-
- described_class.new(project, user, params).execute(issue)
- end
-
- it 'adds the label of the list it goes to and reopen the issue' do
- described_class.new(project, user, params).execute(issue)
- issue.reload
-
- expect(issue.labels).to contain_exactly(bug, testing)
- expect(issue).to be_opened
- end
- end
+ context 'when parent is a group' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
+ let(:board1) { create(:board, group: group) }
+ let(:board2) { create(:board, group: group) }
- context 'when moving to same list' do
- let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) }
- let(:issue1) { create(:labeled_issue, project: project, labels: [bug, development]) }
- let(:issue2) { create(:labeled_issue, project: project, labels: [bug, development]) }
- let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list1.id } }
+ let(:bug) { create(:group_label, group: group, name: 'Bug') }
+ let(:development) { create(:group_label, group: group, name: 'Development') }
+ let(:testing) { create(:group_label, group: group, name: 'Testing') }
+ let(:regression) { create(:group_label, group: group, name: 'Regression') }
- it 'returns false' do
- expect(described_class.new(project, user, params).execute(issue)).to eq false
- end
+ let!(:list1) { create(:list, board: board1, label: development, position: 0) }
+ let!(:list2) { create(:list, board: board1, label: testing, position: 1) }
+ let!(:closed) { create(:closed_list, board: board1) }
- it 'keeps issues labels' do
- described_class.new(project, user, params).execute(issue)
+ let(:parent) { group }
- expect(issue.reload.labels).to contain_exactly(bug, development)
+ before do
+ parent.add_developer(user)
end
- it 'sorts issues' do
- [issue, issue1, issue2].each do |issue|
- issue.move_to_end && issue.save!
- end
-
- params.merge!(move_after_id: issue1.id, move_before_id: issue2.id)
-
- described_class.new(project, user, params).execute(issue)
-
- expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
- end
+ it_behaves_like 'issues move service'
end
end
end
diff --git a/spec/services/boards/list_service_spec.rb b/spec/services/boards/list_service_spec.rb
index 1d0be99fb35..7518e9e9b75 100644
--- a/spec/services/boards/list_service_spec.rb
+++ b/spec/services/boards/list_service_spec.rb
@@ -2,36 +2,20 @@ require 'spec_helper'
describe Boards::ListService do
describe '#execute' do
- let(:project) { create(:project) }
+ context 'when board parent is a project' do
+ let(:parent) { create(:project) }
- subject(:service) { described_class.new(project, double) }
+ subject(:service) { described_class.new(parent, double) }
- context 'when project does not have a board' do
- it 'creates a new project board' do
- expect { service.execute }.to change(project.boards, :count).by(1)
- end
-
- it 'delegates the project board creation to Boards::CreateService' do
- expect_any_instance_of(Boards::CreateService).to receive(:execute).once
-
- service.execute
- end
+ it_behaves_like 'boards list service'
end
- context 'when project has a board' do
- before do
- create(:board, project: project)
- end
-
- it 'does not create a new board' do
- expect { service.execute }.not_to change(project.boards, :count)
- end
- end
+ context 'when board parent is a group' do
+ let(:parent) { create(:group) }
- it 'returns project boards' do
- board = create(:board, project: project)
+ subject(:service) { described_class.new(parent, double) }
- expect(service.execute).to match_array [board]
+ it_behaves_like 'boards list service'
end
end
end
diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb
index d5322e1bb21..7d3f5f86deb 100644
--- a/spec/services/boards/lists/create_service_spec.rb
+++ b/spec/services/boards/lists/create_service_spec.rb
@@ -2,62 +2,77 @@ require 'spec_helper'
describe Boards::Lists::CreateService do
describe '#execute' do
- let(:project) { create(:project) }
- let(:board) { create(:board, project: project) }
- let(:user) { create(:user) }
- let(:label) { create(:label, project: project, name: 'in-progress') }
+ shared_examples 'creating board lists' do
+ let(:user) { create(:user) }
- subject(:service) { described_class.new(project, user, label_id: label.id) }
+ subject(:service) { described_class.new(parent, user, label_id: label.id) }
- before do
- project.add_developer(user)
- end
+ before do
+ parent.add_developer(user)
+ end
- context 'when board lists is empty' do
- it 'creates a new list at beginning of the list' do
- list = service.execute(board)
+ context 'when board lists is empty' do
+ it 'creates a new list at beginning of the list' do
+ list = service.execute(board)
- expect(list.position).to eq 0
+ expect(list.position).to eq 0
+ end
end
- end
- context 'when board lists has the done list' do
- it 'creates a new list at beginning of the list' do
- list = service.execute(board)
+ context 'when board lists has the done list' do
+ it 'creates a new list at beginning of the list' do
+ list = service.execute(board)
- expect(list.position).to eq 0
+ expect(list.position).to eq 0
+ end
end
- end
- context 'when board lists has labels lists' do
- it 'creates a new list at end of the lists' do
- create(:list, board: board, position: 0)
- create(:list, board: board, position: 1)
+ context 'when board lists has labels lists' do
+ it 'creates a new list at end of the lists' do
+ create(:list, board: board, position: 0)
+ create(:list, board: board, position: 1)
- list = service.execute(board)
+ list = service.execute(board)
- expect(list.position).to eq 2
+ expect(list.position).to eq 2
+ end
end
- end
- context 'when board lists has label and done lists' do
- it 'creates a new list at end of the label lists' do
- list1 = create(:list, board: board, position: 0)
+ context 'when board lists has label and done lists' do
+ it 'creates a new list at end of the label lists' do
+ list1 = create(:list, board: board, position: 0)
- list2 = service.execute(board)
+ list2 = service.execute(board)
- expect(list1.reload.position).to eq 0
- expect(list2.reload.position).to eq 1
+ expect(list1.reload.position).to eq 0
+ expect(list2.reload.position).to eq 1
+ end
end
- end
- context 'when provided label does not belongs to the project' do
- it 'raises an error' do
- label = create(:label, name: 'in-development')
- service = described_class.new(project, user, label_id: label.id)
+ context 'when provided label does not belongs to the parent' do
+ it 'raises an error' do
+ label = create(:label, name: 'in-development')
+ service = described_class.new(parent, user, label_id: label.id)
- expect { service.execute(board) }.to raise_error(ActiveRecord::RecordNotFound)
+ expect { service.execute(board) }.to raise_error(ActiveRecord::RecordNotFound)
+ end
end
end
+
+ context 'when board parent is a project' do
+ let(:parent) { create(:project) }
+ let(:board) { create(:board, project: parent) }
+ let(:label) { create(:label, project: parent, name: 'in-progress') }
+
+ it_behaves_like 'creating board lists'
+ end
+
+ context 'when board parent is a group' do
+ let(:parent) { create(:group) }
+ let(:board) { create(:board, group: parent) }
+ let(:label) { create(:group_label, group: parent, name: 'in-progress') }
+
+ it_behaves_like 'creating board lists'
+ end
end
end
diff --git a/spec/services/boards/lists/destroy_service_spec.rb b/spec/services/boards/lists/destroy_service_spec.rb
index bd98625b44f..3c4eb6b3fc5 100644
--- a/spec/services/boards/lists/destroy_service_spec.rb
+++ b/spec/services/boards/lists/destroy_service_spec.rb
@@ -2,37 +2,24 @@ require 'spec_helper'
describe Boards::Lists::DestroyService do
describe '#execute' do
- let(:project) { create(:project) }
- let(:board) { create(:board, project: project) }
- let(:user) { create(:user) }
+ context 'when board parent is a project' do
+ let(:project) { create(:project) }
+ let(:board) { create(:board, project: project) }
+ let(:user) { create(:user) }
- context 'when list type is label' do
- it 'removes list from board' do
- list = create(:list, board: board)
- service = described_class.new(project, user)
+ let(:parent) { project }
- expect { service.execute(list) }.to change(board.lists, :count).by(-1)
- end
-
- it 'decrements position of higher lists' do
- development = create(:list, board: board, position: 0)
- review = create(:list, board: board, position: 1)
- staging = create(:list, board: board, position: 2)
- closed = board.closed_list
-
- described_class.new(project, user).execute(development)
-
- expect(review.reload.position).to eq 0
- expect(staging.reload.position).to eq 1
- expect(closed.reload.position).to be_nil
- end
+ it_behaves_like 'lists destroy service'
end
- it 'does not remove list from board when list type is closed' do
- list = board.closed_list
- service = described_class.new(project, user)
+ context 'when board parent is a group' do
+ let(:group) { create(:group) }
+ let(:board) { create(:board, group: group) }
+ let(:user) { create(:user) }
+
+ let(:parent) { group }
- expect { service.execute(list) }.not_to change(board.lists, :count)
+ it_behaves_like 'lists destroy service'
end
end
end
diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb
index b189857e4f4..24e04eed642 100644
--- a/spec/services/boards/lists/list_service_spec.rb
+++ b/spec/services/boards/lists/list_service_spec.rb
@@ -1,33 +1,25 @@
require 'spec_helper'
describe Boards::Lists::ListService do
- let(:project) { create(:project) }
- let(:board) { create(:board, project: project) }
- let(:label) { create(:label, project: project) }
- let!(:list) { create(:list, board: board, label: label) }
- let(:service) { described_class.new(project, double) }
-
describe '#execute' do
- context 'when the board has a backlog list' do
- let!(:backlog_list) { create(:backlog_list, board: board) }
-
- it 'does not create a backlog list' do
- expect { service.execute(board) }.not_to change(board.lists, :count)
- end
+ context 'when board parent is a project' do
+ let(:project) { create(:project) }
+ let(:board) { create(:board, project: project) }
+ let(:label) { create(:label, project: project) }
+ let!(:list) { create(:list, board: board, label: label) }
+ let(:service) { described_class.new(project, double) }
- it "returns board's lists" do
- expect(service.execute(board)).to eq [backlog_list, list, board.closed_list]
- end
+ it_behaves_like 'lists list service'
end
- context 'when the board does not have a backlog list' do
- it 'creates a backlog list' do
- expect { service.execute(board) }.to change(board.lists, :count).by(1)
- end
+ context 'when board parent is a group' do
+ let(:group) { create(:group) }
+ let(:board) { create(:board, group: group) }
+ let(:label) { create(:group_label, group: group) }
+ let!(:list) { create(:list, board: board, label: label) }
+ let(:service) { described_class.new(group, double) }
- it "returns board's lists" do
- expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list]
- end
+ it_behaves_like 'lists list service'
end
end
end
diff --git a/spec/services/boards/lists/move_service_spec.rb b/spec/services/boards/lists/move_service_spec.rb
index a9d218bad49..16dfb2ae6af 100644
--- a/spec/services/boards/lists/move_service_spec.rb
+++ b/spec/services/boards/lists/move_service_spec.rb
@@ -2,100 +2,24 @@ require 'spec_helper'
describe Boards::Lists::MoveService do
describe '#execute' do
- let(:project) { create(:project) }
- let(:board) { create(:board, project: project) }
- let(:user) { create(:user) }
+ context 'when board parent is a project' do
+ let(:project) { create(:project) }
+ let(:board) { create(:board, project: project) }
+ let(:user) { create(:user) }
- let!(:planning) { create(:list, board: board, position: 0) }
- let!(:development) { create(:list, board: board, position: 1) }
- let!(:review) { create(:list, board: board, position: 2) }
- let!(:staging) { create(:list, board: board, position: 3) }
- let!(:closed) { create(:closed_list, board: board) }
+ let(:parent) { project }
- context 'when list type is set to label' do
- it 'keeps position of lists when new position is nil' do
- service = described_class.new(project, user, position: nil)
-
- service.execute(planning)
-
- expect(current_list_positions).to eq [0, 1, 2, 3]
- end
-
- it 'keeps position of lists when new positon is equal to old position' do
- service = described_class.new(project, user, position: planning.position)
-
- service.execute(planning)
-
- expect(current_list_positions).to eq [0, 1, 2, 3]
- end
-
- it 'keeps position of lists when new positon is negative' do
- service = described_class.new(project, user, position: -1)
-
- service.execute(planning)
-
- expect(current_list_positions).to eq [0, 1, 2, 3]
- end
-
- it 'keeps position of lists when new positon is equal to number of labels lists' do
- service = described_class.new(project, user, position: board.lists.label.size)
-
- service.execute(planning)
-
- expect(current_list_positions).to eq [0, 1, 2, 3]
- end
-
- it 'keeps position of lists when new positon is greater than number of labels lists' do
- service = described_class.new(project, user, position: board.lists.label.size + 1)
-
- service.execute(planning)
-
- expect(current_list_positions).to eq [0, 1, 2, 3]
- end
-
- it 'increments position of intermediate lists when new positon is equal to first position' do
- service = described_class.new(project, user, position: 0)
-
- service.execute(staging)
-
- expect(current_list_positions).to eq [1, 2, 3, 0]
- end
-
- it 'decrements position of intermediate lists when new positon is equal to last position' do
- service = described_class.new(project, user, position: board.lists.label.last.position)
-
- service.execute(planning)
-
- expect(current_list_positions).to eq [3, 0, 1, 2]
- end
-
- it 'decrements position of intermediate lists when new position is greater than old position' do
- service = described_class.new(project, user, position: 2)
-
- service.execute(planning)
-
- expect(current_list_positions).to eq [2, 0, 1, 3]
- end
-
- it 'increments position of intermediate lists when new position is lower than old position' do
- service = described_class.new(project, user, position: 1)
-
- service.execute(staging)
-
- expect(current_list_positions).to eq [0, 2, 3, 1]
- end
+ it_behaves_like 'lists move service'
end
- it 'keeps position of lists when list type is closed' do
- service = described_class.new(project, user, position: 2)
+ context 'when board parent is a group' do
+ let(:group) { create(:group) }
+ let(:board) { create(:board, group: group) }
+ let(:user) { create(:user) }
- service.execute(closed)
+ let(:parent) { group }
- expect(current_list_positions).to eq [0, 1, 2, 3]
+ it_behaves_like 'lists move service'
end
end
-
- def current_list_positions
- [planning, development, review, staging].map { |list| list.reload.position }
- end
end
diff --git a/spec/services/ci/create_trace_artifact_service_spec.rb b/spec/services/ci/create_trace_artifact_service_spec.rb
deleted file mode 100644
index 8c5e8e438c7..00000000000
--- a/spec/services/ci/create_trace_artifact_service_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'spec_helper'
-
-describe Ci::CreateTraceArtifactService do
- describe '#execute' do
- subject { described_class.new(nil, nil).execute(job) }
-
- context 'when the job does not have trace artifact' do
- context 'when the job has a trace file' do
- let!(:job) { create(:ci_build, :trace_live) }
- let!(:legacy_path) { job.trace.read { |stream| return stream.path } }
- let!(:legacy_checksum) { Digest::SHA256.file(legacy_path).hexdigest }
- let(:new_path) { job.job_artifacts_trace.file.path }
- let(:new_checksum) { Digest::SHA256.file(new_path).hexdigest }
-
- it { expect(File.exist?(legacy_path)).to be_truthy }
-
- it 'creates trace artifact' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(1)
-
- expect(File.exist?(legacy_path)).to be_falsy
- expect(File.exist?(new_path)).to be_truthy
- expect(new_checksum).to eq(legacy_checksum)
- expect(job.job_artifacts_trace.file.exists?).to be_truthy
- expect(job.job_artifacts_trace.file.filename).to eq('job.log')
- end
-
- context 'when failed to create trace artifact record' do
- before do
- # When ActiveRecord error happens
- allow_any_instance_of(Ci::JobArtifact).to receive(:save).and_return(false)
- allow_any_instance_of(Ci::JobArtifact).to receive_message_chain(:errors, :full_messages)
- .and_return("Error")
-
- subject rescue nil
-
- job.reload
- end
-
- it 'keeps legacy trace and removes trace artifact' do
- expect(File.exist?(legacy_path)).to be_truthy
- expect(job.job_artifacts_trace).to be_nil
- end
- end
- end
-
- context 'when the job does not have a trace file' do
- let!(:job) { create(:ci_build) }
-
- it 'does not create trace artifact' do
- expect { subject }.not_to change { Ci::JobArtifact.count }
- end
- end
- end
-
- context 'when the job has already had trace artifact' do
- let!(:job) { create(:ci_build, :trace_artifact) }
-
- it 'does not create trace artifact' do
- expect { subject }.not_to change { Ci::JobArtifact.count }
- end
- end
- end
-end
diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb
index 10c264a90c5..36b6e5a701e 100644
--- a/spec/services/members/destroy_service_spec.rb
+++ b/spec/services/members/destroy_service_spec.rb
@@ -19,32 +19,11 @@ describe Members::DestroyService do
end
end
- def number_of_assigned_issuables(user)
- Issue.assigned_to(user).count + MergeRequest.assigned_to(user).count
- end
-
shared_examples 'a service destroying a member' do
it 'destroys the member' do
expect { described_class.new(current_user).execute(member, opts) }.to change { member.source.members_and_requesters.count }.by(-1)
end
- it 'unassigns issues and merge requests' do
- if member.invite?
- expect { described_class.new(current_user).execute(member, opts) }
- .not_to change { number_of_assigned_issuables(member_user) }
- else
- create :issue, assignees: [member_user]
- issue = create :issue, project: group_project, assignees: [member_user]
- merge_request = create :merge_request, target_project: group_project, source_project: group_project, assignee: member_user
-
- expect { described_class.new(current_user).execute(member, opts) }
- .to change { number_of_assigned_issuables(member_user) }.from(3).to(1)
-
- expect(issue.reload.assignee_ids).to be_empty
- expect(merge_request.reload.assignee_id).to be_nil
- end
- end
-
it 'destroys member notification_settings' do
if member_user.notification_settings.any?
expect { described_class.new(current_user).execute(member, opts) }
@@ -56,6 +35,29 @@ describe Members::DestroyService do
end
end
+ shared_examples 'a service destroying a member with access' do
+ it_behaves_like 'a service destroying a member'
+
+ it 'invalidates cached counts for todos and assigned issues and merge requests', :aggregate_failures do
+ create(:issue, project: group_project, assignees: [member_user])
+ create(:merge_request, source_project: group_project, assignee: member_user)
+ create(:todo, :pending, project: group_project, user: member_user)
+ create(:todo, :done, project: group_project, user: member_user)
+
+ expect(member_user.assigned_open_merge_requests_count).to be(1)
+ expect(member_user.assigned_open_issues_count).to be(1)
+ expect(member_user.todos_pending_count).to be(1)
+ expect(member_user.todos_done_count).to be(1)
+
+ described_class.new(current_user).execute(member, opts)
+
+ expect(member_user.assigned_open_merge_requests_count).to be(0)
+ expect(member_user.assigned_open_issues_count).to be(0)
+ expect(member_user.todos_pending_count).to be(0)
+ expect(member_user.todos_done_count).to be(0)
+ end
+ end
+
shared_examples 'a service destroying an access requester' do
it_behaves_like 'a service destroying a member'
@@ -74,29 +76,39 @@ describe Members::DestroyService do
end
end
- context 'with a member' do
+ context 'with a member with access' do
before do
- group_project.add_developer(member_user)
- group.add_developer(member_user)
+ group_project.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
+ group.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
end
context 'when current user cannot destroy the given member' do
- it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
+ context 'with a project member' do
let(:member) { group_project.members.find_by(user_id: member_user.id) }
- end
- it_behaves_like 'a service destroying a member' do
- let(:opts) { { skip_authorization: true } }
- let(:member) { group_project.members.find_by(user_id: member_user.id) }
- end
+ before do
+ group_project.add_developer(member_user)
+ end
- it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
- let(:member) { group.members.find_by(user_id: member_user.id) }
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError'
+
+ it_behaves_like 'a service destroying a member with access' do
+ let(:opts) { { skip_authorization: true } }
+ end
end
- it_behaves_like 'a service destroying a member' do
- let(:opts) { { skip_authorization: true } }
+ context 'with a group member' do
let(:member) { group.members.find_by(user_id: member_user.id) }
+
+ before do
+ group.add_developer(member_user)
+ end
+
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError'
+
+ it_behaves_like 'a service destroying a member with access' do
+ let(:opts) { { skip_authorization: true } }
+ end
end
end
@@ -106,12 +118,24 @@ describe Members::DestroyService do
group.add_owner(current_user)
end
- it_behaves_like 'a service destroying a member' do
+ context 'with a project member' do
let(:member) { group_project.members.find_by(user_id: member_user.id) }
+
+ before do
+ group_project.add_developer(member_user)
+ end
+
+ it_behaves_like 'a service destroying a member with access'
end
- it_behaves_like 'a service destroying a member' do
+ context 'with a group member' do
let(:member) { group.members.find_by(user_id: member_user.id) }
+
+ before do
+ group.add_developer(member_user)
+ end
+
+ it_behaves_like 'a service destroying a member with access'
end
end
end
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 5d226f34d2d..44a83c436cb 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -28,6 +28,7 @@ describe MergeRequests::CreateService do
it 'creates an MR' do
expect(merge_request).to be_valid
+ expect(merge_request.work_in_progress?).to be(false)
expect(merge_request.title).to eq('Awesome merge_request')
expect(merge_request.assignee).to be_nil
expect(merge_request.merge_params['force_remove_source_branch']).to eq('1')
@@ -62,6 +63,40 @@ describe MergeRequests::CreateService do
expect(Event.where(attributes).count).to eq(1)
end
+ describe 'when marked with /wip' do
+ context 'in title and in description' do
+ let(:opts) do
+ {
+ title: 'WIP: Awesome merge_request',
+ description: "well this is not done yet\n/wip",
+ source_branch: 'feature',
+ target_branch: 'master',
+ assignee: assignee
+ }
+ end
+
+ it 'sets MR to WIP' do
+ expect(merge_request.work_in_progress?).to be(true)
+ end
+ end
+
+ context 'in description only' do
+ let(:opts) do
+ {
+ title: 'Awesome merge_request',
+ description: "well this is not done yet\n/wip",
+ source_branch: 'feature',
+ target_branch: 'master',
+ assignee: assignee
+ }
+ end
+
+ it 'sets MR to WIP' do
+ expect(merge_request.work_in_progress?).to be(true)
+ end
+ end
+ end
+
context 'when merge request is assigned to someone' do
let(:opts) do
{
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index c31259239ee..5279ea6164e 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe MergeRequests::UpdateService, :mailer do
+ include ProjectForksHelper
+
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
@@ -538,5 +540,40 @@ describe MergeRequests::UpdateService, :mailer do
let(:open_issuable) { merge_request }
let(:closed_issuable) { create(:closed_merge_request, source_project: project) }
end
+
+ context 'setting `allow_maintainer_to_push`' do
+ let(:target_project) { create(:project, :public) }
+ let(:source_project) { fork_project(target_project) }
+ let(:user) { create(:user) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: source_project,
+ source_branch: 'fixes',
+ target_project: target_project)
+ end
+
+ before do
+ allow(ProtectedBranch).to receive(:protected?).with(source_project, 'fixes') { false }
+ end
+
+ it 'does not allow a maintainer of the target project to set `allow_maintainer_to_push`' do
+ target_project.add_developer(user)
+
+ update_merge_request(allow_maintainer_to_push: true, title: 'Updated title')
+
+ expect(merge_request.title).to eq('Updated title')
+ expect(merge_request.allow_maintainer_to_push).to be_falsy
+ end
+
+ it 'is allowed by a user that can push to the source and can update the merge request' do
+ merge_request.update!(assignee: user)
+ source_project.add_developer(user)
+
+ update_merge_request(allow_maintainer_to_push: true, title: 'Updated title')
+
+ expect(merge_request.title).to eq('Updated title')
+ expect(merge_request.allow_maintainer_to_push).to be_truthy
+ end
+ end
end
end
diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb
index bfb86284d86..934106627a9 100644
--- a/spec/services/projects/update_pages_service_spec.rb
+++ b/spec/services/projects/update_pages_service_spec.rb
@@ -34,6 +34,7 @@ describe Projects::UpdatePagesService do
context 'with expiry date' do
before do
build.artifacts_expire_in = "2 days"
+ build.save!
end
it "doesn't delete artifacts" do
@@ -105,6 +106,7 @@ describe Projects::UpdatePagesService do
context 'with expiry date' do
before do
build.artifacts_expire_in = "2 days"
+ build.save!
end
it "doesn't delete artifacts" do
@@ -159,6 +161,20 @@ describe Projects::UpdatePagesService do
expect(execute).not_to eq(:success)
end
+
+ context 'when timeout happens by DNS error' do
+ before do
+ allow_any_instance_of(described_class)
+ .to receive(:extract_zip_archive!).and_raise(SocketError)
+ end
+
+ it 'raises an error' do
+ expect { execute }.to raise_error(SocketError)
+
+ build.reload
+ expect(build.artifacts?).to eq(true)
+ end
+ end
end
end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index ad5a289290c..d454ac0bda5 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -132,6 +132,15 @@ describe Projects::UpdateService do
expect(result).to eq({ status: :success })
expect(project.wiki_repository_exists?).to be false
end
+
+ it 'handles empty project feature attributes' do
+ project.project_feature.update(wiki_access_level: ProjectFeature::DISABLED)
+
+ result = update_project(project, user, { name: 'test1' })
+
+ expect(result).to eq({ status: :success })
+ expect(project.wiki_repository_exists?).to be false
+ end
end
context 'when enabling a wiki' do
diff --git a/spec/services/prometheus/adapter_service_spec.rb b/spec/services/prometheus/adapter_service_spec.rb
new file mode 100644
index 00000000000..335fc5844aa
--- /dev/null
+++ b/spec/services/prometheus/adapter_service_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe Prometheus::AdapterService do
+ let(:project) { create(:project) }
+ subject { described_class.new(project) }
+
+ describe '#prometheus_adapter' do
+ let(:cluster) { create(:cluster, :provided_by_user, environment_scope: '*', projects: [project]) }
+
+ context 'prometheus service can execute queries' do
+ let(:prometheus_service) { double(:prometheus_service, can_query?: true) }
+
+ before do
+ allow(project).to receive(:find_or_initialize_service).with('prometheus').and_return prometheus_service
+ end
+
+ it 'return prometheus service as prometheus adapter' do
+ expect(subject.prometheus_adapter).to eq(prometheus_service)
+ end
+ end
+
+ context "prometheus service can't execute queries" do
+ let(:prometheus_service) { double(:prometheus_service, can_query?: false) }
+
+ context 'with cluster with prometheus installed' do
+ let!(:prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
+
+ it 'returns application handling all environments' do
+ expect(subject.prometheus_adapter).to eq(prometheus)
+ end
+ end
+
+ context 'with cluster without prometheus installed' do
+ it 'returns nil' do
+ expect(subject.prometheus_adapter).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index c40cd5b7548..51396d34f8f 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -30,6 +30,7 @@ describe SystemHooksService do
:old_path_with_namespace
)
end
+
it do
project.old_path_with_namespace = 'transfered_from_path'
expect(event_data(project, :transfer)).to include(
@@ -45,18 +46,21 @@ describe SystemHooksService do
:owner_name, :owner_email
)
end
+
it do
expect(event_data(group, :destroy)).to include(
:event_name, :name, :created_at, :updated_at, :path, :group_id,
:owner_name, :owner_email
)
end
+
it do
expect(event_data(group_member, :create)).to include(
:event_name, :created_at, :updated_at, :group_name, :group_path,
:group_id, :user_id, :user_username, :user_name, :user_email, :group_access
)
end
+
it do
expect(event_data(group_member, :destroy)).to include(
:event_name, :created_at, :updated_at, :group_name, :group_path,
@@ -70,6 +74,14 @@ describe SystemHooksService do
expect(data[:project_visibility]).to eq('private')
end
+ it 'handles nil datetime columns' do
+ user.update_attributes(created_at: nil, updated_at: nil)
+ data = event_data(user, :destroy)
+
+ expect(data[:created_at]).to be(nil)
+ expect(data[:updated_at]).to be(nil)
+ end
+
context 'group_rename' do
it 'contains old and new path' do
allow(group).to receive(:path_was).and_return('old-path')
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 5b5edc1aa0d..a3893188c6e 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -789,7 +789,7 @@ describe SystemNoteService do
object: {
url: project_commit_url(project, commit),
title: "GitLab: Mentioned on commit - #{commit.title}",
- icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
+ icon: { title: "GitLab", url16x16: "http://localhost/favicon.ico" },
status: { resolved: false }
}
)
@@ -815,7 +815,7 @@ describe SystemNoteService do
object: {
url: project_issue_url(project, issue),
title: "GitLab: Mentioned on issue - #{issue.title}",
- icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
+ icon: { title: "GitLab", url16x16: "http://localhost/favicon.ico" },
status: { resolved: false }
}
)
@@ -841,7 +841,7 @@ describe SystemNoteService do
object: {
url: project_snippet_url(project, snippet),
title: "GitLab: Mentioned on snippet - #{snippet.title}",
- icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
+ icon: { title: "GitLab", url16x16: "http://localhost/favicon.ico" },
status: { resolved: false }
}
)
diff --git a/spec/support/bare_repo_operations.rb b/spec/support/bare_repo_operations.rb
index 38d11992dc2..8eeaa37d3c5 100644
--- a/spec/support/bare_repo_operations.rb
+++ b/spec/support/bare_repo_operations.rb
@@ -11,6 +11,14 @@ class BareRepoOperations
@path_to_repo = path_to_repo
end
+ def commit_tree(tree_id, msg, parent: EMPTY_TREE_ID)
+ commit_tree_args = ['commit-tree', tree_id, '-m', msg]
+ commit_tree_args += ['-p', parent] unless parent == EMPTY_TREE_ID
+ commit_id = execute(commit_tree_args)
+
+ commit_id[0]
+ end
+
# Based on https://stackoverflow.com/a/25556917/1856239
def commit_file(file, dst_path, branch = 'master')
head_id = execute(['show', '--format=format:%H', '--no-patch', branch], allow_failure: true)[0] || EMPTY_TREE_ID
@@ -26,11 +34,9 @@ class BareRepoOperations
tree_id = execute(['write-tree'])
- commit_tree_args = ['commit-tree', tree_id[0], '-m', "Add #{dst_path}"]
- commit_tree_args += ['-p', head_id] unless head_id == EMPTY_TREE_ID
- commit_id = execute(commit_tree_args)
+ commit_id = commit_tree(tree_id[0], "Add #{dst_path}", parent: head_id)
- execute(['update-ref', "refs/heads/#{branch}", commit_id[0]])
+ execute(['update-ref', "refs/heads/#{branch}", commit_id])
end
private
diff --git a/spec/support/matchers/match_ids.rb b/spec/support/matchers/match_ids.rb
new file mode 100644
index 00000000000..d8424405b96
--- /dev/null
+++ b/spec/support/matchers/match_ids.rb
@@ -0,0 +1,24 @@
+RSpec::Matchers.define :match_ids do |*expected|
+ match do |actual|
+ actual_ids = map_ids(actual)
+ expected_ids = map_ids(expected)
+
+ expect(actual_ids).to match_array(expected_ids)
+ end
+
+ description do
+ 'matches elements by ids'
+ end
+
+ def map_ids(elements)
+ elements = elements.flatten if elements.respond_to?(:flatten)
+
+ if elements.respond_to?(:map)
+ elements.map(&:id)
+ elsif elements.respond_to?(:id)
+ [elements.id]
+ else
+ raise ArgumentError, "could not map elements to ids: #{elements}"
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions.rb
new file mode 100644
index 00000000000..b6aeb30d69c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/discussions.rb
@@ -0,0 +1,169 @@
+shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
+ it "returns an array of discussions" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['id']).to eq(note.discussion_id)
+ end
+
+ it "returns a 404 error when noteable id not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/12345/discussions", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id" do
+ it "returns a discussion by id" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions/#{note.discussion_id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['id']).to eq(note.discussion_id)
+ expect(json_response['notes'].first['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error if discussion not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
+ it "creates a new note" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['notes'].first['body']).to eq('hi!')
+ expect(json_response['notes'].first['author']['username']).to eq(user.username)
+ end
+
+ it "returns a 400 bad request error if body not given" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 401 unauthorized error if user not authenticated" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user),
+ body: 'hi!', created_at: creation_time
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['notes'].first['body']).to eq('hi!')
+ expect(json_response['notes'].first['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['notes'].first['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'when user does not have access to read the discussion' do
+ before do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'responds with 404' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", private_user),
+ body: 'Foo'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes" do
+ it 'adds a new note to the discussion' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('Hello!')
+ expect(json_response['type']).to eq('DiscussionNote')
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 400 bad request error if discussion is individual note" do
+ note.update_attribute(:type, nil)
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ it 'returns modified note' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/12345", user),
+ body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "DELETE /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ it 'deletes a note' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(204)
+ # Check if note is really deleted
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) do
+ api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb
new file mode 100644
index 00000000000..79b2196660c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/notes.rb
@@ -0,0 +1,206 @@
+shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
+ context 'sorting' do
+ before do
+ params = { noteable: noteable, author: user }
+ params[:project] = parent if parent.is_a?(Project)
+
+ create_list(:note, 3, params)
+ end
+
+ it 'sorts by created_at in descending order by default' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ response_dates = json_response.map { |note| note['created_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort.reverse)
+ end
+
+ it 'sorts by ascending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?sort=asc", user)
+
+ response_dates = json_response.map { |note| note['created_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort)
+ end
+
+ it 'sorts by updated_at in descending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at", user)
+
+ response_dates = json_response.map { |note| note['updated_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort.reverse)
+ end
+
+ it 'sorts by updated_at in ascending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at&sort=asc", user)
+
+ response_dates = json_response.map { |note| note['updated_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort)
+ end
+ end
+
+ it "returns an array of notes" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error when noteable id not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/12345/notes", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it "returns a note by id" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error if note not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
+ it "creates a new note" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ end
+
+ it "returns a 400 bad request error if body not given" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 401 unauthorized error if user not authenticated" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes"), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ it "creates an activity event when a note is created" do
+ expect(Event).to receive(:create!)
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
+ end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user),
+ body: 'hi!', created_at: creation_time
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'when the user is posting an award emoji on a noteable created by someone else' do
+ it 'creates a new note' do
+ parent.add_developer(private_user)
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), body: ':+1:'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq(':+1:')
+ end
+ end
+
+ context 'when the user is posting an award emoji on his/her own noteable' do
+ it 'creates a new note' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: ':+1:'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq(':+1:')
+ end
+ end
+
+ context 'when user does not have access to read the noteable' do
+ before do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'responds with 404' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user),
+ body: 'Foo'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+
+ describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it 'returns modified note' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user),
+ body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "DELETE /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it 'deletes a note' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(204)
+ # Check if note is really deleted
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) { api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user) }
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/boards/boards_create_service.rb b/spec/support/shared_examples/services/boards/boards_create_service.rb
new file mode 100644
index 00000000000..5bdc04f660f
--- /dev/null
+++ b/spec/support/shared_examples/services/boards/boards_create_service.rb
@@ -0,0 +1,27 @@
+shared_examples 'boards create service' do
+ context 'when parent does not have a board' do
+ it 'creates a new board' do
+ expect { service.execute }.to change(Board, :count).by(1)
+ end
+
+ it 'creates the default lists' do
+ board = service.execute
+
+ expect(board.lists.size).to eq 2
+ expect(board.lists.first).to be_backlog
+ expect(board.lists.last).to be_closed
+ end
+ end
+
+ context 'when parent has a board' do
+ before do
+ create(:board, parent: parent)
+ end
+
+ it 'does not create a new board' do
+ expect(service).to receive(:can_create_board?) { false }
+
+ expect { service.execute }.not_to change(parent.boards, :count)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/boards/boards_list_service.rb b/spec/support/shared_examples/services/boards/boards_list_service.rb
new file mode 100644
index 00000000000..e0d5a7c61f2
--- /dev/null
+++ b/spec/support/shared_examples/services/boards/boards_list_service.rb
@@ -0,0 +1,29 @@
+shared_examples 'boards list service' do
+ context 'when parent does not have a board' do
+ it 'creates a new parent board' do
+ expect { service.execute }.to change(parent.boards, :count).by(1)
+ end
+
+ it 'delegates the parent board creation to Boards::CreateService' do
+ expect_any_instance_of(Boards::CreateService).to receive(:execute).once
+
+ service.execute
+ end
+ end
+
+ context 'when parent has a board' do
+ before do
+ create(:board, parent: parent)
+ end
+
+ it 'does not create a new board' do
+ expect { service.execute }.not_to change(parent.boards, :count)
+ end
+ end
+
+ it 'returns parent boards' do
+ board = create(:board, parent: parent)
+
+ expect(service.execute).to eq [board]
+ end
+end
diff --git a/spec/support/shared_examples/services/boards/issues_list_service.rb b/spec/support/shared_examples/services/boards/issues_list_service.rb
new file mode 100644
index 00000000000..3e744323cea
--- /dev/null
+++ b/spec/support/shared_examples/services/boards/issues_list_service.rb
@@ -0,0 +1,60 @@
+shared_examples 'issues list service' do
+ it 'delegates search to IssuesFinder' do
+ params = { board_id: board.id, id: list1.id }
+
+ expect_any_instance_of(IssuesFinder).to receive(:execute).once.and_call_original
+
+ described_class.new(parent, user, params).execute
+ end
+
+ context 'issues are ordered by priority' do
+ it 'returns opened issues when list_id is missing' do
+ params = { board_id: board.id }
+
+ issues = described_class.new(parent, user, params).execute
+
+ expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1]
+ end
+
+ it 'returns opened issues when listing issues from Backlog' do
+ params = { board_id: board.id, id: backlog.id }
+
+ issues = described_class.new(parent, user, params).execute
+
+ expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1]
+ end
+
+ it 'returns closed issues when listing issues from Closed' do
+ params = { board_id: board.id, id: closed.id }
+
+ issues = described_class.new(parent, user, params).execute
+
+ expect(issues).to eq [closed_issue4, closed_issue2, closed_issue5, closed_issue3, closed_issue1]
+ end
+
+ it 'returns opened issues that have label list applied when listing issues from a label list' do
+ params = { board_id: board.id, id: list1.id }
+
+ issues = described_class.new(parent, user, params).execute
+
+ expect(issues).to eq [list1_issue3, list1_issue1, list1_issue2]
+ end
+ end
+
+ context 'with list that does not belong to the board' do
+ it 'raises an error' do
+ list = create(:list)
+ service = described_class.new(parent, user, board_id: board.id, id: list.id)
+
+ expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+
+ context 'with invalid list id' do
+ it 'raises an error' do
+ service = described_class.new(parent, user, board_id: board.id, id: nil)
+
+ expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/boards/issues_move_service.rb b/spec/support/shared_examples/services/boards/issues_move_service.rb
new file mode 100644
index 00000000000..4a4fbaa3a0e
--- /dev/null
+++ b/spec/support/shared_examples/services/boards/issues_move_service.rb
@@ -0,0 +1,87 @@
+shared_examples 'issues move service' do
+ context 'when moving an issue between lists' do
+ let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) }
+ let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list2.id } }
+
+ it 'delegates the label changes to Issues::UpdateService' do
+ expect_any_instance_of(Issues::UpdateService).to receive(:execute).with(issue).once
+
+ described_class.new(parent, user, params).execute(issue)
+ end
+
+ it 'removes the label from the list it came from and adds the label of the list it goes to' do
+ described_class.new(parent, user, params).execute(issue)
+
+ expect(issue.reload.labels).to contain_exactly(bug, testing)
+ end
+ end
+
+ context 'when moving to closed' do
+ let!(:list3) { create(:list, board: board2, label: regression, position: 1) }
+
+ let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression]) }
+ let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: closed.id } }
+
+ it 'delegates the close proceedings to Issues::CloseService' do
+ expect_any_instance_of(Issues::CloseService).to receive(:execute).with(issue).once
+
+ described_class.new(parent, user, params).execute(issue)
+ end
+
+ it 'removes all list-labels from boards and close the issue' do
+ described_class.new(parent, user, params).execute(issue)
+ issue.reload
+
+ expect(issue.labels).to contain_exactly(bug)
+ expect(issue).to be_closed
+ end
+ end
+
+ context 'when moving from closed' do
+ let(:issue) { create(:labeled_issue, :closed, project: project, labels: [bug]) }
+ let(:params) { { board_id: board1.id, from_list_id: closed.id, to_list_id: list2.id } }
+
+ it 'delegates the re-open proceedings to Issues::ReopenService' do
+ expect_any_instance_of(Issues::ReopenService).to receive(:execute).with(issue).once
+
+ described_class.new(parent, user, params).execute(issue)
+ end
+
+ it 'adds the label of the list it goes to and reopen the issue' do
+ described_class.new(parent, user, params).execute(issue)
+ issue.reload
+
+ expect(issue.labels).to contain_exactly(bug, testing)
+ expect(issue).to be_opened
+ end
+ end
+
+ context 'when moving to same list' do
+ let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) }
+ let(:issue1) { create(:labeled_issue, project: project, labels: [bug, development]) }
+ let(:issue2) { create(:labeled_issue, project: project, labels: [bug, development]) }
+ let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list1.id } }
+
+ it 'returns false' do
+ expect(described_class.new(parent, user, params).execute(issue)).to eq false
+ end
+
+ it 'keeps issues labels' do
+ described_class.new(parent, user, params).execute(issue)
+
+ expect(issue.reload.labels).to contain_exactly(bug, development)
+ end
+
+ it 'sorts issues' do
+ [issue, issue1, issue2].each do |issue|
+ issue.move_to_end && issue.save!
+ end
+
+ params.merge!(move_after_id: issue1.id, move_before_id: issue2.id)
+
+ described_class.new(parent, user, params).execute(issue)
+
+ expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/boards/lists_destroy_service.rb b/spec/support/shared_examples/services/boards/lists_destroy_service.rb
new file mode 100644
index 00000000000..62b6ffe1836
--- /dev/null
+++ b/spec/support/shared_examples/services/boards/lists_destroy_service.rb
@@ -0,0 +1,30 @@
+shared_examples 'lists destroy service' do
+ context 'when list type is label' do
+ it 'removes list from board' do
+ list = create(:list, board: board)
+ service = described_class.new(parent, user)
+
+ expect { service.execute(list) }.to change(board.lists, :count).by(-1)
+ end
+
+ it 'decrements position of higher lists' do
+ development = create(:list, board: board, position: 0)
+ review = create(:list, board: board, position: 1)
+ staging = create(:list, board: board, position: 2)
+ closed = board.closed_list
+
+ described_class.new(parent, user).execute(development)
+
+ expect(review.reload.position).to eq 0
+ expect(staging.reload.position).to eq 1
+ expect(closed.reload.position).to be_nil
+ end
+ end
+
+ it 'does not remove list from board when list type is closed' do
+ list = board.closed_list
+ service = described_class.new(parent, user)
+
+ expect { service.execute(list) }.not_to change(board.lists, :count)
+ end
+end
diff --git a/spec/support/shared_examples/services/boards/lists_list_service.rb b/spec/support/shared_examples/services/boards/lists_list_service.rb
new file mode 100644
index 00000000000..0a8220111ab
--- /dev/null
+++ b/spec/support/shared_examples/services/boards/lists_list_service.rb
@@ -0,0 +1,23 @@
+shared_examples 'lists list service' do
+ context 'when the board has a backlog list' do
+ let!(:backlog_list) { create(:backlog_list, board: board) }
+
+ it 'does not create a backlog list' do
+ expect { service.execute(board) }.not_to change(board.lists, :count)
+ end
+
+ it "returns board's lists" do
+ expect(service.execute(board)).to eq [backlog_list, list, board.closed_list]
+ end
+ end
+
+ context 'when the board does not have a backlog list' do
+ it 'creates a backlog list' do
+ expect { service.execute(board) }.to change(board.lists, :count).by(1)
+ end
+
+ it "returns board's lists" do
+ expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list]
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/boards/lists_move_service.rb b/spec/support/shared_examples/services/boards/lists_move_service.rb
new file mode 100644
index 00000000000..07c98cb29b7
--- /dev/null
+++ b/spec/support/shared_examples/services/boards/lists_move_service.rb
@@ -0,0 +1,93 @@
+shared_examples 'lists move service' do
+ let!(:planning) { create(:list, board: board, position: 0) }
+ let!(:development) { create(:list, board: board, position: 1) }
+ let!(:review) { create(:list, board: board, position: 2) }
+ let!(:staging) { create(:list, board: board, position: 3) }
+ let!(:closed) { create(:closed_list, board: board) }
+
+ context 'when list type is set to label' do
+ it 'keeps position of lists when new position is nil' do
+ service = described_class.new(parent, user, position: nil)
+
+ service.execute(planning)
+
+ expect(current_list_positions).to eq [0, 1, 2, 3]
+ end
+
+ it 'keeps position of lists when new positon is equal to old position' do
+ service = described_class.new(parent, user, position: planning.position)
+
+ service.execute(planning)
+
+ expect(current_list_positions).to eq [0, 1, 2, 3]
+ end
+
+ it 'keeps position of lists when new positon is negative' do
+ service = described_class.new(parent, user, position: -1)
+
+ service.execute(planning)
+
+ expect(current_list_positions).to eq [0, 1, 2, 3]
+ end
+
+ it 'keeps position of lists when new positon is equal to number of labels lists' do
+ service = described_class.new(parent, user, position: board.lists.label.size)
+
+ service.execute(planning)
+
+ expect(current_list_positions).to eq [0, 1, 2, 3]
+ end
+
+ it 'keeps position of lists when new positon is greater than number of labels lists' do
+ service = described_class.new(parent, user, position: board.lists.label.size + 1)
+
+ service.execute(planning)
+
+ expect(current_list_positions).to eq [0, 1, 2, 3]
+ end
+
+ it 'increments position of intermediate lists when new positon is equal to first position' do
+ service = described_class.new(parent, user, position: 0)
+
+ service.execute(staging)
+
+ expect(current_list_positions).to eq [1, 2, 3, 0]
+ end
+
+ it 'decrements position of intermediate lists when new positon is equal to last position' do
+ service = described_class.new(parent, user, position: board.lists.label.last.position)
+
+ service.execute(planning)
+
+ expect(current_list_positions).to eq [3, 0, 1, 2]
+ end
+
+ it 'decrements position of intermediate lists when new position is greater than old position' do
+ service = described_class.new(parent, user, position: 2)
+
+ service.execute(planning)
+
+ expect(current_list_positions).to eq [2, 0, 1, 3]
+ end
+
+ it 'increments position of intermediate lists when new position is lower than old position' do
+ service = described_class.new(parent, user, position: 1)
+
+ service.execute(staging)
+
+ expect(current_list_positions).to eq [0, 2, 3, 1]
+ end
+ end
+
+ it 'keeps position of lists when list type is closed' do
+ service = described_class.new(parent, user, position: 2)
+
+ service.execute(closed)
+
+ expect(current_list_positions).to eq [0, 1, 2, 3]
+ end
+
+ def current_list_positions
+ [planning, development, review, staging].map { |list| list.reload.position }
+ end
+end
diff --git a/spec/tasks/gitlab/artifacts/check_rake_spec.rb b/spec/tasks/gitlab/artifacts/check_rake_spec.rb
new file mode 100644
index 00000000000..d495b08aca0
--- /dev/null
+++ b/spec/tasks/gitlab/artifacts/check_rake_spec.rb
@@ -0,0 +1,34 @@
+require 'rake_helper'
+
+describe 'gitlab:artifacts rake tasks' do
+ describe 'check' do
+ let!(:artifact) { create(:ci_job_artifact, :archive, :correct_checksum) }
+
+ before do
+ Rake.application.rake_require('tasks/gitlab/artifacts/check')
+ stub_env('VERBOSE' => 'true')
+ end
+
+ it 'outputs the integrity check for each batch' do
+ expect { run_rake_task('gitlab:artifacts:check') }.to output(/Failures: 0/).to_stdout
+ end
+
+ it 'errors out about missing files on the file system' do
+ FileUtils.rm_f(artifact.file.path)
+
+ expect { run_rake_task('gitlab:artifacts:check') }.to output(/No such file.*#{Regexp.quote(artifact.file.path)}/).to_stdout
+ end
+
+ it 'errors out about invalid checksum' do
+ artifact.update_column(:file_sha256, 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
+
+ expect { run_rake_task('gitlab:artifacts:check') }.to output(/Checksum mismatch/).to_stdout
+ end
+
+ it 'errors out about missing checksum' do
+ artifact.update_column(:file_sha256, nil)
+
+ expect { run_rake_task('gitlab:artifacts:check') }.to output(/Checksum missing/).to_stdout
+ end
+ end
+end
diff --git a/spec/tasks/gitlab/traces_rake_spec.rb b/spec/tasks/gitlab/traces_rake_spec.rb
new file mode 100644
index 00000000000..bd18e8ffc1e
--- /dev/null
+++ b/spec/tasks/gitlab/traces_rake_spec.rb
@@ -0,0 +1,55 @@
+require 'rake_helper'
+
+describe 'gitlab:traces rake tasks' do
+ before do
+ Rake.application.rake_require 'tasks/gitlab/traces'
+ end
+
+ shared_examples 'passes the job id to worker' do
+ it do
+ expect(ArchiveTraceWorker).to receive(:bulk_perform_async).with([[job.id]])
+
+ run_rake_task('gitlab:traces:archive')
+ end
+ end
+
+ shared_examples 'does not pass the job id to worker' do
+ it do
+ expect(ArchiveTraceWorker).not_to receive(:bulk_perform_async)
+
+ run_rake_task('gitlab:traces:archive')
+ end
+ end
+
+ context 'when trace file stored in default path' do
+ let!(:job) { create(:ci_build, :success, :trace_live) }
+
+ it_behaves_like 'passes the job id to worker'
+ end
+
+ context 'when trace is stored in database' do
+ let!(:job) { create(:ci_build, :success) }
+
+ before do
+ job.update_column(:trace, 'trace in db')
+ end
+
+ it_behaves_like 'passes the job id to worker'
+ end
+
+ context 'when job has trace artifact' do
+ let!(:job) { create(:ci_build, :success) }
+
+ before do
+ create(:ci_job_artifact, :trace, job: job)
+ end
+
+ it_behaves_like 'does not pass the job id to worker'
+ end
+
+ context 'when job is not finished yet' do
+ let!(:build) { create(:ci_build, :running, :trace_live) }
+
+ it_behaves_like 'does not pass the job id to worker'
+ end
+end
diff --git a/spec/validators/url_placeholder_validator_spec.rb b/spec/validators/url_placeholder_validator_spec.rb
new file mode 100644
index 00000000000..b76d8acdf88
--- /dev/null
+++ b/spec/validators/url_placeholder_validator_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe UrlPlaceholderValidator do
+ let(:validator) { described_class.new(attributes: [:link_url], **options) }
+ let!(:badge) { build(:badge) }
+ let(:placeholder_url) { 'http://www.example.com/%{project_path}/%{project_id}/%{default_branch}/%{commit_sha}' }
+
+ subject { validator.validate_each(badge, :link_url, badge.link_url) }
+
+ describe '#validates_each' do
+ context 'with no options' do
+ let(:options) { {} }
+
+ it 'allows http and https protocols by default' do
+ expect(validator.send(:default_options)[:protocols]).to eq %w(http https)
+ end
+
+ it 'checks that the url structure is valid' do
+ badge.link_url = placeholder_url
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+ end
+
+ context 'with placeholder regex' do
+ let(:options) { { placeholder_regex: /(project_path|project_id|commit_sha|default_branch)/ } }
+
+ it 'checks that the url is valid and obviate placeholders that match regex' do
+ badge.link_url = placeholder_url
+
+ subject
+
+ expect(badge.errors.empty?).to be true
+ end
+ end
+ end
+end
diff --git a/spec/validators/url_validator_spec.rb b/spec/validators/url_validator_spec.rb
new file mode 100644
index 00000000000..763dff181d2
--- /dev/null
+++ b/spec/validators/url_validator_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+describe UrlValidator do
+ let(:validator) { described_class.new(attributes: [:link_url], **options) }
+ let!(:badge) { build(:badge) }
+
+ subject { validator.validate_each(badge, :link_url, badge.link_url) }
+
+ describe '#validates_each' do
+ context 'with no options' do
+ let(:options) { {} }
+
+ it 'allows http and https protocols by default' do
+ expect(validator.send(:default_options)[:protocols]).to eq %w(http https)
+ end
+
+ it 'checks that the url structure is valid' do
+ badge.link_url = 'http://www.google.es/%{whatever}'
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+ end
+
+ context 'with protocols' do
+ let(:options) { { protocols: %w(http) } }
+
+ it 'allows urls with the defined protocols' do
+ badge.link_url = 'http://www.example.com'
+
+ subject
+
+ expect(badge.errors.empty?).to be true
+ end
+
+ it 'add error if the url protocol does not match the selected ones' do
+ badge.link_url = 'https://www.example.com'
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+ end
+ end
+end
diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
index c5f455b8948..f28bf430f02 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -12,7 +12,7 @@ describe 'layouts/nav/sidebar/_project' do
end
describe 'issue boards' do
- it 'has boards tab when multiple issue boards available' do
+ it 'has board tab' do
render
expect(rendered).to have_css('a[title="Board"]')
diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb
index 62af946dcab..15fce65979b 100644
--- a/spec/views/projects/_home_panel.html.haml_spec.rb
+++ b/spec/views/projects/_home_panel.html.haml_spec.rb
@@ -1,7 +1,8 @@
require 'spec_helper'
describe 'projects/_home_panel' do
- let(:project) { create(:project, :public) }
+ let(:group) { create(:group) }
+ let(:project) { create(:project, :public, namespace: group) }
let(:notification_settings) do
user&.notification_settings_for(project)
@@ -35,4 +36,55 @@ describe 'projects/_home_panel' do
expect(rendered).not_to have_selector('.notification_dropdown')
end
end
+
+ context 'when project' do
+ let!(:user) { create(:user) }
+ let(:badges) { project.badges }
+
+ context 'has no badges' do
+ it 'should not render any badge' do
+ render
+
+ expect(rendered).to have_selector('.project-badges')
+ expect(rendered).not_to have_selector('.project-badges > a')
+ end
+ end
+
+ shared_examples 'show badges' do
+ it 'should render the all badges' do
+ render
+
+ expect(rendered).to have_selector('.project-badges a')
+
+ badges.each do |badge|
+ expect(rendered).to have_link(href: badge.rendered_link_url)
+ end
+ end
+ end
+
+ context 'only has group badges' do
+ before do
+ create(:group_badge, group: project.group)
+ end
+
+ it_behaves_like 'show badges'
+ end
+
+ context 'only has project badges' do
+ before do
+ create(:project_badge, project: project)
+ end
+
+ it_behaves_like 'show badges'
+ end
+
+ context 'has both group and project badges' do
+ before do
+ create(:project_badge, project: project)
+ create(:group_badge, group: project.group)
+ end
+
+ it_behaves_like 'show badges'
+ end
+ end
end
diff --git a/spec/views/projects/tree/show.html.haml_spec.rb b/spec/views/projects/tree/show.html.haml_spec.rb
index 44b32df0395..3b098320ad7 100644
--- a/spec/views/projects/tree/show.html.haml_spec.rb
+++ b/spec/views/projects/tree/show.html.haml_spec.rb
@@ -13,6 +13,7 @@ describe 'projects/tree/show' do
allow(view).to receive(:can?).and_return(true)
allow(view).to receive(:can_collaborate_with_project?).and_return(true)
+ allow(view).to receive_message_chain('user_access.can_push_to_branch?').and_return(true)
allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings)
end
diff --git a/spec/workers/create_trace_artifact_worker_spec.rb b/spec/workers/archive_trace_worker_spec.rb
index 854abd9cca7..b768588c6e1 100644
--- a/spec/workers/create_trace_artifact_worker_spec.rb
+++ b/spec/workers/archive_trace_worker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CreateTraceArtifactWorker do
+describe ArchiveTraceWorker do
describe '#perform' do
subject { described_class.new.perform(job&.id) }
@@ -8,8 +8,7 @@ describe CreateTraceArtifactWorker do
let(:job) { create(:ci_build) }
it 'executes service' do
- expect_any_instance_of(Ci::CreateTraceArtifactService)
- .to receive(:execute).with(job)
+ expect_any_instance_of(Gitlab::Ci::Trace).to receive(:archive!)
subject
end
@@ -19,8 +18,7 @@ describe CreateTraceArtifactWorker do
let(:job) { nil }
it 'does not execute service' do
- expect_any_instance_of(Ci::CreateTraceArtifactService)
- .not_to receive(:execute)
+ expect_any_instance_of(Gitlab::Ci::Trace).not_to receive(:archive!)
subject
end
diff --git a/spec/workers/build_finished_worker_spec.rb b/spec/workers/build_finished_worker_spec.rb
index c7ff8cf3b92..acd8da11d8d 100644
--- a/spec/workers/build_finished_worker_spec.rb
+++ b/spec/workers/build_finished_worker_spec.rb
@@ -14,7 +14,7 @@ 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(CreateTraceArtifactWorker).to receive(:perform_async)
+ expect(ArchiveTraceWorker).to receive(:perform_async)
described_class.new.perform(build.id)
end
diff --git a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
index 68cfe9d5545..615462380e0 100644
--- a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
@@ -25,7 +25,7 @@ describe Gitlab::GithubImport::ObjectImporter do
importer_class = double(:importer_class)
importer_instance = double(:importer_instance)
representation = double(:representation)
- project = double(:project, path_with_namespace: 'foo/bar')
+ project = double(:project, full_path: 'foo/bar')
client = double(:client)
expect(worker)
diff --git a/spec/workers/concerns/pipeline_background_queue_spec.rb b/spec/workers/concerns/pipeline_background_queue_spec.rb
new file mode 100644
index 00000000000..24c0a3c6a20
--- /dev/null
+++ b/spec/workers/concerns/pipeline_background_queue_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe PipelineBackgroundQueue do
+ let(:worker) do
+ Class.new do
+ def self.name
+ 'DummyWorker'
+ end
+
+ include ApplicationWorker
+ include PipelineBackgroundQueue
+ end
+ end
+
+ it 'sets a default object storage queue automatically' do
+ expect(worker.sidekiq_options['queue'])
+ .to eq 'pipeline_background:dummy'
+ end
+end
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index 47297de738b..74539a7e493 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -195,6 +195,12 @@ describe GitGarbageCollectWorker do
expect(File.exist?(bitmap_path(after_packs.first))).to eq(bitmaps_enabled)
end
+
+ it 'cleans up repository after finishing' do
+ expect_any_instance_of(Project).to receive(:cleanup).and_call_original
+
+ subject.perform(project.id, 'gc', lease_key, lease_uuid)
+ end
end
context 'with bitmaps enabled' do
diff --git a/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb b/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
index 7c8c665a9b3..48e7eaf32fc 100644
--- a/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::GithubImport::ImportDiffNoteWorker do
describe '#import' do
it 'imports a diff note' do
- project = double(:project, path_with_namespace: 'foo/bar')
+ project = double(:project, full_path: 'foo/bar')
client = double(:client)
importer = double(:importer)
hash = {
diff --git a/spec/workers/gitlab/github_import/import_issue_worker_spec.rb b/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
index 4116380ff4d..8cf6ac15919 100644
--- a/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_issue_worker_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::GithubImport::ImportIssueWorker do
describe '#import' do
it 'imports an issue' do
- project = double(:project, path_with_namespace: 'foo/bar')
+ project = double(:project, full_path: 'foo/bar')
client = double(:client)
importer = double(:importer)
hash = {
diff --git a/spec/workers/gitlab/github_import/import_note_worker_spec.rb b/spec/workers/gitlab/github_import/import_note_worker_spec.rb
index 0ca825a722b..677697c02df 100644
--- a/spec/workers/gitlab/github_import/import_note_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_note_worker_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::GithubImport::ImportNoteWorker do
describe '#import' do
it 'imports a note' do
- project = double(:project, path_with_namespace: 'foo/bar')
+ project = double(:project, full_path: 'foo/bar')
client = double(:client)
importer = double(:importer)
hash = {
diff --git a/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb b/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
index d49f560af42..e287ddbe0d7 100644
--- a/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::GithubImport::ImportPullRequestWorker do
describe '#import' do
it 'imports a pull request' do
- project = double(:project, path_with_namespace: 'foo/bar')
+ project = double(:project, full_path: 'foo/bar')
client = double(:client)
importer = double(:importer)
hash = {
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 5d9b0679796..cd6661f09a1 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -114,6 +114,18 @@ describe PostReceive do
end
end
+ describe '#process_wiki_changes' do
+ let(:gl_repository) { "wiki-#{project.id}" }
+
+ it 'updates project activity' do
+ described_class.new.perform(gl_repository, key_id, base64_changes)
+
+ expect { project.reload }
+ .to change(project, :last_activity_at)
+ .and change(project, :last_repository_updated_at)
+ end
+ end
+
context "webhook" do
it "fetches the correct project" do
expect(Project).to receive(:find_by).with(id: project.id.to_s)
diff --git a/spec/workers/process_commit_worker_spec.rb b/spec/workers/process_commit_worker_spec.rb
index 76ef57b6b1e..ac79d9c0ac1 100644
--- a/spec/workers/process_commit_worker_spec.rb
+++ b/spec/workers/process_commit_worker_spec.rb
@@ -20,32 +20,6 @@ describe ProcessCommitWorker do
worker.perform(project.id, -1, commit.to_hash)
end
- context 'when commit is a merge request merge commit' do
- let(:merge_request) do
- create(:merge_request,
- description: "Closes #{issue.to_reference}",
- source_branch: 'feature-merged',
- target_branch: 'master',
- source_project: project)
- end
-
- let(:commit) do
- project.repository.create_branch('feature-merged', 'feature')
-
- sha = project.repository.merge(user,
- merge_request.diff_head_sha,
- merge_request,
- "Closes #{issue.to_reference}")
- project.repository.commit(sha)
- end
-
- it 'it does not close any issues from the commit message' do
- expect(worker).not_to receive(:close_issues)
-
- worker.perform(project.id, user.id, commit.to_hash)
- end
- end
-
it 'processes the commit message' do
expect(worker).to receive(:process_commit_message).and_call_original
@@ -73,13 +47,21 @@ describe ProcessCommitWorker do
describe '#process_commit_message' do
context 'when pushing to the default branch' do
- it 'closes issues that should be closed per the commit message' do
+ before do
allow(commit).to receive(:safe_message).and_return("Closes #{issue.to_reference}")
+ end
+ it 'closes issues that should be closed per the commit message' do
expect(worker).to receive(:close_issues).with(project, user, user, commit, [issue])
worker.process_commit_message(project, commit, user, user, true)
end
+
+ it 'creates cross references' do
+ expect(commit).to receive(:create_cross_references!).with(user, [issue])
+
+ worker.process_commit_message(project, commit, user, user, true)
+ end
end
context 'when pushing to a non-default branch' do
@@ -90,12 +72,44 @@ describe ProcessCommitWorker do
worker.process_commit_message(project, commit, user, user, false)
end
+
+ it 'does not create cross references' do
+ expect(commit).to receive(:create_cross_references!).with(user, [])
+
+ worker.process_commit_message(project, commit, user, user, false)
+ end
end
- it 'creates cross references' do
- expect(commit).to receive(:create_cross_references!)
+ context 'when commit is a merge request merge commit to the default branch' do
+ let(:merge_request) do
+ create(:merge_request,
+ description: "Closes #{issue.to_reference}",
+ source_branch: 'feature-merged',
+ target_branch: 'master',
+ source_project: project)
+ end
- worker.process_commit_message(project, commit, user, user)
+ let(:commit) do
+ project.repository.create_branch('feature-merged', 'feature')
+
+ MergeRequests::MergeService
+ .new(project, merge_request.author)
+ .execute(merge_request)
+
+ merge_request.reload.merge_commit
+ end
+
+ it 'does not close any issues from the commit message' do
+ expect(worker).not_to receive(:close_issues)
+
+ worker.process_commit_message(project, commit, user, user, true)
+ end
+
+ it 'still creates cross references' do
+ expect(commit).to receive(:create_cross_references!).with(user, [])
+
+ worker.process_commit_message(project, commit, user, user, true)
+ end
end
end
diff --git a/vendor/gitignore/Dart.gitignore b/vendor/gitignore/Dart.gitignore
index 58950beb4fa..7bf00e82cc9 100644
--- a/vendor/gitignore/Dart.gitignore
+++ b/vendor/gitignore/Dart.gitignore
@@ -1,4 +1,4 @@
-# See https://www.dartlang.org/tools/private-files.html
+# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
diff --git a/vendor/gitignore/Qt.gitignore b/vendor/gitignore/Qt.gitignore
index 037a1e75790..5291a385b25 100644
--- a/vendor/gitignore/Qt.gitignore
+++ b/vendor/gitignore/Qt.gitignore
@@ -1,5 +1,4 @@
# C++ objects and libs
-
*.slo
*.lo
*.o
@@ -11,7 +10,6 @@
*.dylib
# Qt-es
-
object_script.*.Release
object_script.*.Debug
*_plugin_import.cpp
@@ -35,13 +33,11 @@ Makefile*
target_wrapper.*
# QtCreator
-
*.autosave
-# QtCtreator Qml
+# QtCreator Qml
*.qmlproject.user
*.qmlproject.user.*
-# QtCtreator CMake
+# QtCreator CMake
CMakeLists.txt.user*
-
diff --git a/vendor/gitignore/R.gitignore b/vendor/gitignore/R.gitignore
index fcff087aebb..26fad6fadff 100644
--- a/vendor/gitignore/R.gitignore
+++ b/vendor/gitignore/R.gitignore
@@ -31,3 +31,6 @@ vignettes/*.pdf
# Temporary files created by R markdown
*.utf8.md
*.knit.md
+
+# Shiny token, see https://shiny.rstudio.com/articles/shinyapps.html
+rsconnect/
diff --git a/vendor/gitignore/TeX.gitignore b/vendor/gitignore/TeX.gitignore
index 5359e544bcf..78c1c5cd26e 100644
--- a/vendor/gitignore/TeX.gitignore
+++ b/vendor/gitignore/TeX.gitignore
@@ -110,6 +110,14 @@ acs-*.bib
*.gaux
*.gtex
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
# hyperref
*.brf
diff --git a/vendor/gitignore/VisualStudio.gitignore b/vendor/gitignore/VisualStudio.gitignore
index c49041ff7d2..8e930f59c47 100644
--- a/vendor/gitignore/VisualStudio.gitignore
+++ b/vendor/gitignore/VisualStudio.gitignore
@@ -259,9 +259,6 @@ FakesAssemblies/
.ntvs_analysis.dat
node_modules/
-# TypeScript v1 declaration files
-typings/
-
# Visual Studio 6 build log
*.plg
diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
index 0ac8885405e..c233e255fe0 100644
--- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
+++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
@@ -36,7 +36,6 @@ variables:
KUBERNETES_VERSION: 1.8.6
HELM_VERSION: 2.6.1
- CODECLIMATE_VERSION: 0.69.0
stages:
- build
@@ -286,6 +285,8 @@ production:
export CI_APPLICATION_TAG=$CI_COMMIT_SHA
export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID}
export TILLER_NAMESPACE=$KUBE_NAMESPACE
+ # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Static Code Analysis
+ export SCA_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
function sast_container() {
if [[ -n "$CI_REGISTRY_USER" ]]; then
@@ -306,20 +307,16 @@ production:
}
function codeclimate() {
- cc_opts="--env CODECLIMATE_CODE="$PWD" \
- --volume "$PWD":/code \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- --volume /tmp/cc:/tmp/cc"
-
- docker run ${cc_opts} "codeclimate/codeclimate:${CODECLIMATE_VERSION}" init
- docker run ${cc_opts} "codeclimate/codeclimate:${CODECLIMATE_VERSION}" analyze -f json > codeclimate.json
+ docker run --env CODECLIMATE_CODE="$PWD" \
+ --volume "$PWD":/code \
+ --volume /var/run/docker.sock:/var/run/docker.sock \
+ --volume /tmp/cc:/tmp/cc \
+ "registry.gitlab.com/gitlab-org/security-products/codequality/codeclimate:${SCA_VERSION}" analyze -f json > codeclimate.json
}
function sast() {
case "$CI_SERVER_VERSION" in
*-ee)
- # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable"
- SAST_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
# Deprecation notice for CONFIDENCE_LEVEL variable
if [ -z "$SAST_CONFIDENCE_LEVEL" -a "$CONFIDENCE_LEVEL" ]; then
@@ -331,7 +328,7 @@ production:
--env SAST_DISABLE_REMOTE_CHECKS="${SAST_DISABLE_REMOTE_CHECKS:-false}" \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/sast:$SAST_VERSION" /app/bin/run /code
+ "registry.gitlab.com/gitlab-org/security-products/sast:$SCA_VERSION" /app/bin/run /code
;;
*)
echo "GitLab EE is required"
diff --git a/vendor/licenses.csv b/vendor/licenses.csv
index 8f127468e25..03115292f02 100644
--- a/vendor/licenses.csv
+++ b/vendor/licenses.csv
@@ -9,14 +9,17 @@
JSONStream,1.3.2,MIT
RedCloth,4.3.2,MIT
abbrev,1.0.9,ISC
+abbrev,1.1.1,ISC
accepts,1.3.3,MIT
+accepts,1.3.4,MIT
ace-rails-ap,4.1.2,MIT
acorn,3.3.0,MIT
acorn,4.0.13,MIT
acorn,5.1.1,MIT
-acorn,5.3.0,MIT
+acorn,5.4.1,MIT
acorn-dynamic-import,2.0.2,MIT
acorn-jsx,3.0.1,MIT
+acorn-node,1.3.0,Apache 2.0
actionmailer,4.2.10,MIT
actionpack,4.2.10,MIT
actionview,4.2.10,MIT
@@ -25,6 +28,7 @@ activemodel,4.2.10,MIT
activerecord,4.2.10,MIT
activesupport,4.2.10,MIT
acts-as-taggable-on,4.0.0,MIT
+address,1.0.3,MIT
addressable,2.5.2,Apache 2.0
addressparser,1.0.1,MIT
after,0.8.2,MIT
@@ -32,59 +36,70 @@ agent-base,2.1.1,MIT
ajv,4.11.8,MIT
ajv,5.2.2,MIT
ajv,5.5.2,MIT
+ajv,6.1.1,MIT
ajv-keywords,1.5.1,MIT
-ajv-keywords,2.1.0,MIT
+ajv-keywords,3.1.0,MIT
akismet,2.0.0,MIT
align-text,0.1.4,MIT
allocations,1.0.5,MIT
alphanum-sort,1.0.2,MIT
amdefine,1.0.1,BSD-3-Clause OR MIT
+amqplib,0.5.2,MIT
+ansi-align,2.0.0,ISC
ansi-escapes,1.4.0,MIT
-ansi-html,0.0.5,"Apache, Version 2.0"
+ansi-escapes,3.0.0,MIT
ansi-html,0.0.7,Apache 2.0
ansi-regex,2.1.1,MIT
ansi-regex,3.0.0,MIT
ansi-styles,2.2.1,MIT
ansi-styles,3.2.0,MIT
anymatch,1.3.2,ISC
+anymatch,2.0.0,ISC
append-transform,0.4.0,MIT
-aproba,1.1.2,ISC
+aproba,1.2.0,ISC
are-we-there-yet,1.1.4,ISC
arel,6.0.4,MIT
argparse,1.0.9,MIT
arr-diff,2.0.0,MIT
-arr-flatten,1.0.1,MIT
+arr-diff,4.0.0,MIT
+arr-flatten,1.1.0,MIT
+arr-union,3.1.0,MIT
array-filter,0.0.1,MIT
array-find,1.0.0,MIT
array-find-index,1.0.2,MIT
array-flatten,1.1.1,MIT
array-flatten,2.1.1,MIT
+array-includes,3.0.3,MIT
array-map,0.0.0,MIT
array-reduce,0.0.0,MIT
array-slice,0.2.3,MIT
array-union,1.0.2,MIT
array-uniq,1.0.3,MIT
array-unique,0.2.1,MIT
+array-unique,0.3.2,MIT
arraybuffer.slice,0.0.7,MIT
arrify,1.0.1,MIT
asana,0.6.0,MIT
asciidoctor,1.5.3,MIT
asciidoctor-plantuml,0.0.7,MIT
asn1,0.2.3,MIT
-asn1.js,4.9.1,MIT
+asn1.js,4.10.1,MIT
assert,1.4.1,MIT
assert-plus,0.2.0,MIT
assert-plus,1.0.0,MIT
asset_sync,2.2.0,MIT
-ast-types,0.10.1,MIT
+assign-symbols,1.0.0,MIT
+ast-types,0.11.1,MIT
astw,2.2.0,MIT
async,0.9.2,MIT
async,1.5.2,MIT
async,2.1.5,MIT
async,2.4.1,MIT
+async,2.6.0,MIT
async-each,1.0.1,MIT
async-limiter,1.0.0,MIT
asynckit,0.4.0,MIT
+atob,2.0.3,(MIT OR Apache-2.0)
atomic,1.1.99,Apache 2.0
attr_encrypted,3.0.3,MIT
attr_required,1.0.0,MIT
@@ -176,9 +191,10 @@ babylon,7.0.0-beta.32,MIT
backo2,1.0.2,MIT
balanced-match,0.4.2,MIT
balanced-match,1.0.0,MIT
+base,0.11.2,MIT
base32,0.3.2,MIT
base64-arraybuffer,0.1.5,MIT
-base64-js,1.2.0,MIT
+base64-js,1.2.3,MIT
base64id,1.0.0,MIT
batch,0.6.1,MIT
batch-loader,1.2.1,MIT
@@ -186,50 +202,57 @@ bcrypt,3.1.11,MIT
bcrypt-pbkdf,1.0.1,New BSD
bcrypt_pbkdf,1.0.0,MIT
better-assert,1.0.2,MIT
+bfj-node4,5.2.1,MIT
big.js,3.1.3,MIT
-binary-extensions,1.10.0,MIT
+binary-extensions,1.11.0,MIT
bindata,2.4.1,ruby
+bitsyntax,0.0.4,Unknown
bl,1.1.2,MIT
blackst0ne-mermaid,7.1.0-fixed,MIT
blob,0.0.4,MIT*
block-stream,0.0.9,ISC
-bluebird,2.11.0,MIT
bluebird,3.5.0,MIT
-bn.js,4.11.6,MIT
-body-parser,1.17.2,MIT
+bluebird,3.5.1,MIT
+bn.js,4.11.8,MIT
+body-parser,1.18.2,MIT
bonjour,3.5.0,MIT
boom,2.10.1,New BSD
boom,4.3.1,New BSD
boom,5.2.0,New BSD
bootstrap-sass,3.3.6,MIT
bootstrap_form,2.7.0,MIT
+boxen,1.3.0,MIT
+brace-expansion,1.1.11,MIT
brace-expansion,1.1.8,MIT
braces,0.1.5,MIT
braces,1.8.5,MIT
-brorand,1.0.7,MIT
+braces,2.3.1,MIT
+brorand,1.1.0,MIT
browser,2.2.0,MIT
-browser-pack,6.0.2,MIT
+browser-pack,6.0.4,MIT
browser-resolve,1.11.2,MIT
browserify,14.5.0,MIT
-browserify-aes,1.0.6,MIT
+browserify-aes,1.1.1,MIT
browserify-cipher,1.0.0,MIT
browserify-des,1.0.0,MIT
browserify-rsa,4.0.1,MIT
-browserify-sign,4.0.0,ISC
+browserify-sign,4.0.4,ISC
browserify-zlib,0.1.4,MIT
browserify-zlib,0.2.0,MIT
browserslist,1.7.7,MIT
buffer,4.9.1,MIT
-buffer,5.0.8,MIT
+buffer,5.1.0,MIT
buffer-indexof,1.1.0,MIT
+buffer-more-ints,0.0.2,MIT
buffer-xor,1.0.3,MIT
builder,3.2.3,MIT
buildmail,4.0.1,MIT
builtin-modules,1.1.1,MIT
builtin-status-codes,3.0.0,MIT
-bytes,2.4.0,MIT
bytes,2.5.0,MIT
bytes,3.0.0,MIT
+cacache,10.0.4,ISC
+cache-base,1.0.1,MIT
cached-path-relative,1.0.1,MIT
caller-path,0.1.0,MIT
callsite,1.0.0,MIT*
@@ -241,6 +264,7 @@ camelcase,4.1.0,MIT
camelcase-keys,2.1.0,MIT
caniuse-api,1.6.1,MIT
caniuse-db,1.0.30000649,CC-BY-4.0
+capture-stack-trace,1.0.0,MIT
carrierwave,1.2.1,MIT
caseless,0.11.0,Apache 2.0
caseless,0.12.0,Apache 2.0
@@ -248,18 +272,27 @@ cause,0.1,MIT
center-align,0.1.3,MIT
chalk,1.1.3,MIT
chalk,2.3.0,MIT
+chalk,2.3.1,MIT
+chardet,0.4.2,MIT
charlock_holmes,0.7.5,MIT
+chart.js,1.0.2,MIT
+check-types,7.3.0,MIT
chokidar,1.7.0,MIT
+chokidar,2.0.2,MIT
+chownr,1.0.1,ISC
chronic,0.10.2,MIT
chronic_duration,0.10.6,MIT
chunky_png,1.3.5,MIT
-cipher-base,1.0.3,MIT
+cipher-base,1.0.4,MIT
circular-json,0.3.3,MIT
-circular-json,0.4.0,MIT
+circular-json,0.5.1,MIT
citrus,3.0.2,MIT
clap,1.1.3,MIT
+class-utils,0.3.6,MIT
classlist-polyfill,1.2.0,Unlicense
+cli-boxes,1.0.0,MIT
cli-cursor,1.0.2,MIT
+cli-cursor,2.1.0,MIT
cli-width,2.1.0,ISC
clipboard,1.7.1,MIT
cliui,2.1.0,ISC
@@ -270,6 +303,7 @@ co,4.6.0,MIT
coa,1.0.1,MIT
code-point-at,1.1.0,MIT
coercible,1.0.0,MIT
+collection-visit,1.0.0,MIT
color,0.11.4,MIT
color-convert,1.9.1,MIT
color-name,1.1.2,MIT
@@ -278,21 +312,23 @@ colormin,1.1.2,MIT
colors,1.1.2,MIT
combine-lists,1.0.1,MIT
combine-source-map,0.7.2,MIT
-combined-stream,1.0.5,MIT
-commander,2.9.0,MIT
+combine-source-map,0.8.0,MIT
+combined-stream,1.0.6,MIT
+commander,2.14.1,MIT
commondir,1.0.1,MIT
+commonmarker,0.17.8,MIT
component-bind,1.0.0,MIT*
component-emitter,1.2.1,MIT
component-inherit,0.0.3,MIT*
compressible,2.0.11,MIT
compression,1.7.0,MIT
-compression-webpack-plugin,1.0.0,MIT
+compression-webpack-plugin,1.1.7,MIT
concat-map,0.0.1,MIT
concat-stream,1.5.2,MIT
concat-stream,1.6.0,MIT
concurrent-ruby-ext,1.0.5,MIT
-configstore,1.4.0,Simplified BSD
-connect,3.6.3,MIT
+configstore,3.1.1,Simplified BSD
+connect,3.6.6,MIT
connect-history-api-fallback,1.3.0,MIT
connection_pool,2.2.1,MIT
console-browserify,1.1.0,MIT
@@ -301,21 +337,25 @@ consolidate,0.14.5,MIT
constants-browserify,1.0.0,MIT
contains-path,0.1.0,MIT
content-disposition,0.5.2,MIT
-content-type,1.0.2,MIT
+content-type,1.0.4,MIT
convert-source-map,1.1.3,MIT
convert-source-map,1.5.0,MIT
cookie,0.3.1,MIT
cookie-signature,1.0.6,MIT
-copy-webpack-plugin,4.0.1,MIT
+copy-concurrently,1.0.5,ISC
+copy-descriptor,0.1.1,MIT
+copy-webpack-plugin,4.4.1,MIT
core-js,2.3.0,MIT
core-js,2.4.1,MIT
core-js,2.5.1,MIT
+core-js,2.5.3,MIT
core-util-is,1.0.2,MIT
cosmiconfig,2.1.1,MIT
crack,0.4.3,MIT
create-ecdh,4.0.0,MIT
-create-hash,1.1.2,MIT
-create-hmac,1.1.4,MIT
+create-error-class,3.0.2,MIT
+create-hash,1.1.3,MIT
+create-hmac,1.1.6,MIT
creole,0.5.0,ruby
cropper,2.3.0,MIT
cross-spawn,5.1.0,MIT
@@ -323,9 +363,9 @@ cryptiles,2.0.5,New BSD
cryptiles,3.1.2,New BSD
crypto-browserify,3.11.0,MIT
crypto-browserify,3.12.0,MIT
+crypto-random-string,1.0.0,MIT
css-color-names,0.0.4,MIT
-css-loader,0.28.0,MIT
-css-selector-tokenizer,0.6.0,MIT
+css-loader,0.28.9,MIT
css-selector-tokenizer,0.7.0,MIT
css_parser,1.5.0,MIT
cssesc,0.1.0,MIT
@@ -333,6 +373,7 @@ cssnano,3.10.0,MIT
csso,2.3.2,MIT
currently-unhandled,0.4.1,MIT
custom-event,1.0.1,MIT
+cyclist,0.2.2,MIT*
d,0.1.1,MIT
d,1.0.0,MIT
d3,3.5.17,New BSD
@@ -363,7 +404,6 @@ date-format,1.2.0,MIT
date-now,0.1.4,MIT
de-indent,1.0.2,MIT
debug,2.2.0,MIT
-debug,2.6.7,MIT
debug,2.6.8,MIT
debug,2.6.9,MIT
debug,3.1.0,MIT
@@ -372,6 +412,7 @@ decamelize,1.2.0,MIT
deckar01-task_list,2.0.0,MIT
declarative,0.0.10,MIT
declarative-option,0.1.0,MIT
+decode-uri-component,0.2.0,MIT
decompress-response,3.3.0,MIT
deep-equal,1.0.1,MIT
deep-extend,0.4.2,MIT
@@ -379,6 +420,9 @@ deep-is,0.1.3,MIT
default-require-extensions,1.0.0,MIT
default_value_for,3.0.2,MIT
define-properties,1.1.2,MIT
+define-property,0.2.5,MIT
+define-property,1.0.0,MIT
+define-property,2.0.2,MIT
defined,1.0.0,MIT
degenerator,1.0.4,MIT
del,2.2.2,MIT
@@ -386,14 +430,15 @@ del,3.0.0,MIT
delayed-stream,1.0.0,MIT
delegate,3.1.2,MIT
delegates,1.0.0,MIT
-depd,1.1.0,MIT
depd,1.1.1,MIT
deps-sort,2.0.0,MIT
des.js,1.0.0,MIT
descendants_tracker,0.0.4,MIT
destroy,1.0.4,MIT
detect-indent,4.0.0,MIT
+detect-libc,1.0.3,Apache 2.0
detect-node,2.0.3,ISC
+detect-port-alt,1.1.5,MIT
detective,4.7.1,MIT
devise,4.2.0,MIT
devise-two-factor,3.0.0,MIT
@@ -402,6 +447,7 @@ diff,3.4.0,New BSD
diff-lcs,1.3,"MIT,Artistic-2.0,GPL-2.0+"
diffie-hellman,5.0.2,MIT
diffy,3.1.0,MIT
+dir-glob,2.0.0,MIT
dns-equal,1.0.0,MIT
dns-packet,1.2.2,MIT
dns-txt,2.0.2,MIT
@@ -418,26 +464,28 @@ domhandler,2.4.1,Simplified BSD
domutils,1.6.2,Simplified BSD
doorkeeper,4.2.6,MIT
doorkeeper-openid_connect,1.2.0,MIT
+dot-prop,4.2.0,MIT
double-ended-queue,2.1.0-0,MIT
dropzone,4.2.0,MIT
dropzonejs-rails,0.7.2,MIT
duplexer,0.1.1,MIT
duplexer2,0.1.4,New BSD
duplexer3,0.1.4,New BSD
-duplexify,3.5.1,MIT
+duplexify,3.5.3,MIT
ecc-jsbn,0.1.1,MIT
ee-first,1.1.1,MIT
-ejs,2.5.6,Apache 2.0
+ejs,2.5.7,Apache 2.0
electron-to-chromium,1.3.3,ISC
-elliptic,6.3.3,MIT
+elliptic,6.4.0,MIT
email_reply_trimmer,0.1.6,MIT
emoji-unicode-version,0.2.1,MIT
emojis-list,2.1.0,MIT
-encodeurl,1.0.1,MIT
+encodeurl,1.0.2,MIT
encryptor,3.0.0,MIT
end-of-stream,1.4.0,MIT
-engine.io,3.1.4,MIT
-engine.io-client,3.1.4,MIT
+end-of-stream,1.4.1,MIT
+engine.io,3.1.5,MIT
+engine.io-client,3.1.5,MIT
engine.io-parser,2.1.2,MIT
enhanced-resolve,0.9.1,MIT
enhanced-resolve,3.4.1,MIT
@@ -447,7 +495,7 @@ equalizer,0.0.11,MIT
errno,0.1.4,MIT
error-ex,1.3.0,MIT
erubis,2.7.0,MIT
-es-abstract,1.8.2,MIT
+es-abstract,1.10.0,MIT
es-to-primitive,1.1.1,MIT
es5-ext,0.10.24,MIT
es6-iterator,2.0.1,MIT
@@ -487,28 +535,35 @@ estraverse,4.1.1,Simplified BSD
estraverse,4.2.0,Simplified BSD
esutils,2.0.2,Simplified BSD
et-orbi,1.0.3,MIT
-etag,1.8.0,MIT
+etag,1.8.1,MIT
eve-raphael,0.5.0,Apache 2.0
event-emitter,0.3.5,MIT
event-stream,3.3.4,MIT
eventemitter3,1.2.0,MIT
events,1.1.1,MIT
eventsource,0.1.6,MIT
-evp_bytestokey,1.0.0,MIT
+evp_bytestokey,1.0.3,MIT
excon,0.57.1,MIT
execa,0.7.0,MIT
execjs,2.6.0,MIT
exit-hook,1.1.1,MIT
expand-braces,0.1.2,MIT
expand-brackets,0.1.5,MIT
+expand-brackets,2.1.4,MIT
expand-range,0.1.1,MIT
expand-range,1.8.2,MIT
-exports-loader,0.6.4,MIT
-express,4.15.4,MIT
+expand-tilde,2.0.2,MIT
+exports-loader,0.7.0,MIT
+express,4.16.2,MIT
expression_parser,0.9.0,MIT
extend,3.0.1,MIT
+extend-shallow,2.0.1,MIT
+extend-shallow,3.0.2,MIT
+external-editor,2.1.0,MIT
extglob,0.3.2,MIT
+extglob,2.0.4,MIT
extsprintf,1.3.0,MIT
+extsprintf,1.4.0,MIT
faraday,0.12.2,MIT
faraday_middleware,0.11.0.1,MIT
faraday_middleware-multi_json,0.0.6,MIT
@@ -520,18 +575,19 @@ fast_gettext,1.4.0,"MIT,ruby"
fastparse,1.1.1,MIT
faye-websocket,0.10.0,MIT
faye-websocket,0.11.1,MIT
-faye-websocket,0.7.3,MIT
ffi,1.9.18,New BSD
figures,1.7.0,MIT
+figures,2.0.0,MIT
file-entry-cache,2.0.0,MIT
-file-loader,0.11.1,MIT
+file-loader,1.1.8,MIT
file-uri-to-path,1.0.0,MIT
-filename-regex,2.0.0,MIT
+filename-regex,2.0.1,MIT
fileset,2.0.3,MIT
-filesize,3.3.0,New BSD
-filesize,3.5.10,New BSD
+filesize,3.5.11,New BSD
+filesize,3.6.0,New BSD
fill-range,2.2.3,MIT
-finalhandler,1.0.4,MIT
+fill-range,4.0.0,MIT
+finalhandler,1.1.0,MIT
find-cache-dir,1.0.0,MIT
find-root,0.1.2,MIT
find-up,1.1.2,MIT
@@ -542,6 +598,7 @@ flipper,0.11.0,MIT
flipper-active_record,0.11.0,MIT
flipper-active_support_cache_store,0.11.0,MIT
flowdock,0.7.1,MIT
+flush-write-stream,1.0.2,MIT
fog-aliyun,0.2.0,MIT
fog-aws,1.4.0,MIT
fog-core,1.44.3,MIT
@@ -554,26 +611,26 @@ fog-xml,0.1.3,MIT
follow-redirects,1.0.0,MIT
follow-redirects,1.2.6,MIT
font-awesome-rails,4.7.0.1,"MIT,SIL Open Font License"
-for-each,0.3.2,MIT
-for-in,0.1.6,MIT
-for-own,0.1.4,MIT
+for-in,1.0.2,MIT
+for-own,0.1.5,MIT
foreach,2.0.5,MIT
forever-agent,0.6.1,Apache 2.0
form-data,2.0.0,MIT
form-data,2.1.4,MIT
-form-data,2.3.1,MIT
+form-data,2.3.2,MIT
formatador,0.2.5,MIT
-forwarded,0.1.0,MIT
-fresh,0.5.0,MIT
+forwarded,0.1.2,MIT
+fragment-cache,0.2.1,MIT
+fresh,0.5.2,MIT
from,0.1.7,MIT
+from2,2.3.0,MIT
fs-access,1.0.1,MIT
-fs-extra,0.26.7,MIT
+fs-write-stream-atomic,1.0.10,ISC
fs.realpath,1.0.0,ISC
-fsevents,1.1.2,MIT
+fsevents,1.1.3,MIT
fstream,1.0.11,ISC
fstream-ignore,1.0.5,ISC
ftp,0.3.10,MIT
-function-bind,1.1.0,MIT
function-bind,1.1.1,MIT
fuzzaldrin-plus,0.5.0,MIT
gauge,2.7.4,ISC
@@ -585,28 +642,33 @@ get-caller-file,1.0.2,ISC
get-stdin,4.0.1,MIT
get-stream,3.0.0,MIT
get-uri,2.0.1,MIT
+get-value,2.0.6,MIT
get_process_mem,0.2.0,MIT
getpass,0.1.7,MIT
gettext_i18n_rails,1.8.0,MIT
gettext_i18n_rails_js,1.2.0,MIT
-gitaly-proto,0.84.0,MIT
-github-linguist,4.7.6,MIT
+gitaly-proto,0.88.0,MIT
+github-linguist,5.3.3,MIT
github-markup,1.6.1,MIT
gitlab-flowdock-git-hook,1.0.1,MIT
gitlab-grit,2.8.2,MIT
gitlab-markup,1.6.3,MIT
gitlab_omniauth-ldap,2.0.4,MIT
glob,5.0.15,ISC
-glob,6.0.4,ISC
glob,7.1.1,ISC
glob,7.1.2,ISC
glob-base,0.3.0,MIT
glob-parent,2.0.0,ISC
+glob-parent,3.1.0,ISC
+global-dirs,0.1.1,MIT
+global-modules,1.0.0,MIT
+global-prefix,1.0.2,MIT
globalid,0.4.1,MIT
globals,10.4.0,MIT
globals,9.18.0,MIT
globby,5.0.0,MIT
globby,6.1.0,MIT
+globby,7.1.1,MIT
gollum-grit_adapter,1.0.1,MIT
gollum-lib,4.2.7,MIT
gollum-rugged_adapter,0.4.4,MIT
@@ -615,19 +677,19 @@ good-listener,1.2.2,MIT
google-api-client,0.13.6,Apache 2.0
google-protobuf,3.5.1,New BSD
googleapis-common-protos-types,1.0.1,Apache 2.0
-googleauth,0.5.3,Apache 2.0
-got,3.3.1,MIT
+googleauth,0.6.2,Apache 2.0
+got,6.7.1,MIT
got,7.1.0,MIT
gpgme,2.0.13,LGPL-2.1+
graceful-fs,4.1.11,ISC
-graceful-readlink,1.0.1,MIT
grape,1.0.0,MIT
grape-entity,0.6.0,MIT
grape-route-helpers,2.1.0,MIT
grape_logging,1.7.0,MIT
graphlib,2.1.1,MIT
-grpc,1.8.3,Apache 2.0
+grpc,1.10.0,Apache 2.0
gzip-size,3.0.0,MIT
+gzip-size,4.1.0,MIT
hamlit,2.6.1,MIT
handle-thing,1.2.5,MIT
handlebars,4.0.6,MIT
@@ -642,11 +704,18 @@ has-binary2,1.0.2,MIT
has-cors,1.1.0,MIT
has-flag,1.0.0,MIT
has-flag,2.0.0,MIT
+has-flag,3.0.0,MIT
has-symbol-support-x,1.3.0,MIT
has-to-string-tag-x,1.3.0,MIT
has-unicode,2.0.1,ISC
+has-value,0.3.1,MIT
+has-value,1.0.0,MIT
+has-values,0.1.4,MIT
+has-values,1.0.0,MIT
+hash-base,2.0.2,MIT
+hash-base,3.0.4,MIT
hash-sum,1.0.2,MIT
-hash.js,1.0.3,MIT
+hash.js,1.1.3,MIT
hashie,3.5.6,MIT
hashie-forbidden_attributes,0.1.1,MIT
hawk,3.1.3,New BSD
@@ -655,9 +724,11 @@ he,1.1.1,MIT
health_check,2.6.0,MIT
hipchat,1.5.2,MIT
hipchat-notifier,1.1.0,MIT
+hmac-drbg,1.0.1,MIT
hoek,2.16.3,New BSD
-hoek,4.2.0,New BSD
+hoek,4.2.1,New BSD
home-or-tmp,2.0.0,MIT
+homedir-polyfill,1.0.1,MIT
hosted-git-info,2.2.0,ISC
hpack.js,2.1.6,MIT
html-comment-regex,1.1.1,MIT
@@ -670,7 +741,6 @@ htmlparser2,3.9.2,MIT
http,0.9.8,MIT
http-cookie,1.0.3,MIT
http-deceiver,1.2.7,MIT
-http-errors,1.6.1,MIT
http-errors,1.6.2,MIT
http-form_data,1.0.1,MIT
http-proxy,1.16.2,MIT
@@ -690,26 +760,31 @@ i18n,0.9.1,MIT
ice_nine,0.11.2,MIT
iconv-lite,0.4.15,MIT
iconv-lite,0.4.19,MIT
-icss-replace-symbols,1.0.2,ISC
+icss-replace-symbols,1.1.0,ISC
+icss-utils,2.1.0,ISC
ieee754,1.1.8,New BSD
+iferr,0.1.5,MIT
ignore,3.3.3,MIT
+ignore,3.3.7,MIT
ignore-by-default,1.0.1,ISC
immediate,3.0.6,MIT
-imports-loader,0.7.1,MIT
+import-lazy,2.1.0,MIT
+import-local,1.0.0,MIT
+imports-loader,0.8.0,MIT
imurmurhash,0.1.4,MIT
indent-string,2.1.0,MIT
indexes-of,1.0.1,MIT
indexof,0.0.1,MIT*
-infinity-agent,2.0.3,MIT
inflection,1.10.0,MIT
inflection,1.3.8,MIT
inflight,1.0.6,ISC
influxdb,0.2.3,MIT
inherits,2.0.1,ISC
inherits,2.0.3,ISC
-ini,1.3.4,ISC
+ini,1.3.5,ISC
inline-source-map,0.6.2,MIT
inquirer,0.12.0,MIT
+inquirer,3.3.0,MIT
insert-module-globals,7.0.1,MIT
internal-ip,1.2.0,MIT
interpret,1.0.1,MIT
@@ -717,46 +792,62 @@ invariant,2.2.2,New BSD
invert-kv,1.0.0,MIT
ip,1.0.1,MIT
ip,1.1.5,MIT
-ipaddr.js,1.4.0,MIT
+ipaddr.js,1.6.0,MIT
ipaddress,0.8.3,MIT
is-absolute,0.2.6,MIT
is-absolute-url,2.1.0,MIT
+is-accessor-descriptor,0.1.6,MIT
+is-accessor-descriptor,1.0.0,MIT
is-arrayish,0.2.1,MIT
is-binary-path,1.0.1,MIT
is-buffer,1.1.5,MIT
is-buffer,1.1.6,MIT
is-builtin-module,1.0.0,MIT
is-callable,1.1.3,MIT
+is-data-descriptor,0.1.4,MIT
+is-data-descriptor,1.0.0,MIT
is-date-object,1.0.1,MIT
-is-dotfile,1.0.2,MIT
+is-descriptor,0.1.6,MIT
+is-descriptor,1.0.2,MIT
+is-dotfile,1.0.3,MIT
is-equal-shallow,0.1.3,MIT
is-extendable,0.1.1,MIT
+is-extendable,1.0.1,MIT
is-extglob,1.0.0,MIT
is-extglob,2.1.1,MIT
is-finite,1.0.2,MIT
is-fullwidth-code-point,1.0.0,MIT
is-fullwidth-code-point,2.0.0,MIT
-is-function,1.0.1,MIT
is-glob,2.0.1,MIT
is-glob,3.1.0,MIT
+is-glob,4.0.0,MIT
+is-installed-globally,0.1.0,MIT
+is-my-ip-valid,1.0.0,MIT
is-my-json-valid,2.16.0,MIT
-is-my-json-valid,2.17.1,MIT
+is-my-json-valid,2.17.2,MIT
is-npm,1.0.0,MIT
is-number,0.1.1,MIT
is-number,2.1.0,MIT
+is-number,3.0.0,MIT
+is-number,4.0.0,MIT
+is-obj,1.0.1,MIT
is-object,1.0.1,MIT
+is-odd,2.0.0,MIT
is-path-cwd,1.0.0,MIT
is-path-in-cwd,1.0.0,MIT
is-path-inside,1.0.0,MIT
is-plain-obj,1.1.0,MIT
+is-plain-object,2.0.4,MIT
is-posix-bracket,0.1.1,MIT
is-primitive,2.0.0,MIT
+is-promise,2.1.0,MIT
is-property,1.0.2,MIT
is-redirect,1.0.0,MIT
is-regex,1.0.4,MIT
is-relative,0.2.1,MIT
is-resolvable,1.0.0,MIT
is-retry-allowed,1.1.0,MIT
+is-root,1.0.0,MIT
is-stream,1.1.0,MIT
is-svg,2.1.0,MIT
is-symbol,1.0.1,MIT
@@ -764,12 +855,16 @@ is-typedarray,1.0.0,MIT
is-unc-path,0.1.2,MIT
is-utf8,0.2.1,MIT
is-windows,0.2.0,MIT
+is-windows,1.0.2,MIT
+is-wsl,1.1.0,MIT
isarray,0.0.1,MIT
isarray,1.0.0,MIT
isarray,2.0.1,MIT
isbinaryfile,3.0.2,MIT
isexe,1.1.2,ISC
+isexe,2.0.0,ISC
isobject,2.1.0,MIT
+isobject,3.0.1,MIT
isstream,0.1.2,MIT
istanbul,0.4.5,New BSD
istanbul-api,1.2.1,New BSD
@@ -784,10 +879,11 @@ jasmine-core,2.9.0,MIT
jasmine-jquery,2.1.1,MIT
jed,1.1.1,MIT
jira-ruby,1.4.1,MIT
-jquery,2.2.4,MIT
+jquery,3.3.1,MIT
jquery-atwho-rails,1.3.2,MIT
jquery-rails,4.3.1,MIT
jquery-ujs,1.2.2,MIT
+jquery.waitforimages,2.2.0,MIT
js-base64,2.1.9,New BSD
js-cookie,2.1.3,MIT
js-tokens,3.0.2,MIT
@@ -806,7 +902,6 @@ json-stable-stringify,1.0.1,MIT
json-stringify-safe,5.0.1,ISC
json3,3.3.2,MIT
json5,0.5.1,MIT
-jsonfile,2.4.0,MIT
jsonify,0.0.0,Public Domain
jsonparse,1.3.1,MIT
jsonpointer,4.0.1,MIT
@@ -820,18 +915,23 @@ kaminari-activerecord,1.0.1,MIT
kaminari-core,1.0.1,MIT
karma,2.0.0,MIT
karma-chrome-launcher,2.2.0,MIT
-karma-coverage-istanbul-reporter,1.3.3,MIT
+karma-coverage-istanbul-reporter,1.4.1,MIT
karma-jasmine,1.1.1,MIT
karma-mocha-reporter,2.2.5,MIT
karma-sourcemap-loader,0.3.7,MIT
karma-webpack,2.0.7,MIT
+katex,0.8.3,MIT
kgio,2.10.0,LGPL-2.1+
-kind-of,3.1.0,MIT
-klaw,1.3.1,MIT
+killable,1.0.0,ISC
+kind-of,3.2.2,MIT
+kind-of,4.0.0,MIT
+kind-of,5.1.0,MIT
+kind-of,6.0.2,MIT
kubeclient,2.2.0,MIT
labeled-stream-splicer,2.0.0,MIT
-latest-version,1.0.1,MIT
+latest-version,3.1.0,MIT
lazy-cache,1.0.4,MIT
+lazy-cache,2.0.2,MIT
lcid,1.0.0,MIT
levn,0.3.0,MIT
lexical-scope,1.2.0,MIT
@@ -850,37 +950,31 @@ locale,2.1.2,"ruby,LGPLv3+"
locate-path,2.0.0,MIT
lodash,3.10.1,MIT
lodash,4.17.4,MIT
-lodash._baseassign,3.2.0,MIT
-lodash._basecopy,3.0.1,MIT
+lodash,4.17.5,MIT
lodash._baseget,3.7.2,MIT
-lodash._bindcallback,3.0.1,MIT
-lodash._createassigner,3.1.1,MIT
-lodash._getnative,3.9.1,MIT
-lodash._isiterateecall,3.0.9,MIT
lodash._topath,3.8.1,MIT
-lodash.assign,3.2.0,MIT
lodash.camelcase,4.1.1,MIT
lodash.camelcase,4.3.0,MIT
lodash.capitalize,4.2.1,MIT
lodash.clonedeep,4.5.0,MIT
lodash.cond,4.5.2,MIT
lodash.deburr,4.1.0,MIT
-lodash.defaults,3.1.2,MIT
+lodash.endswith,4.2.1,MIT
lodash.escaperegexp,4.1.2,MIT
lodash.get,3.7.0,MIT
-lodash.isarguments,3.1.0,MIT
lodash.isarray,3.0.4,MIT
+lodash.isfunction,3.0.9,MIT
+lodash.isstring,4.0.1,MIT
lodash.kebabcase,4.0.1,MIT
-lodash.keys,3.1.2,MIT
lodash.memoize,3.0.4,MIT
lodash.memoize,4.1.2,MIT
lodash.mergewith,4.6.0,MIT
-lodash.restparam,3.6.1,MIT
lodash.snakecase,4.0.1,MIT
+lodash.startswith,4.2.1,MIT
lodash.uniq,4.5.0,MIT
lodash.words,4.2.0,MIT
log-symbols,2.1.0,MIT
-log4js,2.4.1,Apache 2.0
+log4js,2.5.3,Apache 2.0
logging,2.2.2,MIT
loggly,1.1.1,MIT
loglevel,1.4.1,MIT
@@ -890,7 +984,6 @@ loofah,2.0.3,MIT
loose-envify,1.3.1,MIT
loud-rejection,1.6.0,MIT
lowercase-keys,1.0.0,MIT
-lru-cache,2.2.4,MIT
lru-cache,2.6.5,ISC
lru-cache,4.1.1,ISC
macaddress,0.2.8,MIT
@@ -899,10 +992,14 @@ mail_room,0.9.1,MIT
mailcomposer,4.0.1,MIT
mailgun-js,0.7.15,MIT
make-dir,1.0.0,MIT
+map-cache,0.2.2,MIT
map-obj,1.0.1,MIT
map-stream,0.1.0,Unknown
+map-visit,1.0.0,MIT
marked,0.3.12,MIT
+match-at,0.1.1,MIT
math-expression-evaluator,1.2.16,MIT
+md5.js,1.3.4,MIT
media-typer,0.3.0,MIT
mem,1.1.0,MIT
memoist,0.16.0,MIT
@@ -913,14 +1010,13 @@ merge-descriptors,1.0.1,MIT
method_source,0.8.2,MIT
methods,1.1.2,MIT
micromatch,2.3.11,MIT
-miller-rabin,4.0.0,MIT
-mime,1.3.4,MIT
+micromatch,3.1.6,MIT
+miller-rabin,4.0.1,MIT
+mime,1.4.1,MIT
mime,1.6.0,MIT
-mime-db,1.27.0,MIT
mime-db,1.29.0,MIT
-mime-db,1.30.0,MIT
-mime-types,2.1.15,MIT
-mime-types,2.1.17,MIT
+mime-db,1.33.0,MIT
+mime-types,2.1.18,MIT
mime-types,3.1,MIT
mime-types-data,3.2016.0521,MIT
mimemagic,0.3.0,MIT
@@ -929,19 +1025,24 @@ mimic-response,1.0.0,MIT
mini_mime,0.1.4,MIT
mini_portile2,2.3.0,MIT
minimalistic-assert,1.0.0,ISC
+minimalistic-crypto-utils,1.0.1,MIT
minimatch,3.0.3,ISC
minimatch,3.0.4,ISC
+minimist,0.0.10,MIT
minimist,0.0.8,MIT
minimist,1.2.0,MIT
+mississippi,2.0.0,Simplified BSD
+mixin-deep,1.3.1,MIT
mkdirp,0.5.1,MIT
module-deps,4.1.1,MIT
moment,2.19.2,MIT
monaco-editor,0.10.0,MIT
mousetrap,1.4.6,Apache 2.0
mousetrap-rails,1.4.6,"MIT,Apache"
+move-concurrently,1.0.1,ISC
ms,0.7.1,MIT
ms,2.0.0,MIT
-multi_json,1.12.2,MIT
+multi_json,1.13.1,MIT
multi_xml,0.6.0,MIT
multicast-dns,6.1.1,MIT
multicast-dns-service-types,1.1.0,MIT
@@ -949,21 +1050,21 @@ multipart-post,2.0.0,MIT
mustermann,1.0.0,MIT
mustermann-grape,1.0.0,MIT
mute-stream,0.0.5,ISC
+mute-stream,0.0.7,ISC
mysql2,0.4.10,MIT
name-all-modules-plugin,1.0.1,MIT
-nan,2.6.2,MIT
+nan,2.8.0,MIT
+nanomatch,1.2.9,MIT
natural-compare,1.4.0,MIT
negotiator,0.6.1,MIT
-nested-error-stacks,1.0.2,MIT
net-ldap,0.16.0,MIT
net-ssh,4.1.0,MIT
netmask,1.0.6,MIT
netrc,0.11.0,MIT
-node-dir,0.1.17,MIT
node-forge,0.6.33,New BSD
node-libs-browser,1.1.1,MIT
node-libs-browser,2.0.0,MIT
-node-pre-gyp,0.6.37,New BSD
+node-pre-gyp,0.6.39,New BSD
node-uuid,1.4.8,MIT
nodemailer,2.7.2,MIT
nodemailer-direct-transport,3.3.2,MIT
@@ -972,7 +1073,7 @@ nodemailer-shared,1.1.0,MIT
nodemailer-smtp-pool,2.8.2,MIT
nodemailer-smtp-transport,2.7.2,MIT
nodemailer-wellknown,0.1.10,MIT
-nodemon,1.11.0,MIT
+nodemon,1.15.1,MIT
nokogiri,1.8.2,MIT
nopt,1.0.10,MIT
nopt,3.0.6,ISC
@@ -990,12 +1091,13 @@ numerizer,0.1.1,MIT
oauth,0.5.1,MIT
oauth-sign,0.8.2,Apache 2.0
oauth2,1.4.0,MIT
-object-assign,3.0.0,MIT
object-assign,4.1.1,MIT
object-component,0.0.3,MIT*
-object-inspect,1.3.0,MIT
+object-copy,0.1.0,MIT
object-keys,1.0.11,MIT
+object-visit,1.0.1,MIT
object.omit,2.0.1,MIT
+object.pick,1.3.0,MIT
obuf,1.1.1,MIT
octokit,4.6.2,MIT
oj,2.17.5,MIT
@@ -1021,8 +1123,9 @@ on-finished,2.3.0,MIT
on-headers,1.0.1,MIT
once,1.4.0,ISC
onetime,1.1.0,MIT
+onetime,2.0.1,MIT
opener,1.4.3,(WTFPL OR MIT)
-opn,4.0.2,MIT
+opn,5.2.0,MIT
optimist,0.6.1,MIT
optionator,0.8.2,MIT
org-ruby,0.9.12,MIT
@@ -1035,27 +1138,33 @@ os-homedir,1.0.2,MIT
os-locale,1.4.0,MIT
os-locale,2.1.0,MIT
os-tmpdir,1.0.2,MIT
-osenv,0.1.4,ISC
+osenv,0.1.5,ISC
p-cancelable,0.3.0,MIT
p-finally,1.0.0,MIT
p-limit,1.1.0,MIT
+p-limit,1.2.0,MIT
p-locate,2.0.0,MIT
p-map,1.1.1,MIT
p-timeout,1.2.0,MIT
+p-try,1.0.0,MIT
pac-proxy-agent,1.1.0,MIT
pac-resolver,2.0.0,MIT
-package-json,1.2.0,MIT
+package-json,4.0.1,MIT
pako,0.2.9,MIT
pako,1.0.5,(MIT AND Zlib)
pako,1.0.6,(MIT AND Zlib)
+parallel-transform,1.1.0,MIT
parents,1.0.1,MIT
-parse-asn1,5.0.0,ISC
+parse-asn1,5.1.0,ISC
parse-glob,3.0.4,MIT
parse-json,2.2.0,MIT
+parse-passwd,1.0.0,MIT
parseqs,0.0.5,MIT
parseuri,0.0.5,MIT
-parseurl,1.3.1,MIT
+parseurl,1.3.2,MIT
+pascalcase,0.1.1,MIT
path-browserify,0.0.0,MIT
+path-dirname,1.0.2,MIT
path-exists,2.1.0,MIT
path-exists,3.0.0,MIT
path-is-absolute,1.0.1,MIT
@@ -1067,13 +1176,14 @@ path-proxy,1.0.0,MIT
path-to-regexp,0.1.7,MIT
path-type,1.1.0,MIT
path-type,2.0.0,MIT
+path-type,3.0.0,MIT
pause-stream,0.0.11,Apache 2.0
-pbkdf2,3.0.9,MIT
+pbkdf2,3.0.14,MIT
peek,1.0.1,MIT
peek-gc,0.0.2,MIT
peek-host,1.0.0,MIT
peek-mysql2,1.1.0,MIT
-peek-performance_bar,1.3.0,MIT
+peek-performance_bar,1.3.1,MIT
peek-pg,1.3.0,MIT
peek-rblineprof,0.2.0,MIT
peek-redis,1.2.0,MIT
@@ -1092,10 +1202,12 @@ pkg-up,1.0.0,MIT
pluralize,1.2.1,MIT
po_to_json,1.0.1,MIT
portfinder,1.0.13,MIT
+posix-character-classes,0.1.1,MIT
posix-spawn,0.3.13,MIT
postcss,5.2.16,MIT
postcss,6.0.14,MIT
postcss,6.0.15,MIT
+postcss,6.0.19,MIT
postcss-calc,5.3.1,MIT
postcss-colormin,2.2.2,MIT
postcss-convert-values,2.6.1,MIT
@@ -1116,10 +1228,10 @@ postcss-minify-font-values,1.0.5,MIT
postcss-minify-gradients,1.0.5,MIT
postcss-minify-params,1.2.2,MIT
postcss-minify-selectors,2.1.1,MIT
-postcss-modules-extract-imports,1.0.1,ISC
-postcss-modules-local-by-default,1.1.1,MIT
-postcss-modules-scope,1.0.2,ISC
-postcss-modules-values,1.2.2,ISC
+postcss-modules-extract-imports,1.2.0,ISC
+postcss-modules-local-by-default,1.2.0,MIT
+postcss-modules-scope,1.1.0,ISC
+postcss-modules-values,1.3.0,ISC
postcss-normalize-charset,1.1.1,MIT
postcss-normalize-url,3.0.8,MIT
postcss-ordered-values,2.2.3,MIT
@@ -1140,26 +1252,31 @@ prettier,1.8.2,MIT
prettier,1.9.2,MIT
prismjs,1.6.0,MIT
private,0.1.8,MIT
+process,0.11.10,MIT
process,0.11.9,MIT
process-nextick-args,1.0.7,MIT
+process-nextick-args,2.0.0,MIT
progress,1.1.8,MIT
prometheus-client-mmap,0.9.1,Apache 2.0
-proxy-addr,1.1.5,MIT
+promise-inflight,1.0.1,ISC
+proxy-addr,2.0.3,MIT
proxy-agent,2.0.0,MIT
prr,0.0.0,MIT
ps-tree,1.1.0,MIT
pseudomap,1.0.2,ISC
+pstree.remy,1.1.0,MIT
public-encrypt,4.0.0,MIT
-public_suffix,3.0.0,MIT
+public_suffix,3.0.2,MIT
+pump,2.0.1,MIT
+pumpify,1.4.0,MIT
punycode,1.3.2,MIT
punycode,1.4.1,MIT
pyu-ruby-sasl,0.0.3.3,MIT
q,1.4.1,MIT
q,1.5.0,MIT
-qjobs,1.1.5,MIT
+qjobs,1.2.0,MIT
qs,6.2.3,New BSD
qs,6.4.0,New BSD
-qs,6.5.0,New BSD
qs,6.5.1,New BSD
query-string,4.3.2,MIT
querystring,0.2.0,MIT
@@ -1183,14 +1300,12 @@ railties,4.2.10,MIT
rainbow,2.2.2,MIT
raindrops,0.18.0,LGPL-2.1+
rake,12.3.0,MIT
-randomatic,1.1.6,MIT
-randombytes,2.0.3,MIT
+randomatic,1.1.7,MIT
randombytes,2.0.6,MIT
-randomfill,1.0.3,MIT
+randomfill,1.0.4,MIT
range-parser,1.2.0,MIT
raphael,2.2.7,MIT
raven-js,3.22.1,Simplified BSD
-raw-body,2.2.0,MIT
raw-body,2.3.2,MIT
raw-loader,0.5.1,MIT
rb-fsevent,0.10.2,MIT
@@ -1198,10 +1313,11 @@ rb-inotify,0.9.10,MIT
rbnacl,4.0.2,MIT
rbnacl-libsodium,1.0.11,MIT
rc,1.2.1,(BSD-2-Clause OR MIT OR Apache-2.0)
+rc,1.2.5,(BSD-2-Clause OR MIT OR Apache-2.0)
rdoc,4.2.2,ruby
re2,1.1.1,New BSD
-react-dev-utils,0.5.2,New BSD
-read-all-stream,3.1.0,MIT
+react-dev-utils,5.0.0,MIT
+react-error-overlay,4.0.0,MIT
read-only-stream,2.0.0,MIT
read-pkg,1.1.0,MIT
read-pkg,2.0.0,MIT
@@ -1210,12 +1326,13 @@ read-pkg-up,2.0.0,MIT
readable-stream,1.1.14,MIT
readable-stream,2.0.6,MIT
readable-stream,2.3.3,MIT
+readable-stream,2.3.4,MIT
readdirp,2.1.0,MIT
readline2,1.0.1,MIT
recaptcha,3.0.0,MIT
rechoir,0.6.2,MIT
recursive-open-struct,1.0.0,MIT
-recursive-readdir,2.1.1,MIT
+recursive-readdir,2.2.1,MIT
redcarpet,3.4.0,MIT
redent,1.0.0,MIT
redis,2.8.0,MIT
@@ -1233,9 +1350,11 @@ reduce-function-call,1.0.2,MIT
regenerate,1.3.2,MIT
regenerator-runtime,0.11.0,MIT
regenerator-transform,0.10.1,BSD
-regex-cache,0.4.3,MIT
+regex-cache,0.4.4,MIT
+regex-not,1.0.2,MIT
regexpu-core,1.0.0,MIT
regexpu-core,2.0.0,MIT
+registry-auth-token,3.3.2,MIT
registry-url,3.1.0,MIT
regjsgen,0.2.0,MIT
regjsparser,0.1.5,Simplified BSD
@@ -1243,14 +1362,13 @@ remove-trailing-separator,1.1.0,ISC
repeat-element,1.1.2,MIT
repeat-string,0.2.2,MIT
repeat-string,1.6.1,MIT
-repeating,1.1.3,MIT
repeating,2.0.1,MIT
representable,3.0.4,MIT
request,2.75.0,Apache 2.0
request,2.81.0,Apache 2.0
request,2.83.0,Apache 2.0
request_store,1.3.1,MIT
-requestretry,1.12.2,MIT
+requestretry,1.13.0,MIT
require-all,2.2.0,MIT
require-directory,2.1.1,MIT
require-from-string,1.2.1,MIT
@@ -1258,22 +1376,28 @@ require-main-filename,1.0.1,ISC
require-uncached,1.0.3,MIT
requires-port,1.0.0,MIT
resolve,1.1.7,MIT
-resolve,1.4.0,MIT
resolve,1.5.0,MIT
+resolve-cwd,2.0.0,MIT
+resolve-dir,1.0.1,MIT
resolve-from,1.0.1,MIT
+resolve-from,3.0.0,MIT
+resolve-url,0.2.1,MIT
responders,2.3.0,MIT
rest-client,2.0.0,MIT
restore-cursor,1.0.1,MIT
-resumer,0.0.0,MIT
+restore-cursor,2.0.0,MIT
+ret,0.1.15,MIT
retriable,3.1.1,MIT
right-align,0.1.3,MIT
rimraf,2.6.1,ISC
+rimraf,2.6.2,ISC
rinku,2.0.0,ISC
-ripemd160,1.0.1,New BSD
+ripemd160,2.0.1,MIT
rotp,2.1.2,MIT
rouge,2.2.1,MIT
rqrcode,0.7.0,MIT
rqrcode-rails3,0.1.7,MIT
+ruby-enum,0.7.2,MIT
ruby-fogbugz,0.2.1,MIT
ruby-prof,0.16.2,Simplified BSD
ruby-saml,1.4.1,MIT
@@ -1283,9 +1407,13 @@ rubypants,0.2.0,BSD
rufus-scheduler,3.4.0,MIT
rugged,0.26.0,MIT
run-async,0.1.0,MIT
+run-async,2.3.0,MIT
+run-queue,1.0.3,ISC
rx-lite,3.1.2,Apache 2.0
-safe-buffer,5.0.1,MIT
+rx-lite,4.0.8,Apache 2.0
+rx-lite-aggregates,4.0.8,Apache 2.0
safe-buffer,5.1.1,MIT
+safe-regex,1.1.0,MIT
safe_yaml,1.0.4,MIT
sanitize,2.1.0,MIT
sanitize-html,1.16.3,MIT
@@ -1295,6 +1423,7 @@ sass-rails,5.0.6,MIT
sawyer,0.8.1,MIT
sax,1.2.2,ISC
schema-utils,0.3.0,MIT
+schema-utils,0.4.5,MIT
securecompare,1.0.0,MIT
seed-fu,2.3.7,MIT
select,1.1.2,MIT
@@ -1304,19 +1433,24 @@ select2-rails,3.5.9.3,MIT
selfsigned,1.10.1,MIT
semver,5.0.3,ISC
semver,5.3.0,ISC
+semver,5.5.0,ISC
semver-diff,2.1.0,MIT
-send,0.15.4,MIT
+send,0.16.1,MIT
sentry-raven,2.5.3,Apache 2.0
+serialize-javascript,1.4.0,New BSD
serve-index,1.9.0,MIT
-serve-static,1.12.4,MIT
+serve-static,1.13.1,MIT
set-blocking,2.0.0,ISC
+set-getter,0.1.0,MIT
set-immediate-shim,1.0.1,MIT
+set-value,0.4.3,MIT
+set-value,2.0.0,MIT
setimmediate,1.0.5,MIT
setprototypeof,1.0.3,ISC
+setprototypeof,1.1.0,ISC
settingslogic,2.0.9,MIT
sexp_processor,4.9.0,MIT
-sha.js,2.4.8,MIT
-sha.js,2.4.9,MIT
+sha.js,2.4.10,MIT
shasum,1.0.2,MIT
shebang-command,1.2.0,MIT
shebang-regex,1.0.0,MIT
@@ -1326,64 +1460,72 @@ sidekiq,5.0.5,LGPL
sidekiq-cron,0.6.0,MIT
sidekiq-limit_fetch,3.4.0,MIT
signal-exit,3.0.2,ISC
-signet,0.7.3,Apache 2.0
+signet,0.8.1,Apache 2.0
slack-node,0.2.0,MIT
slack-notifier,1.5.1,MIT
slash,1.0.0,MIT
slice-ansi,0.0.4,MIT
-slide,1.1.6,ISC
smart-buffer,1.1.15,MIT
smtp-connection,2.12.0,MIT
+snapdragon,0.8.1,MIT
+snapdragon-node,2.1.1,MIT
+snapdragon-util,3.0.1,MIT
sntp,1.0.9,BSD
sntp,2.1.0,BSD
socket.io,2.0.4,MIT
socket.io-adapter,1.1.1,MIT
socket.io-client,2.0.4,MIT
socket.io-parser,3.1.2,MIT
-sockjs,0.3.18,MIT
-sockjs-client,1.0.1,MIT
+sockjs,0.3.19,MIT
sockjs-client,1.1.4,MIT
socks,1.1.10,MIT
socks,1.1.9,MIT
socks-proxy-agent,2.1.1,MIT
sort-keys,1.1.2,MIT
-source-list-map,0.1.8,MIT
source-list-map,2.0.0,MIT
source-map,0.2.0,New BSD
source-map,0.4.4,New BSD
+source-map,0.5.0,New BSD
source-map,0.5.6,New BSD
source-map,0.5.7,New BSD
source-map,0.6.1,New BSD
+source-map-resolve,0.5.1,MIT
source-map-support,0.4.18,MIT
+source-map-url,0.4.0,MIT
spdx-correct,1.0.2,Apache 2.0
spdx-expression-parse,1.0.4,(MIT AND CC-BY-3.0)
spdx-license-ids,1.2.2,Unlicense
spdy,3.4.7,MIT
spdy-transport,2.0.20,MIT
split,0.3.3,MIT
+split-string,3.1.0,MIT
sprintf-js,1.0.3,New BSD
sprockets,3.7.1,MIT
sprockets-rails,3.2.1,MIT
sql.js,0.4.0,MIT
srcset,1.0.0,MIT
+sshkey,1.9.0,MIT
sshpk,1.13.1,MIT
+ssri,5.2.4,ISC
state_machines,0.4.0,MIT
state_machines-activemodel,0.4.0,MIT
state_machines-activerecord,0.4.0,MIT
+static-extend,0.1.2,MIT
statuses,1.3.1,MIT
+statuses,1.4.0,MIT
stream-browserify,2.0.1,MIT
stream-combiner,0.0.4,MIT
stream-combiner2,1.1.1,MIT
+stream-each,1.2.2,MIT
stream-http,2.6.3,MIT
-stream-http,2.7.2,MIT
+stream-http,2.8.0,MIT
stream-shift,1.0.0,MIT
stream-splicer,2.0.0,MIT
streamroller,0.7.0,MIT
strict-uri-encode,1.1.0,MIT
-string-length,1.0.1,MIT
string-width,1.0.2,MIT
string-width,2.0.0,MIT
-string.prototype.trim,1.1.2,MIT
+string-width,2.1.1,MIT
string_decoder,0.10.31,MIT
string_decoder,1.0.3,MIT
stringex,2.7.1,MIT
@@ -1395,23 +1537,25 @@ strip-bom,3.0.0,MIT
strip-eof,1.0.0,MIT
strip-indent,1.0.1,MIT
strip-json-comments,2.0.1,MIT
+style-loader,0.20.2,MIT
subarg,1.0.0,MIT
supports-color,2.0.0,MIT
supports-color,3.2.3,MIT
supports-color,4.2.1,MIT
supports-color,4.5.0,MIT
supports-color,5.1.0,MIT
+supports-color,5.2.0,MIT
svg4everybody,2.1.9,CC0-1.0
svgo,0.7.2,MIT
-syntax-error,1.3.0,MIT
+syntax-error,1.4.0,MIT
sys-filesystem,1.1.6,Artistic 2.0
table,3.8.3,New BSD
tapable,0.1.10,MIT
tapable,0.2.8,MIT
-tape,4.8.0,MIT
tar,2.2.1,ISC
-tar-pack,3.4.0,Simplified BSD
+tar-pack,3.4.1,Simplified BSD
temple,0.7.7,MIT
+term-size,1.2.0,MIT
test-exclude,4.1.1,ISC
text,1.3.1,MIT
text-table,0.2.0,MIT
@@ -1427,35 +1571,37 @@ thunky,0.1.0,MIT*
tilt,2.0.6,MIT
time-stamp,2.0.0,MIT
timeago.js,3.0.2,MIT
-timed-out,2.0.0,MIT
timed-out,4.0.1,MIT
timers-browserify,1.4.2,MIT
timers-browserify,2.0.4,MIT
timespan,2.3.0,MIT
timfel-krb5-auth,0.8.3,LGPL
tiny-emitter,2.0.2,MIT
-tmp,0.0.31,MIT
tmp,0.0.33,MIT
to-array,0.1.4,MIT
to-arraybuffer,1.0.1,MIT
to-fast-properties,1.0.3,MIT
to-fast-properties,2.0.0,MIT
-toml-rb,0.3.15,MIT
-touch,1.0.0,ISC
-tough-cookie,2.3.2,New BSD
+to-object-path,0.3.0,MIT
+to-regex,3.0.1,MIT
+to-regex-range,2.1.1,MIT
+toml-rb,1.0.0,MIT
+touch,3.1.0,ISC
tough-cookie,2.3.3,New BSD
traverse,0.6.6,MIT
trim-newlines,1.0.0,MIT
trim-right,1.0.1,MIT
truncato,0.7.10,MIT
+tryer,1.0.0,MIT
tryit,1.0.3,MIT
tsscmp,1.0.5,MIT
tty-browserify,0.0.0,MIT
+tty-browserify,0.0.1,MIT
tunnel-agent,0.4.3,Apache 2.0
tunnel-agent,0.6.0,Apache 2.0
tweetnacl,0.14.5,Unlicense
type-check,0.3.2,MIT
-type-is,1.6.15,MIT
+type-is,1.6.16,MIT
typedarray,0.0.6,MIT
tzinfo,1.2.4,MIT
u2f,0.2.1,MIT
@@ -1465,40 +1611,48 @@ uglify-js,2.8.29,Simplified BSD
uglify-to-browserify,1.0.2,MIT
uglifyjs-webpack-plugin,0.4.6,MIT
uid-number,0.0.6,ISC
-ultron,1.1.0,MIT
+ultron,1.1.1,MIT
umd,3.0.1,MIT
unc-path-regex,0.1.2,MIT
-undefsafe,0.0.3,MIT / http://rem.mit-license.org
+undefsafe,2.0.2,MIT
underscore,1.7.0,MIT
underscore,1.8.3,MIT
unf,0.1.4,BSD
unf_ext,0.0.7.4,MIT
unicorn,5.1.0,ruby
unicorn-worker-killer,0.4.4,ruby
+union-value,1.0.0,MIT
uniq,1.0.1,MIT
uniqid,4.1.1,MIT
uniqs,2.0.0,MIT
+unique-filename,1.1.0,ISC
+unique-slug,2.0.0,ISC
+unique-string,1.0.0,MIT
unpipe,1.0.0,MIT
-update-notifier,0.5.0,Simplified BSD
+unset-value,1.0.0,MIT
+unzip-response,2.0.1,MIT
+upath,1.0.2,MIT
+update-notifier,2.3.0,Simplified BSD
+urix,0.1.0,MIT
url,0.11.0,MIT
-url-loader,0.5.8,MIT
+url-loader,0.6.2,MIT
url-parse,1.0.5,MIT
-url-parse,1.1.7,MIT
url-parse,1.1.9,MIT
url-parse-lax,1.0.0,MIT
url-to-options,1.0.1,MIT
url_safe_base64,0.2.2,MIT
+use,2.0.2,MIT
user-home,2.0.0,MIT
-useragent,2.2.1,MIT
+useragent,2.3.0,MIT
util,0.10.3,MIT
util-deprecate,1.0.2,MIT
-utils-merge,1.0.0,MIT
-uuid,2.0.3,MIT
-uuid,3.1.0,MIT
-uws,0.14.5,Zlib
+utils-merge,1.0.1,MIT
+uuid,3.2.1,MIT
+uws,9.14.0,Zlib
validate-npm-package-license,3.0.1,Apache 2.0
validates_hostname,1.0.6,MIT
vary,1.1.1,MIT
+vary,1.1.2,MIT
vendors,1.0.1,MIT
verror,1.10.0,MIT
version_sorter,2.1.0,MIT
@@ -1510,21 +1664,20 @@ void-elements,2.0.1,MIT
vue,2.5.13,MIT
vue-eslint-parser,2.0.1,MIT
vue-hot-reload-api,2.2.4,MIT
-vue-loader,13.7.0,MIT
+vue-loader,14.1.1,MIT
vue-resource,1.3.5,MIT
vue-router,3.0.1,MIT
-vue-style-loader,3.0.3,MIT
+vue-style-loader,4.0.2,MIT
vue-template-compiler,2.5.13,MIT
vue-template-es2015-compiler,1.6.0,MIT
vuex,3.0.1,MIT
warden,1.2.6,MIT
watchpack,1.4.0,MIT
wbuf,1.7.2,MIT
-webpack,3.5.5,MIT
-webpack-bundle-analyzer,2.8.2,MIT
-webpack-dev-middleware,1.11.0,MIT
+webpack,3.11.0,MIT
+webpack-bundle-analyzer,2.10.0,MIT
webpack-dev-middleware,1.12.2,MIT
-webpack-dev-server,2.7.1,MIT
+webpack-dev-server,2.11.2,MIT
webpack-rails,0.9.10,MIT
webpack-sources,1.0.1,MIT
webpack-stats-plugin,0.1.5,MIT
@@ -1533,9 +1686,11 @@ websocket-extensions,0.1.1,MIT
when,3.7.8,MIT
whet.extend,0.9.9,MIT
which,1.2.12,ISC
+which,1.3.0,ISC
which-module,1.0.0,ISC
which-module,2.0.0,ISC
wide-align,1.1.2,ISC
+widest-line,2.0.0,MIT
wikicloth,0.8.1,MIT
window-size,0.1.0,MIT
wordwrap,0.0.2,MIT
@@ -1545,15 +1700,16 @@ worker-loader,1.1.0,MIT
wrap-ansi,2.1.0,MIT
wrappy,1.0.2,ISC
write,0.2.1,MIT
-write-file-atomic,1.3.4,ISC
-ws,2.3.1,MIT
+write-file-atomic,2.3.0,ISC
ws,3.3.3,MIT
-xdg-basedir,2.0.0,MIT
+ws,4.0.0,MIT
+xdg-basedir,3.0.0,MIT
xml-simple,1.1.5,ruby
xmlhttprequest-ssl,1.5.5,MIT
xregexp,2.0.0,MIT
xtend,4.0.1,MIT
y18n,3.2.1,ISC
+y18n,4.0.0,ISC
yallist,2.1.2,ISC
yargs,3.10.0,MIT
yargs,6.6.0,MIT
diff --git a/vendor/runner/values.yaml b/vendor/runner/values.yaml
index b7e2e24acaf..e5f95152ac7 100644
--- a/vendor/runner/values.yaml
+++ b/vendor/runner/values.yaml
@@ -15,10 +15,8 @@ rbac:
clusterWideAccess: false
## Configuration for the Pods that that the runner launches for each new job
-##
runners:
image: ubuntu:16.04
- privileged: false
builds: {}
services: {}
helpers: {}
diff --git a/yarn.lock b/yarn.lock
index ab0ad265d81..a2eee3a547d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -54,9 +54,9 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
-"@gitlab-org/gitlab-svgs@^1.8.0":
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.8.0.tgz#95d6afa94395860699ddad60a82bd1bbbc2ba89f"
+"@gitlab-org/gitlab-svgs@^1.13.0":
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.13.0.tgz#9e856ef9fa7bbe49b2dce9789187a89e11311215"
"@types/jquery@^2.0.40":
version "2.0.48"