summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouwe Maan <douwe@selenight.nl>2017-10-05 13:12:08 +0200
committerDouwe Maan <douwe@selenight.nl>2017-10-05 13:12:08 +0200
commit5daa8fbc29ee2fc309602d24167a401563bc3b2c (patch)
treeb99d1b6c54435e2fe1c2565c87ab9a41c36a5cd2
parente0fdcd19ec1973963452dde4384e071286f044b1 (diff)
parentde01353b166018a43ea92b38054b1267c3ba5cea (diff)
downloadgitlab-ce-5daa8fbc29ee2fc309602d24167a401563bc3b2c.tar.gz
Add changelog
-rw-r--r--.flayignore1
-rw-r--r--.gitignore1
-rw-r--r--.gitlab-ci.yml1
-rw-r--r--CHANGELOG.md34
-rw-r--r--CONTRIBUTING.md18
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--GITLAB_SHELL_VERSION3
-rw-r--r--Gemfile8
-rw-r--r--Gemfile.lock68
-rw-r--r--PROCESS.md5
-rw-r--r--app/assets/images/icons.json2
-rw-r--r--app/assets/images/icons.svg2
-rw-r--r--app/assets/images/sprite.symbol.html3297
-rw-r--r--app/assets/javascripts/build.js2
-rw-r--r--app/assets/javascripts/copy_as_gfm.js61
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_code_component.vue4
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_component.vue4
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue34
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_review_component.vue4
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue4
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_test_component.vue34
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js6
-rw-r--r--app/assets/javascripts/diff.js15
-rw-r--r--app/assets/javascripts/dispatcher.js5
-rw-r--r--app/assets/javascripts/gl_dropdown.js1
-rw-r--r--app/assets/javascripts/issuable_context.js5
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js27
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js4
-rw-r--r--app/assets/javascripts/locale/index.js21
-rw-r--r--app/assets/javascripts/locale/sprintf.js26
-rw-r--r--app/assets/javascripts/main.js1
-rw-r--r--app/assets/javascripts/merge_request.js15
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue8
-rw-r--r--app/assets/javascripts/monitoring/components/empty_state.vue42
-rw-r--r--app/assets/javascripts/monitoring/components/graph.vue40
-rw-r--r--app/assets/javascripts/monitoring/components/graph/flag.vue5
-rw-r--r--app/assets/javascripts/monitoring/mixins/monitoring_mixins.js22
-rw-r--r--app/assets/javascripts/monitoring/monitoring_bundle.js5
-rw-r--r--app/assets/javascripts/monitoring/stores/monitoring_store.js2
-rw-r--r--app/assets/javascripts/monitoring/utils/date_time_formatters.js1
-rw-r--r--app/assets/javascripts/notebook/cells/code.vue30
-rw-r--r--app/assets/javascripts/notebook/cells/code/index.vue28
-rw-r--r--app/assets/javascripts/notebook/cells/markdown.vue14
-rw-r--r--app/assets/javascripts/notebook/cells/output/html.vue14
-rw-r--r--app/assets/javascripts/notebook/cells/output/image.vue16
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue18
-rw-r--r--app/assets/javascripts/notebook/cells/prompt.vue16
-rw-r--r--app/assets/javascripts/notebook/index.vue22
-rw-r--r--app/assets/javascripts/notes/components/issue_comment_form.vue1
-rw-r--r--app/assets/javascripts/notes/components/issue_note.vue2
-rw-r--r--app/assets/javascripts/pdf/index.vue20
-rw-r--r--app/assets/javascripts/pdf/page/index.vue14
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue4
-rw-r--r--app/assets/javascripts/project_fork.js18
-rw-r--r--app/assets/javascripts/projects_dropdown/service/projects_service.js2
-rw-r--r--app/assets/javascripts/registry/components/app.vue62
-rw-r--r--app/assets/javascripts/registry/components/collapsible_container.vue131
-rw-r--r--app/assets/javascripts/registry/components/table_registry.vue137
-rw-r--r--app/assets/javascripts/registry/constants.js15
-rw-r--r--app/assets/javascripts/registry/index.js25
-rw-r--r--app/assets/javascripts/registry/stores/actions.js39
-rw-r--r--app/assets/javascripts/registry/stores/getters.js2
-rw-r--r--app/assets/javascripts/registry/stores/index.js39
-rw-r--r--app/assets/javascripts/registry/stores/mutation_types.js7
-rw-r--r--app/assets/javascripts/registry/stores/mutations.js54
-rw-r--r--app/assets/javascripts/repo/components/repo_commit_section.vue4
-rw-r--r--app/assets/javascripts/repo/components/repo_edit_button.vue10
-rw-r--r--app/assets/javascripts/repo/components/repo_file.vue2
-rw-r--r--app/assets/javascripts/repo/components/repo_sidebar.vue4
-rw-r--r--app/assets/javascripts/repo/helpers/repo_helper.js10
-rw-r--r--app/assets/javascripts/repo/index.js4
-rw-r--r--app/assets/javascripts/repo/stores/repo_store.js3
-rw-r--r--app/assets/javascripts/right_sidebar.js44
-rw-r--r--app/assets/javascripts/search_autocomplete.js1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js48
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js41
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js26
-rw-r--r--app/assets/javascripts/vue_shared/components/clipboard_button.vue32
-rw-r--r--app/assets/javascripts/vue_shared/translate.js2
-rw-r--r--app/assets/stylesheets/framework/avatar.scss2
-rw-r--r--app/assets/stylesheets/framework/common.scss6
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss11
-rw-r--r--app/assets/stylesheets/framework/gfm.scss11
-rw-r--r--app/assets/stylesheets/framework/gitlab-theme.scss6
-rw-r--r--app/assets/stylesheets/framework/header.scss9
-rw-r--r--app/assets/stylesheets/framework/images.scss2
-rw-r--r--app/assets/stylesheets/framework/lists.scss4
-rw-r--r--app/assets/stylesheets/framework/new-nav.scss17
-rw-r--r--app/assets/stylesheets/framework/new-sidebar.scss40
-rw-r--r--app/assets/stylesheets/framework/selects.scss145
-rw-r--r--app/assets/stylesheets/framework/variables.scss4
-rw-r--r--app/assets/stylesheets/pages/container_registry.scss8
-rw-r--r--app/assets/stylesheets/pages/diff.scss12
-rw-r--r--app/assets/stylesheets/pages/environments.scss9
-rw-r--r--app/assets/stylesheets/pages/note_form.scss2
-rw-r--r--app/assets/stylesheets/pages/projects.scss90
-rw-r--r--app/assets/stylesheets/pages/search.scss10
-rw-r--r--app/assets/stylesheets/pages/settings_ci_cd.scss4
-rw-r--r--app/controllers/application_controller.rb22
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb2
-rw-r--r--app/controllers/concerns/notes_actions.rb2
-rw-r--r--app/controllers/confirmations_controller.rb1
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb2
-rw-r--r--app/controllers/projects/blob_controller.rb2
-rw-r--r--app/controllers/projects/branches_controller.rb2
-rw-r--r--app/controllers/projects/git_http_client_controller.rb1
-rw-r--r--app/controllers/projects/issues_controller.rb10
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb21
-rw-r--r--app/controllers/projects/registry/tags_controller.rb27
-rw-r--r--app/controllers/projects/tree_controller.rb2
-rw-r--r--app/controllers/projects/wikis_controller.rb16
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/controllers/registrations_controller.rb4
-rw-r--r--app/controllers/sessions_controller.rb18
-rw-r--r--app/helpers/breadcrumbs_helper.rb8
-rw-r--r--app/helpers/diff_helper.rb16
-rw-r--r--app/helpers/events_helper.rb20
-rw-r--r--app/helpers/icons_helper.rb4
-rw-r--r--app/helpers/page_layout_helper.rb2
-rw-r--r--app/helpers/projects_helper.rb7
-rw-r--r--app/models/ci/build.rb4
-rw-r--r--app/models/gpg_key.rb2
-rw-r--r--app/models/key.rb1
-rw-r--r--app/models/merge_request.rb35
-rw-r--r--app/models/personal_access_token.rb6
-rw-r--r--app/models/project.rb54
-rw-r--r--app/models/project_wiki.rb59
-rw-r--r--app/models/repository.rb39
-rw-r--r--app/models/user.rb12
-rw-r--r--app/models/wiki_page.rb10
-rw-r--r--app/policies/global_policy.rb6
-rw-r--r--app/policies/namespace_policy.rb4
-rw-r--r--app/presenters/merge_request_presenter.rb2
-rw-r--r--app/serializers/commit_entity.rb2
-rw-r--r--app/serializers/container_repositories_serializer.rb3
-rw-r--r--app/serializers/container_repository_entity.rb25
-rw-r--r--app/serializers/container_tag_entity.rb23
-rw-r--r--app/serializers/container_tags_serializer.rb17
-rw-r--r--app/serializers/merge_request_entity.rb7
-rw-r--r--app/services/merge_requests/ff_merge_service.rb24
-rw-r--r--app/services/merge_requests/merge_service.rb5
-rw-r--r--app/services/tags/create_service.rb2
-rw-r--r--app/views/layouts/_head.html.haml2
-rw-r--r--app/views/layouts/_search.html.haml4
-rw-r--r--app/views/layouts/header/_default.html.haml20
-rw-r--r--app/views/layouts/header/_new_dropdown.haml4
-rw-r--r--app/views/layouts/nav/_breadcrumbs.html.haml2
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml6
-rw-r--r--app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml3
-rw-r--r--app/views/layouts/nav/sidebar/_profile.html.haml2
-rw-r--r--app/views/projects/_merge_request_fast_forward_settings.html.haml13
-rw-r--r--app/views/projects/_merge_request_rebase_settings.html.haml13
-rw-r--r--app/views/projects/_merge_request_settings.html.haml15
-rw-r--r--app/views/projects/blob/diff.html.haml31
-rw-r--r--app/views/projects/buttons/_fork.html.haml9
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml16
-rw-r--r--app/views/projects/forks/new.html.haml74
-rw-r--r--app/views/projects/issues/_merge_requests.html.haml4
-rw-r--r--app/views/projects/issues/edit.html.haml7
-rw-r--r--app/views/projects/merge_requests/_mr_title.html.haml2
-rw-r--r--app/views/projects/notes/_actions.html.haml2
-rw-r--r--app/views/projects/registry/repositories/_image.html.haml32
-rw-r--r--app/views/projects/registry/repositories/index.html.haml93
-rw-r--r--app/views/projects/services/_form.html.haml2
-rw-r--r--app/views/projects/tags/_tag.html.haml7
-rw-r--r--app/views/projects/tree/_old_tree_content.html.haml2
-rw-r--r--app/views/projects/tree/_tree_header.html.haml4
-rw-r--r--app/views/projects/tree/show.html.haml2
-rw-r--r--app/views/projects/wikis/_form.html.haml22
-rw-r--r--app/views/projects/wikis/_main_links.html.haml6
-rw-r--r--app/views/projects/wikis/_new.html.haml11
-rw-r--r--app/views/projects/wikis/_pages_wiki_page.html.haml2
-rw-r--r--app/views/projects/wikis/_sidebar.html.haml4
-rw-r--r--app/views/projects/wikis/edit.html.haml19
-rw-r--r--app/views/projects/wikis/empty.html.haml6
-rw-r--r--app/views/projects/wikis/git_access.html.haml14
-rw-r--r--app/views/projects/wikis/history.html.haml18
-rw-r--r--app/views/projects/wikis/pages.html.haml8
-rw-r--r--app/views/projects/wikis/show.html.haml14
-rw-r--r--app/views/shared/_personal_access_tokens_form.html.haml4
-rw-r--r--app/views/shared/_sidebar_toggle_button.html.haml6
-rw-r--r--app/views/shared/_target_switcher.html.haml16
-rw-r--r--app/views/shared/issuable/_participants.html.haml2
-rw-r--r--app/views/shared/notes/_comment_button.html.haml2
-rw-r--r--changelogs/unreleased/12673-fix_v3_project_hooks_build_events4
-rw-r--r--changelogs/unreleased/12892-reset-css-text-align-to-initial-for-rtl.md4
-rw-r--r--changelogs/unreleased/13711-allow-same-period-housekeeping.yml2
-rw-r--r--changelogs/unreleased/14553-missing-space-in-log-msg.yml5
-rw-r--r--changelogs/unreleased/22619-add-an-email-address-to-unsubscribe-list-header-in-email4
-rw-r--r--changelogs/unreleased/26890-fix-default-branches-sorting.yml5
-rw-r--r--changelogs/unreleased/26908-make-timelogs-use-foreign-keys4
-rw-r--r--changelogs/unreleased/32340-correct-jobs-api-documentation4
-rw-r--r--changelogs/unreleased/33493-attempt-to-link-saml-users-to-ldap-by-email.yml5
-rw-r--r--changelogs/unreleased/34366-issue-sidebar-don-t-render-participants-in-collapsed-state.yml5
-rw-r--r--changelogs/unreleased/35942-api-binary-encoding.yaml3
-rw-r--r--changelogs/unreleased/3612-update-script-template-order-in-vue-files.yml5
-rw-r--r--changelogs/unreleased/36631-activerecord-statementinvalid-pg-querycanceled-error-canceling-statement-due-to-statement-timeout.yml6
-rw-r--r--changelogs/unreleased/36670-remove-edit-form.yml5
-rw-r--r--changelogs/unreleased/36742-hide-close-mr-button-on-merge.yml5
-rw-r--r--changelogs/unreleased/36953-add-gitLab-pages-version-to-admin-dashboard.yml2
-rw-r--r--changelogs/unreleased/37229-mr-widget-status-icon.yml5
-rw-r--r--changelogs/unreleased/37335-counter-active-state.yml5
-rw-r--r--changelogs/unreleased/37467-helper-method-from-users-endpoint-overrides-api-helper-method.yml5
-rw-r--r--changelogs/unreleased/37970-timestamped-ci.yml5
-rw-r--r--changelogs/unreleased/38036-hover-and-legend-data-should-be-linked.yml5
-rw-r--r--changelogs/unreleased/38052-use-simple-api-for-projects.yml5
-rw-r--r--changelogs/unreleased/38187-38315-fix-dropdown-open-top-bottom-spacing.yml5
-rw-r--r--changelogs/unreleased/38202-cannot-rename-a-hashed-project.yml6
-rw-r--r--changelogs/unreleased/38319-nomethoderror-undefined-method-sha-for-nil-nilclass.yml5
-rw-r--r--changelogs/unreleased/38417-use-explicit-boolean-vue-attribute.yml5
-rw-r--r--changelogs/unreleased/38432-fix-notes-type-for-import.yml6
-rw-r--r--changelogs/unreleased/38476-improve-merge-jid-cleanup-on-merge-process.yml5
-rw-r--r--changelogs/unreleased/38502-fix-nav-dropdown-close-animation.yml5
-rw-r--r--changelogs/unreleased/38571-fix-exception-in-raven-report.yml6
-rw-r--r--changelogs/unreleased/38619-fix-comment-delete-confirm-text.yml5
-rw-r--r--changelogs/unreleased/38635-fix-gitlab-check-git-ssh-config.yml5
-rw-r--r--changelogs/unreleased/38789-prometheus-graphs-occasionally-have-incorrect-y-scale.yml5
-rw-r--r--changelogs/unreleased/add-ci-builds-index-for-jobscontroller.yml5
-rw-r--r--changelogs/unreleased/add-composite-index-on-merge-requests-merge-commit-sha.yml5
-rw-r--r--changelogs/unreleased/add-labels-template-index.yml5
-rw-r--r--changelogs/unreleased/add-mock-deployment-and-monitoring-service-for-development.yaml4
-rw-r--r--changelogs/unreleased/breadcrumb-item-links.yml5
-rw-r--r--changelogs/unreleased/bvl-fix-close-issuable-link.yml5
-rw-r--r--changelogs/unreleased/close-issue-by-implements.yml5
-rw-r--r--changelogs/unreleased/commit-row-avatar-align-top.yml5
-rw-r--r--changelogs/unreleased/commit-side-by-side-comment.yml5
-rw-r--r--changelogs/unreleased/dm-api-unauthorized.yml5
-rw-r--r--changelogs/unreleased/dm-copy-parallel-diff.yml5
-rw-r--r--changelogs/unreleased/dm-pat-revoke.yml5
-rw-r--r--changelogs/unreleased/docs-add-summary-about-project-archiving.yml5
-rw-r--r--changelogs/unreleased/docs-openid-connect.yml5
-rw-r--r--changelogs/unreleased/ff_port_from_ee.yml5
-rw-r--r--changelogs/unreleased/fix-edit-project-service-cancel-button-position.yml5
-rw-r--r--changelogs/unreleased/fix-gpg-case-insensitive.yml5
-rw-r--r--changelogs/unreleased/fix-mr-sidebar-counter-after-merge.yml5
-rw-r--r--changelogs/unreleased/gem-sm-bump-google-api-client-gem-from-0-8-6-to-0-13-6.yml5
-rw-r--r--changelogs/unreleased/hash-mr-scroll-load.yml5
-rw-r--r--changelogs/unreleased/lint-changelog-yaml.yml5
-rw-r--r--changelogs/unreleased/mentions-in-comments.yml5
-rw-r--r--changelogs/unreleased/merge-request-notes-performance.yml5
-rw-r--r--changelogs/unreleased/mr-widget-merged-date-tooltip.yml5
-rw-r--r--changelogs/unreleased/rd-fix-case-sensative-email-conf-signup.yml5
-rw-r--r--changelogs/unreleased/remote_user.yml4
-rw-r--r--changelogs/unreleased/remove_repo_prefix_from_api.yml5
-rw-r--r--changelogs/unreleased/repository-name-emojis4
-rw-r--r--changelogs/unreleased/sh-fix-username-logging.yml5
-rw-r--r--changelogs/unreleased/sh-thread-safe-markdown.yml5
-rw-r--r--changelogs/unreleased/tag-link-size.yml5
-rw-r--r--changelogs/unreleased/update-pages-0-6.yml5
-rw-r--r--changelogs/unreleased/winh-sprintf.yml5
-rw-r--r--changelogs/unreleased/zj-repo-gitaly.yml5
-rw-r--r--config/application.rb1
-rw-r--r--config/environments/test.rb2
-rw-r--r--config/gitlab.yml.example6
-rw-r--r--config/initializers/1_settings.rb2
-rw-r--r--config/initializers/devise.rb2
-rw-r--r--config/initializers/gettext_rails_i18n_patch.rb14
-rw-r--r--config/initializers/grpc.rb11
-rw-r--r--config/routes/project.rb2
-rw-r--r--config/webpack.config.js8
-rw-r--r--db/migrate/20141126120926_add_merge_request_rebase_enabled_to_projects.rb17
-rw-r--r--db/migrate/20150827121444_add_fast_forward_option_to_project.rb19
-rw-r--r--db/migrate/20170927095921_add_ci_builds_index_for_jobscontroller.rb39
-rw-r--r--db/migrate/20170927122209_add_partial_index_for_labels_template.rb45
-rw-r--r--db/migrate/20170928100231_add_composite_index_on_merge_requests_merge_commit_sha.rb33
-rw-r--r--db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb25
-rw-r--r--db/post_migrate/20170926150348_schedule_merge_request_diff_migrations_take_two.rb32
-rw-r--r--db/post_migrate/20170927112318_update_legacy_diff_notes_type_for_import.rb16
-rw-r--r--db/post_migrate/20170927112319_update_notes_type_for_import.rb16
-rw-r--r--db/schema.rb8
-rw-r--r--doc/administration/gitaly/index.md8
-rw-r--r--doc/administration/job_artifacts.md6
-rw-r--r--doc/api/merge_requests.md9
-rw-r--r--doc/ci/enable_or_disable_ci.md39
-rw-r--r--doc/ci/environments.md15
-rw-r--r--doc/ci/img/builds_tab.pngbin1956 -> 0 bytes
-rw-r--r--doc/ci/img/deployments_view.pngbin19923 -> 61088 bytes
-rw-r--r--doc/ci/img/environments_available.pngbin0 -> 21089 bytes
-rw-r--r--doc/ci/img/environments_available_staging.pngbin10098 -> 0 bytes
-rw-r--r--doc/ci/img/environments_dynamic_groups.pngbin45349 -> 58239 bytes
-rw-r--r--doc/ci/img/environments_link_url.pngbin12277 -> 0 bytes
-rw-r--r--doc/ci/img/environments_link_url_deployments.pngbin7490 -> 0 bytes
-rw-r--r--doc/ci/img/environments_link_url_mr.pngbin17947 -> 34361 bytes
-rw-r--r--doc/ci/img/environments_manual_action_builds.pngbin11137 -> 0 bytes
-rw-r--r--doc/ci/img/environments_manual_action_deployments.pngbin12563 -> 32748 bytes
-rw-r--r--doc/ci/img/environments_manual_action_environments.pngbin14914 -> 24191 bytes
-rw-r--r--doc/ci/img/environments_manual_action_jobs.pngbin0 -> 19919 bytes
-rw-r--r--doc/ci/img/environments_manual_action_pipelines.pngbin16243 -> 38974 bytes
-rw-r--r--doc/ci/img/environments_manual_action_single_pipeline.pngbin16576 -> 23381 bytes
-rw-r--r--doc/ci/img/environments_mr_review_app.pngbin15366 -> 30991 bytes
-rw-r--r--doc/ci/img/environments_terminal_button_on_index.pngbin79725 -> 29162 bytes
-rw-r--r--doc/ci/img/environments_terminal_button_on_show.pngbin73210 -> 17811 bytes
-rw-r--r--doc/ci/img/environments_view.pngbin21155 -> 0 bytes
-rw-r--r--doc/ci/img/permissions_settings.pngbin39194 -> 0 bytes
-rw-r--r--doc/ci/img/prometheus_environment_detail_with_metrics.pngbin120479 -> 0 bytes
-rw-r--r--doc/ci/variables/README.md23
-rw-r--r--doc/ci/variables/img/secret_variables.pngbin0 -> 15658 bytes
-rw-r--r--doc/development/fe_guide/style_guide_js.md21
-rw-r--r--doc/development/fe_guide/vue.md2
-rw-r--r--doc/development/gitaly.md32
-rw-r--r--doc/development/i18n_guide.md11
-rw-r--r--doc/development/testing.md2
-rw-r--r--doc/development/ux_guide/animation.md10
-rw-r--r--doc/development/ux_guide/components.md19
-rw-r--r--doc/development/ux_guide/illustrations.md86
-rwxr-xr-xdoc/development/ux_guide/img/illustration-size-large-horizontal.pngbin0 -> 55272 bytes
-rw-r--r--doc/development/ux_guide/img/illustration-size-large-vertical.pngbin0 -> 59217 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustration-size-medium.pngbin0 -> 20994 bytes
-rw-r--r--doc/development/ux_guide/img/illustration-size-small.pngbin0 -> 43536 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-border-radius.pngbin0 -> 7779 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-caps-do.pngbin0 -> 3775 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-caps-don't.pngbin0 -> 3922 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-color-grey.pngbin0 -> 251 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-color-orange.pngbin0 -> 275 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-color-purple.pngbin0 -> 275 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-geometric.pngbin0 -> 5057 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-palette-oragne.pngbin0 -> 10439 bytes
-rwxr-xr-xdoc/development/ux_guide/img/illustrations-palette-purple.pngbin0 -> 10002 bytes
-rw-r--r--doc/development/ux_guide/img/skeleton-loading.gifbin0 -> 1093917 bytes
-rw-r--r--doc/development/ux_guide/index.md5
-rw-r--r--doc/install/kubernetes/gitlab_chart.md9
-rw-r--r--doc/install/kubernetes/index.md18
-rw-r--r--doc/topics/authentication/index.md1
-rw-r--r--doc/topics/autodevops/index.md2
-rw-r--r--doc/user/admin_area/monitoring/health_check.md2
-rw-r--r--doc/user/project/container_registry.md22
-rw-r--r--doc/user/project/img/container_registry.pngbin0 -> 35202 bytes
-rw-r--r--doc/user/project/img/container_registry_enable.pngbin3057 -> 0 bytes
-rw-r--r--doc/user/project/img/container_registry_tab.pngbin3800 -> 0 bytes
-rw-r--r--doc/user/project/img/issue_board.pngbin51439 -> 82592 bytes
-rw-r--r--doc/user/project/img/issue_board_move_issue_card_list.pngbin74826 -> 36747 bytes
-rw-r--r--doc/user/project/img/labels_assign_label_in_new_issue.pngbin11636 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_default.pngbin32030 -> 24404 bytes
-rw-r--r--doc/user/project/img/labels_filter.pngbin31931 -> 19071 bytes
-rw-r--r--doc/user/project/img/labels_filter_by_priority.pngbin23969 -> 38717 bytes
-rw-r--r--doc/user/project/img/labels_new_label.pngbin16787 -> 10720 bytes
-rw-r--r--doc/user/project/img/labels_prioritize.pngbin38185 -> 24194 bytes
-rw-r--r--doc/user/project/img/project_repository_settings.pngbin35236 -> 17872 bytes
-rw-r--r--doc/user/project/issue_board.md6
-rw-r--r--doc/user/project/issues/img/button_close_issue.pngbin15508 -> 12274 bytes
-rw-r--r--doc/user/project/issues/img/group_issues_list_view.pngbin265130 -> 127781 bytes
-rw-r--r--doc/user/project/issues/img/issue_board.pngbin58645 -> 56253 bytes
-rw-r--r--doc/user/project/issues/img/issue_template.pngbin28061 -> 25022 bytes
-rw-r--r--doc/user/project/issues/img/issues_main_view.pngbin73751 -> 72540 bytes
-rw-r--r--doc/user/project/issues/img/issues_main_view_numbered.jpgbin103249 -> 205803 bytes
-rw-r--r--doc/user/project/issues/img/new_issue.pngbin31727 -> 28734 bytes
-rw-r--r--doc/user/project/issues/img/new_issue_from_issue_board.pngbin137175 -> 57427 bytes
-rw-r--r--doc/user/project/issues/img/new_issue_from_open_issue.pngbin20628 -> 13346 bytes
-rw-r--r--doc/user/project/issues/img/new_issue_from_projects_dashboard.pngbin29865 -> 23685 bytes
-rw-r--r--doc/user/project/issues/img/new_issue_from_tracker_list.pngbin24345 -> 19632 bytes
-rw-r--r--doc/user/project/issues/img/project_issues_list_view.pngbin309131 -> 196071 bytes
-rw-r--r--doc/user/project/issues/img/sidebar_move_issue.pngbin54511 -> 50132 bytes
-rw-r--r--doc/user/project/labels.md45
-rw-r--r--doc/user/project/merge_requests/cherry_pick_changes.md31
-rw-r--r--doc/user/project/merge_requests/fast_forward_merge.md35
-rw-r--r--doc/user/project/merge_requests/img/cherry_pick_changes_commit.pngbin141744 -> 13604 bytes
-rw-r--r--doc/user/project/merge_requests/img/cherry_pick_changes_commit_modal.pngbin111488 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/cherry_pick_changes_mr.pngbin93870 -> 16494 bytes
-rw-r--r--doc/user/project/merge_requests/img/cherry_pick_changes_mr_modal.pngbin86650 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/commit_compare.pngbin33385 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/ff_merge_mr.pngbin0 -> 21380 bytes
-rw-r--r--doc/user/project/merge_requests/img/ff_merge_rebase_locally.pngbin0 -> 21013 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_request.pngbin0 -> 67228 bytes
-rw-r--r--doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.pngbin60346 -> 22791 bytes
-rw-r--r--doc/user/project/merge_requests/img/revert_changes_commit_modal.pngbin88824 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/revert_changes_mr_modal.pngbin93536 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/versions.pngbin55703 -> 23629 bytes
-rw-r--r--doc/user/project/merge_requests/img/versions_compare.pngbin24886 -> 17228 bytes
-rw-r--r--doc/user/project/merge_requests/img/versions_dropdown.pngbin21547 -> 13887 bytes
-rw-r--r--doc/user/project/merge_requests/img/wip_blocked_accept_button.pngbin18606 -> 8071 bytes
-rw-r--r--doc/user/project/merge_requests/img/wip_mark_as_wip.pngbin11396 -> 17081 bytes
-rw-r--r--doc/user/project/merge_requests/img/wip_unmark_as_wip.pngbin8565 -> 18585 bytes
-rw-r--r--doc/user/project/merge_requests/index.md24
-rw-r--r--doc/user/project/merge_requests/revert_changes.md44
-rw-r--r--doc/user/project/settings/index.md10
-rw-r--r--doc/workflow/README.md1
-rw-r--r--features/project/ff_merge_requests.feature24
-rw-r--r--features/steps/project/ff_merge_requests.rb65
-rw-r--r--features/steps/project/fork.rb2
-rw-r--r--features/steps/shared/diff_note.rb2
-rw-r--r--lib/api/branches.rb20
-rw-r--r--lib/api/commits.rb18
-rw-r--r--lib/api/entities.rb44
-rw-r--r--lib/api/helpers.rb8
-rw-r--r--lib/api/internal.rb7
-rw-r--r--lib/api/merge_requests.rb4
-rw-r--r--lib/api/repositories.rb4
-rw-r--r--lib/api/tags.rb12
-rw-r--r--lib/api/templates.rb8
-rw-r--r--lib/api/v3/branches.rb8
-rw-r--r--lib/api/v3/commits.rb16
-rw-r--r--lib/api/v3/entities.rb4
-rw-r--r--lib/api/v3/merge_requests.rb4
-rw-r--r--lib/api/v3/repositories.rb4
-rw-r--r--lib/api/v3/tags.rb4
-rw-r--r--lib/api/v3/templates.rb8
-rw-r--r--lib/backup/repository.rb2
-rw-r--r--lib/banzai/filter/markdown_filter.rb32
-rw-r--r--lib/banzai/filter/sanitization_filter.rb3
-rw-r--r--lib/github/import.rb41
-rw-r--r--lib/github/import/issue.rb13
-rw-r--r--lib/github/import/legacy_diff_note.rb12
-rw-r--r--lib/github/import/merge_request.rb13
-rw-r--r--lib/github/import/note.rb13
-rw-r--r--lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb32
-rw-r--r--lib/gitlab/bare_repository_importer.rb3
-rw-r--r--lib/gitlab/ci/ansi2html.rb13
-rw-r--r--lib/gitlab/git/diff.rb46
-rw-r--r--lib/gitlab/git/hook.rb17
-rw-r--r--lib/gitlab/git/hooks_service.rb15
-rw-r--r--lib/gitlab/git/operation_service.rb4
-rw-r--r--lib/gitlab/git/repository.rb205
-rw-r--r--lib/gitlab/git/rev_list.rb2
-rw-r--r--lib/gitlab/git/user.rb12
-rw-r--r--lib/gitlab/git/wiki.rb115
-rw-r--r--lib/gitlab/git/wiki_file.rb19
-rw-r--r--lib/gitlab/git/wiki_page.rb39
-rw-r--r--lib/gitlab/git/wiki_page_version.rb19
-rw-r--r--lib/gitlab/gitaly_client.rb4
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb2
-rw-r--r--lib/gitlab/gitaly_client/operation_service.rb79
-rw-r--r--lib/gitlab/gitaly_client/ref_service.rb22
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb5
-rw-r--r--lib/gitlab/gitaly_client/util.rb27
-rw-r--r--lib/gitlab/kubernetes.rb2
-rw-r--r--lib/gitlab/ldap/adapter.rb22
-rw-r--r--lib/gitlab/ldap/person.rb6
-rw-r--r--lib/gitlab/ldap/user.rb26
-rw-r--r--lib/gitlab/o_auth/user.rb68
-rw-r--r--lib/gitlab/saml/user.rb37
-rw-r--r--lib/gitlab/shell.rb16
-rw-r--r--lib/gitlab/sidekiq_middleware/memory_killer.rb2
-rw-r--r--lib/gitlab/sql/union.rb9
-rw-r--r--lib/gitlab/url_sanitizer.rb8
-rw-r--r--lib/gitlab/workhorse.rb9
-rw-r--r--lib/system_check/app/git_user_default_ssh_config_check.rb1
-rw-r--r--lib/tasks/gitlab/assets.rake2
-rw-r--r--lib/tasks/gitlab/shell.rake2
-rw-r--r--locale/bg/gitlab.po334
-rw-r--r--locale/de/gitlab.po392
-rw-r--r--locale/en/gitlab.po2
-rw-r--r--locale/eo/gitlab.po334
-rw-r--r--locale/es/gitlab.po334
-rw-r--r--locale/fr/gitlab.po508
-rw-r--r--locale/gitlab.pot148
-rw-r--r--locale/it/gitlab.po334
-rw-r--r--locale/ja/gitlab.po334
-rw-r--r--locale/ko/gitlab.po334
-rw-r--r--locale/nl_NL/gitlab.po428
-rw-r--r--locale/pt_BR/gitlab.po334
-rw-r--r--locale/ru/gitlab.po470
-rw-r--r--locale/uk/gitlab.po474
-rw-r--r--locale/zh_CN/gitlab.po396
-rw-r--r--locale/zh_HK/gitlab.po334
-rw-r--r--locale/zh_TW/gitlab.po356
-rw-r--r--qa/Gemfile1
-rw-r--r--qa/Gemfile.lock25
-rw-r--r--qa/README.md19
-rw-r--r--qa/qa/page/admin/menu.rb11
-rw-r--r--qa/qa/page/project/show.rb4
-rw-r--r--qa/qa/specs/config.rb3
-rwxr-xr-xscripts/lint-changelog-yaml22
-rwxr-xr-xscripts/static-analysis3
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb319
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb2
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb14
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb34
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb2
-rw-r--r--spec/controllers/projects/registry/repositories_controller_spec.rb44
-rw-r--r--spec/controllers/projects/registry/tags_controller_spec.rb90
-rw-r--r--spec/controllers/projects_controller_spec.rb18
-rw-r--r--spec/factories/deployments.rb2
-rw-r--r--spec/factories/gitaly/commit.rb17
-rw-r--r--spec/factories/gitaly/commit_author.rb9
-rw-r--r--spec/features/container_registry_spec.rb9
-rw-r--r--spec/features/copy_as_gfm_spec.rb128
-rw-r--r--spec/features/issues/form_spec.rb49
-rw-r--r--spec/features/issues_spec.rb110
-rw-r--r--spec/features/merge_requests/diff_notes_avatars_spec.rb22
-rw-r--r--spec/features/merge_requests/widget_spec.rb22
-rw-r--r--spec/features/projects/branches/download_buttons_spec.rb2
-rw-r--r--spec/features/projects/branches_spec.rb96
-rw-r--r--spec/features/projects/fork_spec.rb57
-rw-r--r--spec/features/projects/issuable_templates_spec.rb46
-rw-r--r--spec/features/projects/project_settings_spec.rb26
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb2
-rw-r--r--spec/features/projects/wiki/user_views_wiki_page_spec.rb6
-rw-r--r--spec/features/protected_branches_spec.rb184
-rw-r--r--spec/features/security/project/internal_access_spec.rb15
-rw-r--r--spec/features/security/project/private_access_spec.rb15
-rw-r--r--spec/features/security/project/public_access_spec.rb15
-rw-r--r--spec/features/signup_spec.rb18
-rw-r--r--spec/features/tags/master_deletes_tag_spec.rb27
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request.json6
-rw-r--r--spec/fixtures/api/schemas/registry/repositories.json6
-rw-r--r--spec/fixtures/api/schemas/registry/repository.json27
-rw-r--r--spec/fixtures/api/schemas/registry/tag.json28
-rw-r--r--spec/fixtures/api/schemas/registry/tags.json6
-rw-r--r--spec/fixtures/config/kubeconfig.yml2
-rw-r--r--spec/helpers/groups_helper_spec.rb2
-rw-r--r--spec/helpers/page_layout_helper_spec.rb6
-rw-r--r--spec/helpers/projects_helper_spec.rb4
-rw-r--r--spec/javascripts/build_spec.js14
-rw-r--r--spec/javascripts/fixtures/merge_requests.rb6
-rw-r--r--spec/javascripts/helpers/vuex_action_helper.js (renamed from spec/javascripts/notes/stores/helpers.js)0
-rw-r--r--spec/javascripts/issuable_context_spec.js34
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js56
-rw-r--r--spec/javascripts/locale/sprintf_spec.js74
-rw-r--r--spec/javascripts/merge_request_spec.js39
-rw-r--r--spec/javascripts/monitoring/graph/flag_spec.js49
-rw-r--r--spec/javascripts/monitoring/graph_spec.js18
-rw-r--r--spec/javascripts/notes/components/issue_comment_form_spec.js40
-rw-r--r--spec/javascripts/notes/stores/actions_spec.js2
-rw-r--r--spec/javascripts/projects_dropdown/service/projects_service_spec.js2
-rw-r--r--spec/javascripts/registry/components/app_spec.js122
-rw-r--r--spec/javascripts/registry/components/collapsible_container_spec.js58
-rw-r--r--spec/javascripts/registry/components/table_registry_spec.js49
-rw-r--r--spec/javascripts/registry/getters_spec.js43
-rw-r--r--spec/javascripts/registry/mock_data.js122
-rw-r--r--spec/javascripts/registry/stores/actions_spec.js85
-rw-r--r--spec/javascripts/registry/stores/mutations_spec.js81
-rw-r--r--spec/javascripts/repo/components/repo_edit_button_spec.js2
-rw-r--r--spec/javascripts/repo/components/repo_file_spec.js12
-rw-r--r--spec/javascripts/repo/components/repo_sidebar_spec.js4
-rw-r--r--spec/javascripts/right_sidebar_spec.js116
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js36
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js113
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js15
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js151
-rw-r--r--spec/lib/github/import/legacy_diff_note_spec.rb9
-rw-r--r--spec/lib/github/import/note_spec.rb9
-rw-r--r--spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb122
-rw-r--r--spec/lib/gitlab/ci/ansi2html_spec.rb26
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb40
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb32
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb3
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb38
-rw-r--r--spec/lib/gitlab/git/hook_spec.rb8
-rw-r--r--spec/lib/gitlab/git/hooks_service_spec.rb2
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb79
-rw-r--r--spec/lib/gitlab/git/user_spec.rb32
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb2
-rw-r--r--spec/lib/gitlab/gitaly_client/operation_service_spec.rb92
-rw-r--r--spec/lib/gitlab/gitaly_client/util_spec.rb43
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb14
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml2
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb17
-rw-r--r--spec/lib/gitlab/path_regex_spec.rb7
-rw-r--r--spec/lib/gitlab/popen_spec.rb2
-rw-r--r--spec/lib/gitlab/saml/user_spec.rb97
-rw-r--r--spec/lib/gitlab/shell_spec.rb46
-rw-r--r--spec/lib/gitlab/sql/union_spec.rb7
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb25
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb63
-rw-r--r--spec/lib/system_check/app/git_user_default_ssh_config_check_spec.rb7
-rw-r--r--spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb59
-rw-r--r--spec/migrations/update_legacy_diff_notes_type_for_import_spec.rb22
-rw-r--r--spec/migrations/update_notes_type_for_import_spec.rb22
-rw-r--r--spec/models/gpg_key_spec.rb8
-rw-r--r--spec/models/key_spec.rb10
-rw-r--r--spec/models/merge_request_spec.rb43
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb2
-rw-r--r--spec/models/project_spec.rb29
-rw-r--r--spec/models/project_wiki_spec.rb64
-rw-r--r--spec/models/repository_spec.rb341
-rw-r--r--spec/models/wiki_page_spec.rb14
-rw-r--r--spec/policies/global_policy_spec.rb23
-rw-r--r--spec/policies/namespace_policy_spec.rb20
-rw-r--r--spec/presenters/merge_request_presenter_spec.rb4
-rw-r--r--spec/requests/api/helpers_spec.rb21
-rw-r--r--spec/requests/api/runner_spec.rb3
-rw-r--r--spec/serializers/build_serializer_spec.rb2
-rw-r--r--spec/serializers/container_repository_entity_spec.rb41
-rw-r--r--spec/serializers/container_tag_entity_spec.rb43
-rw-r--r--spec/serializers/merge_request_entity_spec.rb13
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb2
-rw-r--r--spec/serializers/status_entity_spec.rb4
-rw-r--r--spec/services/merge_requests/ff_merge_service_spec.rb84
-rw-r--r--spec/services/projects/create_service_spec.rb86
-rw-r--r--spec/services/projects/fork_service_spec.rb5
-rw-r--r--spec/services/projects/transfer_service_spec.rb7
-rw-r--r--spec/services/projects/update_service_spec.rb45
-rw-r--r--spec/services/tags/create_service_spec.rb2
-rw-r--r--spec/spec_helper.rb18
-rw-r--r--spec/support/stub_gitlab_calls.rb4
-rw-r--r--spec/support/test_env.rb1
-rw-r--r--spec/support/update_invalid_issuable.rb27
-rw-r--r--spec/views/projects/registry/repositories/index.html.haml_spec.rb36
-rw-r--r--spec/views/shared/issuable/_participants.html.haml.rb26
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb6
-rw-r--r--spec/workers/repository_check/single_repository_worker_spec.rb7
-rw-r--r--yarn.lock2
606 files changed, 12464 insertions, 7000 deletions
diff --git a/.flayignore b/.flayignore
index b63ce4c4df0..acac0ce14c9 100644
--- a/.flayignore
+++ b/.flayignore
@@ -5,3 +5,4 @@ app/policies/project_policy.rb
app/models/concerns/relative_positioning.rb
app/workers/stuck_merge_jobs_worker.rb
lib/gitlab/redis/*.rb
+lib/gitlab/gitaly_client/operation_service.rb
diff --git a/.gitignore b/.gitignore
index 3baf640a9c3..4933575332b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,4 +63,5 @@ eslint-report.html
/.gitlab_workhorse_secret
/webpack-report/
/locale/**/LC_MESSAGES
+/locale/**/*.time_stamp
/.rspec
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ed993abae73..8501911fde4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -404,6 +404,7 @@ docs lint:
before_script: []
script:
- scripts/lint-doc.sh
+ - scripts/lint-changelog-yaml
- mv doc/ /nanoc/content/
- cd /nanoc
# Build HTML from Markdown
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d08e42b3b65..efd32d44890 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,23 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 10.0.3 (2017-10-05)
+
+- [FIXED] find_user Users helper method no longer overrides find_user API helper method. !14418
+- [FIXED] Fix CSRF validation issue when closing/opening merge requests from the UI. !14555
+- [FIXED] Kubernetes integration: ensure v1.8.0 compatibility. !14635
+- [FIXED] Fixes data parameter not being sent in ajax request for jobs log.
+- [FIXED] Improves UX of autodevops popover to match gpg one.
+- [FIXED] Fixed commenting on side-by-side commit diff.
+- [FIXED] Make sure API responds with 401 when invalid authentication info is provided.
+- [FIXED] Fix merge request counter updates after merge.
+- [FIXED] Fix gitlab-rake gitlab:import:repos task failing.
+- [FIXED] Fix pushes to an empty repository not invalidating has_visible_content? cache.
+- [FIXED] Ensure all refs are restored on a restore from backup.
+- [FIXED] Gitaly RepositoryExists remains opt-in for all method calls.
+- [FIXED] Fix 500 error on merged merge requests when GitLab is restored from a backup.
+- [FIXED] Adjust MRs being stuck on "process of being merged" for more than 2 hours.
+
## 10.0.2 (2017-09-27)
- [FIXED] Notes will not show an empty bubble when the author isn't a member. !14450
@@ -85,6 +102,8 @@ entry.
- [FIXED] Fixed merge request changes bar jumping.
- [FIXED] Improve migrations using triggers.
- [FIXED] Fix ConvDev Index nav item and Monitoring submenu regression.
+- [FIXED] disabling notifications globally now properly turns off group/project added
+ emails !13325
- [DEPRECATED] Deprecate custom SSH client configuration for the git user. !13930
- [CHANGED] allow all users to delete their account. !13636 (Jacopo Beschi @jacopo-beschi)
- [CHANGED] Use full path of project's avatar in webhooks. !13649 (Vitaliy @blackst0ne Klachkov)
@@ -193,6 +212,21 @@ entry.
- Added type to CHANGELOG entries. (Jacopo Beschi @jacopo-beschi)
- [BUGIFX] Improves subgroup creation permissions. !13418
+## 9.5.8 (2017-10-04)
+
+- [FIXED] Fixed fork button being disabled for users who can fork to a group.
+
+## 9.5.7 (2017-10-03)
+
+- Fix gitlab rake:import:repos task.
+
+## 9.5.6 (2017-09-29)
+
+- [FIXED] Fix MR ready to merge buttons/controls at mobile breakpoint. !14242
+- [FIXED] Fix errors thrown in merge request widget with external CI service/integration.
+- [FIXED] Update x/x discussions resolved checkmark icon to be green when all discussions resolved.
+- [FIXED] Fix 500 error on merged merge requests when GitLab is restored from a backup.
+
## 9.5.5 (2017-09-18)
- [SECURITY] Upgrade mail and nokogiri gems due to security issues. !13662 (Markus Koller)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dfb2ce0099a..6b261bd5938 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -49,7 +49,7 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
Thank you for your interest in contributing to GitLab. This guide details how
to contribute to GitLab in a way that is efficient for everyone.
-Looking for something to work on? Look for the label [Accepting Merge Requests](#i-want-to-contribute).
+Looking for something to work on? Look for issues with the label [Accepting Merge Requests](#i-want-to-contribute).
GitLab comes into two flavors, GitLab Community Edition (CE) our free and open
source edition, and GitLab Enterprise Edition (EE) which is our commercial
@@ -101,7 +101,7 @@ the remaining issues on the GitHub issue tracker.
## I want to contribute!
If you want to contribute to GitLab, but are not sure where to start,
-look for [issues with the label `Accepting Merge Requests` and weight < 5][accepting-mrs-weight].
+look for [issues with the label `Accepting Merge Requests` and small weight][accepting-mrs-weight].
These issues will be of reasonable size and challenge, for anyone to start
contributing to GitLab.
@@ -209,8 +209,7 @@ We add the ~"Accepting Merge Requests" label to:
- Low priority ~bug issues (i.e. we do not add it to the bugs that we want to
solve in the ~"Next Patch Release")
-- Small ~"feature proposal" that do not need ~UX / ~"Product work", or for which
-the ~UX / ~"Product work" is already done
+- Small ~"feature proposal"
- Small ~"technical debt" issues
After adding the ~"Accepting Merge Requests" label, we try to estimate the
@@ -223,6 +222,17 @@ know how difficult the issue is. Additionally:
- We encourage people that have never contributed to any open source project to
look for ["Accepting Merge Requests" issues with a weight of 1][firt-timers]
+If you've decided that you would like to work on an issue, please @-mention
+the [appropriate product manager](https://about.gitlab.com/handbook/product/#who-to-talk-to-for-what)
+as soon as possible. The product manager will then pull in appropriate GitLab team
+members to further discuss scope, design, and technical considerations. This will
+ensure that that your contribution is aligned with the GitLab product and minimize
+any rework and delay in getting it merged into master.
+
+GitLab team members who apply the ~"Accepting Merge Requests" label to an issue
+should update the issue description with a responsible product manager, inviting
+any potential community contributor to @-mention per above.
+
[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=Accepting+Merge+Requests&scope=all&sort=weight_asc&state=opened
[firt-timers]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=Accepting+Merge+Requests&scope=all&sort=upvotes_desc&state=opened&weight=1
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 9b0025a7850..8298bb08b2d 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.40.0
+0.43.0
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 4b9fcbec101..a918a2aa18d 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-0.5.1
+0.6.0
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index da902181863..5508e17c23b 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1,2 @@
-5.9.2
+5.9.3
+
diff --git a/Gemfile b/Gemfile
index b58632d3542..44c459c497f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -105,7 +105,7 @@ gem 'fog-rackspace', '~> 0.1.1'
gem 'fog-aliyun', '~> 0.1.0'
# for Google storage
-gem 'google-api-client', '~> 0.8.6'
+gem 'google-api-client', '~> 0.13.6'
# for aws storage
gem 'unf', '~> 0.1.4'
@@ -239,7 +239,7 @@ gem 'rack-proxy', '~> 0.6.0'
gem 'sass-rails', '~> 5.0.6'
gem 'uglifier', '~> 2.7.2'
-gem 'addressable', '~> 2.3.8'
+gem 'addressable', '~> 2.5.2'
gem 'bootstrap-sass', '~> 3.3.0'
gem 'font-awesome-rails', '~> 4.7'
gem 'gemojione', '~> 3.3'
@@ -356,7 +356,7 @@ end
group :test do
gem 'shoulda-matchers', '~> 3.1.2', require: false
gem 'email_spec', '~> 1.6.0'
- gem 'json-schema', '~> 2.6.2'
+ gem 'json-schema', '~> 2.8.0'
gem 'webmock', '~> 2.3.2'
gem 'test_after_commit', '~> 1.1'
gem 'sham_rack', '~> 1.3.6'
@@ -398,7 +398,7 @@ group :ed25519 do
end
# Gitaly GRPC client
-gem 'gitaly-proto', '~> 0.33.0', require: 'gitaly'
+gem 'gitaly-proto', '~> 0.39.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 3313a687ff0..4622fd141ba 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -45,7 +45,8 @@ GEM
adamantium (0.2.0)
ice_nine (~> 0.11.0)
memoizable (~> 0.4.0)
- addressable (2.3.8)
+ addressable (2.5.2)
+ public_suffix (>= 2.0.2, < 4.0)
akismet (2.0.0)
allocations (1.0.5)
arel (6.0.4)
@@ -62,10 +63,6 @@ GEM
attr_encrypted (3.0.3)
encryptor (~> 3.0.0)
attr_required (1.0.0)
- autoparse (0.3.3)
- addressable (>= 2.3.1)
- extlib (>= 0.9.15)
- multi_json (>= 1.0.0)
autoprefixer-rails (6.2.3)
execjs
json
@@ -146,6 +143,8 @@ GEM
debugger-ruby_core_source (1.3.8)
deckar01-task_list (2.0.0)
html-pipeline
+ declarative (0.0.10)
+ declarative-option (0.1.0)
default_value_for (3.0.2)
activerecord (>= 3.2.0, < 5.1)
descendants_tracker (0.0.4)
@@ -188,7 +187,6 @@ GEM
excon (0.57.1)
execjs (2.6.0)
expression_parser (0.9.0)
- extlib (0.9.16)
factory_girl (4.7.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.7.0)
@@ -275,7 +273,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
- gitaly-proto (0.33.0)
+ gitaly-proto (0.39.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
@@ -288,10 +286,10 @@ GEM
flowdock (~> 0.7)
gitlab-grit (>= 2.4.1)
multi_json
- gitlab-grit (2.8.1)
+ gitlab-grit (2.8.2)
charlock_holmes (~> 0.6)
diff-lcs (~> 1.1)
- mime-types (>= 1.16, < 3)
+ mime-types (>= 1.16)
posix-spawn (~> 0.3)
gitlab-markup (1.6.2)
gitlab_omniauth-ldap (2.0.4)
@@ -319,20 +317,16 @@ GEM
json
multi_json
request_store (>= 1.0)
- google-api-client (0.8.7)
- activesupport (>= 3.2, < 5.0)
- addressable (~> 2.3)
- autoparse (~> 0.3)
- extlib (~> 0.9)
- faraday (~> 0.9)
- googleauth (~> 0.3)
- launchy (~> 2.4)
- multi_json (~> 1.10)
- retriable (~> 1.4)
- signet (~> 0.6)
+ google-api-client (0.13.6)
+ addressable (~> 2.5, >= 2.5.1)
+ googleauth (~> 0.5)
+ httpclient (>= 2.8.1, < 3.0)
+ mime-types (~> 3.0)
+ representable (~> 3.0)
+ retriable (>= 2.0, < 4.0)
google-protobuf (3.4.0.2)
- googleauth (0.5.1)
- faraday (~> 0.9)
+ googleauth (0.5.3)
+ faraday (~> 0.12)
jwt (~> 1.4)
logging (~> 2.0)
memoist (~> 0.12)
@@ -422,8 +416,8 @@ GEM
multi_json (>= 1.3)
securecompare
url_safe_base64
- json-schema (2.6.2)
- addressable (~> 2.3.8)
+ json-schema (2.8.0)
+ addressable (>= 2.4)
jwt (1.5.6)
kaminari (1.0.1)
activesupport (>= 4.1.0)
@@ -475,18 +469,20 @@ GEM
mail (2.6.6)
mime-types (>= 1.16, < 4)
mail_room (0.9.1)
- memoist (0.15.0)
+ memoist (0.16.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
method_source (0.8.2)
- mime-types (2.99.3)
+ mime-types (3.1)
+ mime-types-data (~> 3.2015)
+ mime-types-data (3.2016.0521)
mimemagic (0.3.0)
mini_mime (0.1.4)
mini_portile2 (2.3.0)
minitest (5.7.0)
mmap2 (2.2.7)
mousetrap-rails (1.4.6)
- multi_json (1.12.1)
+ multi_json (1.12.2)
multi_xml (0.6.0)
multipart-post (2.0.0)
mustermann (1.0.0)
@@ -635,6 +631,7 @@ GEM
pry (~> 0.10)
pry-rails (0.3.5)
pry (>= 0.9.10)
+ public_suffix (3.0.0)
pyu-ruby-sasl (0.0.3.3)
rack (1.6.8)
rack-accept (0.4.5)
@@ -717,6 +714,10 @@ GEM
redis-store (~> 1.2.0)
redis-store (1.2.0)
redis (>= 2.2)
+ representable (3.0.4)
+ declarative (< 0.1.0)
+ declarative-option (< 0.2.0)
+ uber (< 0.2.0)
request_store (1.3.1)
responders (2.3.0)
railties (>= 4.2.0, < 5.1)
@@ -724,7 +725,7 @@ GEM
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
- retriable (1.4.1)
+ retriable (3.1.1)
rinku (2.0.0)
rotp (2.1.2)
rouge (2.2.1)
@@ -903,12 +904,13 @@ GEM
tzinfo (1.2.3)
thread_safe (~> 0.1)
u2f (0.2.1)
+ uber (0.1.0)
uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
unf (0.1.4)
unf_ext
- unf_ext (0.0.7.2)
+ unf_ext (0.0.7.4)
unicode-display_width (1.3.0)
unicorn (5.1.0)
kgio (~> 2.6)
@@ -963,7 +965,7 @@ DEPENDENCIES
ace-rails-ap (~> 4.1.0)
activerecord_sane_schema_dumper (= 0.2)
acts-as-taggable-on (~> 4.0)
- addressable (~> 2.3.8)
+ addressable (~> 2.5.2)
akismet (~> 2.0)
allocations (~> 1.0)
asana (~> 0.6.0)
@@ -1025,7 +1027,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
- gitaly-proto (~> 0.33.0)
+ gitaly-proto (~> 0.39.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.6.2)
@@ -1033,7 +1035,7 @@ DEPENDENCIES
gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.4)
gon (~> 6.1.0)
- google-api-client (~> 0.8.6)
+ google-api-client (~> 0.13.6)
gpgme
grape (~> 1.0)
grape-entity (~> 0.6.0)
@@ -1051,7 +1053,7 @@ DEPENDENCIES
jira-ruby (~> 1.4)
jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 4.1.0)
- json-schema (~> 2.6.2)
+ json-schema (~> 2.8.0)
jwt (~> 1.5.6)
kaminari (~> 1.0)
knapsack (~> 1.11.0)
diff --git a/PROCESS.md b/PROCESS.md
index ed4e84dd0b6..5e65bb59246 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -197,6 +197,11 @@ month. When we say 'the most recent monthly release', this can refer to either
the version currently running on GitLab.com, or the most recent version
available in the package repositories.
+A regression issue should be labeled with the appropriate [subject label](../CONTRIBUTING.md#subject-labels-wiki-container-registry-ldap-api-etc)
+and [team label](../CONTRIBUTING.md#team-labels-ci-discussion-edge-platform-etc),
+just like any other issue, to help GitLab team members focus on issues that are
+relevant to [their area of responsibility](https://about.gitlab.com/handbook/engineering/workflow/#choosing-something-to-work-on).
+
## Release retrospective and kickoff
- [Retrospective](https://about.gitlab.com/handbook/engineering/workflow/#retrospective)
diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json
index e5da75faf38..6b8f85e37fd 100644
--- a/app/assets/images/icons.json
+++ b/app/assets/images/icons.json
@@ -1 +1 @@
-{"iconCount":134,"icons":["abuse","account","admin","angle-double-left","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-right","assignee","bold","book","branch","calendar","cancel","chevron-down","chevron-left","chevron-right","chevron-up","clock","code","comment-dots","comment-next","comment","comments","commit","credit-card","disk","doc_code","doc_image","doc_text","download","duplicate","earth","eye-slash","eye","file-additions","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","merge-request-close-m","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","star-o","star","stop","talic","task-done","template","thump-down","thump-up","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} \ No newline at end of file
+{"iconCount":135,"spriteSize":58718,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-right","assignee","bold","book","branch","calendar","cancel","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","comment-dots","comment-next","comment","comments","commit","credit-card","disk","doc_code","doc_image","doc_text","download","duplicate","earth","eye-slash","eye","file-additions","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","star-o","star","stop","talic","task-done","template","thump-down","thump-up","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","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 5c3a9962bd3..30cb2109ec2 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-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-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="M2 15V1a1 1 0 0 1 1-1h4.604c.93 0 1.762.088 2.495.264.733.176 1.353.445 1.863.807.509.363.897.82 1.164 1.369.268.549.401 1.197.401 1.945 0 .366-.045.718-.137 1.055-.091.337-.23.652-.417.945a3.453 3.453 0 0 1-.71.796 3.645 3.645 0 0 1-1.021.588c.469.117.87.295 1.203.533.333.238.608.515.824.83.216.315.374.657.473 1.027.099.37.148.75.148 1.138 0 1.553-.5 2.725-1.5 3.516-1 .791-2.423 1.187-4.27 1.187H3a1 1 0 0 1-1-1zm3.297-5.967v4.319H8.12c.425 0 .791-.053 1.099-.16.307-.106.564-.252.769-.44.205-.186.357-.406.456-.659.099-.252.148-.529.148-.83a3.04 3.04 0 0 0-.131-.928 1.78 1.78 0 0 0-.413-.703 1.8 1.8 0 0 0-.73-.445c-.3-.103-.66-.154-1.077-.154H5.297zm0-2.33h2.44c.842-.014 1.468-.192 1.878-.533.41-.34.616-.826.616-1.456 0-.725-.21-1.247-.632-1.566-.421-.318-1.086-.478-1.995-.478H5.297v4.033z"/></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="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="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="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="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 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="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 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 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-additions" 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="M7.228 5l-.475-1.335A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H7.228zM13 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="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="M8.462 2.177a.505.505 0 0 1-.038.044l.038-.044zm-.787 0l.038.043a.5.5 0 0 1-.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="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="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-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="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="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="merge-request-close-m" 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="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="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 7V1a1 1 0 1 1 2 0v6h6a1 1 0 0 1 0 2H9v6a1 1 0 0 1-2 0V9H1a1 1 0 1 1 0-2h6z"/></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="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.666 4.423a5 5 0 1 1-.203 6.944 1 1 0 1 0-1.478 1.347 7 7 0 1 0 .12-9.556L1.842 2.137a.5.5 0 0 0-.815.385L1 7.26a.5.5 0 0 0 .607.492l4.629-1.013a.5.5 0 0 0 .207-.877L4.666 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.494 4.423a5 5 0 1 0 .203 6.944 1 1 0 1 1 1.478 1.347 7 7 0 1 1-.12-9.556l1.262-1.021a.5.5 0 0 1 .815.385l.028 4.738a.5.5 0 0 1-.607.492L9.924 6.739a.5.5 0 0 1-.207-.877l1.777-1.439z"/></symbol><symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.009 6.958a4 4 0 0 0 5.283 4.775 1 1 0 0 1 .712 1.87A6 6 0 0 1 2.077 6.44l-.741-.2a.5.5 0 0 1-.12-.915L3.41 4.058a.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-.711-1.87 6 6 0 0 1 7.927 7.162l.74.2a.5.5 0 0 1 .121.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 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 0h8a3 3 0 0 1 3 3v7.186a3 3 0 0 1-1.426 2.554l-4 2.465a3 3 0 0 1-3.148 0l-4-2.465A3 3 0 0 1 1 10.186V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v7.186a1 1 0 0 0 .475.852l4 2.464a1 1 0 0 0 1.05 0l4-2.464a1 1 0 0 0 .475-.852V3a1 1 0 0 0-1-1H4zm0 1.5a.5.5 0 0 1 .5-.5h4v8.837a.5.5 0 0 1-.753.431l-3.5-2.052A.5.5 0 0 1 4 9.785V3.5z"/></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="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 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 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="talic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 0h7a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm2 2h3L8 14H5L8 2zM3 14h7a1 1 0 0 1 0 2H3a1 1 0 0 1 0-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="thump-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="thump-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="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="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.34 10.479A3 3 0 0 1 12.756 15h-9.51A3 3 0 0 1 .66 10.479l4.755-8.083a3 3 0 0 1 5.172 0l4.755 8.083zm-6.478-7.07a1 1 0 0 0-1.724 0l-4.755 8.084A1 1 0 0 0 3.245 13h9.51a1 1 0 0 0 .862-1.507L8.862 3.41zM8 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.535 7.95L1.292 3.707a1 1 0 0 1-.281-.695 1 1 0 1 1 1.695-.719l4.95 4.95a.998.998 0 0 1 0 1.414l-4.95 4.95a1.002 1.002 0 0 1-.707.293c-.549 0-1-.452-1-1 0-.266.106-.52.293-.708L5.535 7.95zm7 0L8.292 3.707a1 1 0 0 1-.281-.695 1 1 0 1 1 1.695-.719l4.95 4.95a.998.998 0 0 1 0 1.414l-4.95 4.95a1.002 1.002 0 0 1-.707.293c-.549 0-1-.452-1-1.001 0-.265.106-.519.293-.707l4.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-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="M2 15V1a1 1 0 0 1 1-1h4.604c.93 0 1.762.088 2.495.264.733.176 1.353.445 1.863.807.509.363.897.82 1.164 1.369.268.549.401 1.197.401 1.945 0 .366-.045.718-.137 1.055-.091.337-.23.652-.417.945a3.453 3.453 0 0 1-.71.796 3.645 3.645 0 0 1-1.021.588c.469.117.87.295 1.203.533.333.238.608.515.824.83.216.315.374.657.473 1.027.099.37.148.75.148 1.138 0 1.553-.5 2.725-1.5 3.516-1 .791-2.423 1.187-4.27 1.187H3a1 1 0 0 1-1-1zm3.297-5.967v4.319H8.12c.425 0 .791-.053 1.099-.16.307-.106.564-.252.769-.44.205-.186.357-.406.456-.659.099-.252.148-.529.148-.83a3.04 3.04 0 0 0-.131-.928 1.78 1.78 0 0 0-.413-.703 1.8 1.8 0 0 0-.73-.445c-.3-.103-.66-.154-1.077-.154H5.297zm0-2.33h2.44c.842-.014 1.468-.192 1.878-.533.41-.34.616-.826.616-1.456 0-.725-.21-1.247-.632-1.566-.421-.318-1.086-.478-1.995-.478H5.297v4.033z"/></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="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="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="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 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="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 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 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-additions" 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="M7.228 5l-.475-1.335A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H7.228zM13 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="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="M8.462 2.177a.505.505 0 0 1-.038.044l.038-.044zm-.787 0l.038.043a.5.5 0 0 1-.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="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="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-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="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="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="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 7V1a1 1 0 1 1 2 0v6h6a1 1 0 0 1 0 2H9v6a1 1 0 0 1-2 0V9H1a1 1 0 1 1 0-2h6z"/></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="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.666 4.423a5 5 0 1 1-.203 6.944 1 1 0 1 0-1.478 1.347 7 7 0 1 0 .12-9.556L1.842 2.137a.5.5 0 0 0-.815.385L1 7.26a.5.5 0 0 0 .607.492l4.629-1.013a.5.5 0 0 0 .207-.877L4.666 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.494 4.423a5 5 0 1 0 .203 6.944 1 1 0 1 1 1.478 1.347 7 7 0 1 1-.12-9.556l1.262-1.021a.5.5 0 0 1 .815.385l.028 4.738a.5.5 0 0 1-.607.492L9.924 6.739a.5.5 0 0 1-.207-.877l1.777-1.439z"/></symbol><symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.009 6.958a4 4 0 0 0 5.283 4.775 1 1 0 0 1 .712 1.87A6 6 0 0 1 2.077 6.44l-.741-.2a.5.5 0 0 1-.12-.915L3.41 4.058a.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-.711-1.87 6 6 0 0 1 7.927 7.162l.74.2a.5.5 0 0 1 .121.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 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 0h8a3 3 0 0 1 3 3v7.186a3 3 0 0 1-1.426 2.554l-4 2.465a3 3 0 0 1-3.148 0l-4-2.465A3 3 0 0 1 1 10.186V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v7.186a1 1 0 0 0 .475.852l4 2.464a1 1 0 0 0 1.05 0l4-2.464a1 1 0 0 0 .475-.852V3a1 1 0 0 0-1-1H4zm0 1.5a.5.5 0 0 1 .5-.5h4v8.837a.5.5 0 0 1-.753.431l-3.5-2.052A.5.5 0 0 1 4 9.785V3.5z"/></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="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 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 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="talic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 0h7a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm2 2h3L8 14H5L8 2zM3 14h7a1 1 0 0 1 0 2H3a1 1 0 0 1 0-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="thump-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="thump-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="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="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.34 10.479A3 3 0 0 1 12.756 15h-9.51A3 3 0 0 1 .66 10.479l4.755-8.083a3 3 0 0 1 5.172 0l4.755 8.083zm-6.478-7.07a1 1 0 0 0-1.724 0l-4.755 8.084A1 1 0 0 0 3.245 13h9.51a1 1 0 0 0 .862-1.507L8.862 3.41zM8 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/sprite.symbol.html b/app/assets/images/sprite.symbol.html
deleted file mode 100644
index d928d3f73b8..00000000000
--- a/app/assets/images/sprite.symbol.html
+++ /dev/null
@@ -1,3297 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta charset="utf-8"/>
- <meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
- <script src="https://rawgit.com/jonathantneal/svg4everybody/master/dist/svg4everybody.js"></script>
- <script>svg4everybody();</script>
- <title>SVG &lt;symbol&gt; sprite preview | svg-sprite</title>
- <style>@charset "UTF-8";body{padding:0;margin:0;color:#666;background:#fafafa;font-family:Arial,Helvetica,sans-serif;font-size:1em;line-height:1.4}header{display:block;padding:3em 3em 2em 3em;background-color:#fff}header p{margin:2em 0 0 0}section{border-top:1px solid #eee;padding:2em 3em 0 3em}section ul{margin:0;padding:0}section li{display:inline;display:inline-block;background-color:#fff;position:relative;margin:0 2em 2em 0;vertical-align:top;border:1px solid #ccc;padding:1em 1em 3em 1em;cursor:default}.icon-box{margin:0;width:144px;height:144px;position:relative;background:#ccc url("data:image/gif;base64,R0lGODlhDAAMAIAAAMzMzP///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjEgNjQuMTQwOTQ5LCAyMDEwLzEyLzA3LTEwOjU3OjAxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozQjk4OTI0MUY5NTIxMUUyQkJDMEI5NEFEM0Y1QTYwQyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozQjk4OTI0MkY5NTIxMUUyQkJDMEI5NEFEM0Y1QTYwQyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjNCOTg5MjNGRjk1MjExRTJCQkMwQjk0QUQzRjVBNjBDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjNCOTg5MjQwRjk1MjExRTJCQkMwQjk0QUQzRjVBNjBDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMyMTAvLi0sKyopKCcmJSQjIiEgHx4dHBsaGRgXFhUUExIREA8ODQwLCgkIBwYFBAMCAQAAIfkEAAAAAAAsAAAAAAwADAAAAhaEH6mHmmzcgzJAUG/NVGrfOZ8YLlABADs=") top left repeat;border:1px solid #ccc;display:table-cell;vertical-align:middle;text-align:center}.icon{display:inline;display:inline-block}h1{margin-top:0}h2{margin:0;padding:0;font-size:1em;font-weight:normal;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;position:absolute;left:1em;right:1em;bottom:1em}footer{display:block;margin:0;padding:0 3em 3em 3em}footer p{margin:0;font-size:.7em}footer a{color:#0f7595;margin-left:0}</style>
-
-<!--
-
-Sprite shape dimensions
-====================================================================================================
-You will need to set the sprite shape dimensions via CSS when you use them as inline SVG, otherwise
-they would become a huge 100% in size. You may use the following dimension classes for doing so.
-They might well be outsourced to an external stylesheet of course.
-
--->
-
-<style type="text/css">
- .svg-abuse-dims { width: 16px; height: 16px; }
- .svg-account-dims { width: 16px; height: 16px; }
- .svg-admin-dims { width: 16px; height: 16px; }
- .svg-angle-double-left-dims { width: 16px; height: 16px; }
- .svg-angle-down-dims { width: 16px; height: 16px; }
- .svg-angle-left-dims { width: 16px; height: 16px; }
- .svg-angle-right-dims { width: 16px; height: 16px; }
- .svg-angle-up-dims { width: 16px; height: 16px; }
- .svg-appearance-dims { width: 16px; height: 16px; }
- .svg-applications-dims { width: 16px; height: 16px; }
- .svg-approval-dims { width: 16px; height: 16px; }
- .svg-arrow-right-dims { width: 16px; height: 16px; }
- .svg-assignee-dims { width: 16px; height: 16px; }
- .svg-bold-dims { width: 16px; height: 16px; }
- .svg-book-dims { width: 16px; height: 16px; }
- .svg-branch-dims { width: 16px; height: 16px; }
- .svg-calendar-dims { width: 16px; height: 16px; }
- .svg-cancel-dims { width: 16px; height: 16px; }
- .svg-chevron-down-dims { width: 16px; height: 16px; }
- .svg-chevron-left-dims { width: 16px; height: 16px; }
- .svg-chevron-right-dims { width: 16px; height: 16px; }
- .svg-chevron-up-dims { width: 16px; height: 16px; }
- .svg-clock-dims { width: 16px; height: 16px; }
- .svg-code-dims { width: 16px; height: 16px; }
- .svg-comment-dims { width: 16px; height: 16px; }
- .svg-comment-dots-dims { width: 16px; height: 16px; }
- .svg-comment-next-dims { width: 16px; height: 16px; }
- .svg-comments-dims { width: 16px; height: 16px; }
- .svg-commit-dims { width: 16px; height: 16px; }
- .svg-credit-card-dims { width: 16px; height: 16px; }
- .svg-disk-dims { width: 16px; height: 16px; }
- .svg-doc_code-dims { width: 16px; height: 16px; }
- .svg-doc_image-dims { width: 16px; height: 16px; }
- .svg-doc_text-dims { width: 16px; height: 16px; }
- .svg-download-dims { width: 16px; height: 16px; }
- .svg-duplicate-dims { width: 16px; height: 16px; }
- .svg-earth-dims { width: 16px; height: 16px; }
- .svg-eye-dims { width: 16px; height: 16px; }
- .svg-eye-slash-dims { width: 16px; height: 16px; }
- .svg-file-additions-dims { width: 16px; height: 16px; }
- .svg-file-deletion-dims { width: 16px; height: 16px; }
- .svg-file-modified-dims { width: 16px; height: 16px; }
- .svg-filter-dims { width: 16px; height: 16px; }
- .svg-folder-dims { width: 16px; height: 16px; }
- .svg-fork-dims { width: 16px; height: 16px; }
- .svg-git-merge-dims { width: 16px; height: 16px; }
- .svg-group-dims { width: 16px; height: 16px; }
- .svg-history-dims { width: 16px; height: 16px; }
- .svg-home-dims { width: 16px; height: 16px; }
- .svg-hook-dims { width: 16px; height: 16px; }
- .svg-issue-block-dims { width: 16px; height: 16px; }
- .svg-issue-child-dims { width: 16px; height: 16px; }
- .svg-issue-close-dims { width: 16px; height: 16px; }
- .svg-issue-duplicate-dims { width: 16px; height: 16px; }
- .svg-issue-new-dims { width: 16px; height: 16px; }
- .svg-issue-open-dims { width: 16px; height: 16px; }
- .svg-issue-open-m-dims { width: 16px; height: 16px; }
- .svg-issue-parent-dims { width: 16px; height: 16px; }
- .svg-issues-dims { width: 16px; height: 16px; }
- .svg-key-dims { width: 16px; height: 16px; }
- .svg-key-2-dims { width: 16px; height: 16px; }
- .svg-label-dims { width: 16px; height: 16px; }
- .svg-labels-dims { width: 16px; height: 16px; }
- .svg-leave-dims { width: 16px; height: 16px; }
- .svg-level-up-dims { width: 16px; height: 16px; }
- .svg-license-dims { width: 16px; height: 16px; }
- .svg-link-dims { width: 16px; height: 16px; }
- .svg-list-bulleted-dims { width: 16px; height: 16px; }
- .svg-list-numbered-dims { width: 16px; height: 16px; }
- .svg-location-dims { width: 16px; height: 16px; }
- .svg-location-dot-dims { width: 16px; height: 16px; }
- .svg-lock-dims { width: 16px; height: 16px; }
- .svg-lock-open-dims { width: 16px; height: 16px; }
- .svg-log-dims { width: 16px; height: 16px; }
- .svg-mail-dims { width: 16px; height: 16px; }
- .svg-merge-request-close-dims { width: 16px; height: 16px; }
- .svg-merge-request-close-m-dims { width: 16px; height: 16px; }
- .svg-messages-dims { width: 16px; height: 16px; }
- .svg-mobile-issue-close-dims { width: 16px; height: 16px; }
- .svg-monitor-dims { width: 16px; height: 16px; }
- .svg-more-dims { width: 16px; height: 16px; }
- .svg-notifications-dims { width: 16px; height: 16px; }
- .svg-notifications-off-dims { width: 16px; height: 16px; }
- .svg-overview-dims { width: 16px; height: 16px; }
- .svg-pencil-dims { width: 16px; height: 16px; }
- .svg-pipeline-dims { width: 16px; height: 16px; }
- .svg-play-dims { width: 16px; height: 16px; }
- .svg-plus-dims { width: 16px; height: 16px; }
- .svg-plus-square-dims { width: 16px; height: 16px; }
- .svg-plus-square-o-dims { width: 16px; height: 16px; }
- .svg-preferences-dims { width: 16px; height: 16px; }
- .svg-profile-dims { width: 16px; height: 16px; }
- .svg-project-dims { width: 16px; height: 16px; }
- .svg-push-rules-dims { width: 16px; height: 16px; }
- .svg-question-dims { width: 16px; height: 16px; }
- .svg-question-o-dims { width: 16px; height: 16px; }
- .svg-quote-dims { width: 16px; height: 16px; }
- .svg-redo-dims { width: 16px; height: 16px; }
- .svg-remove-dims { width: 16px; height: 16px; }
- .svg-repeat-dims { width: 16px; height: 16px; }
- .svg-retry-dims { width: 16px; height: 16px; }
- .svg-scale-dims { width: 16px; height: 16px; }
- .svg-screen-full-dims { width: 16px; height: 16px; }
- .svg-screen-normal-dims { width: 16px; height: 16px; }
- .svg-search-dims { width: 16px; height: 16px; }
- .svg-settings-dims { width: 16px; height: 16px; }
- .svg-shield-dims { width: 16px; height: 16px; }
- .svg-slight-frown-dims { width: 16px; height: 16px; }
- .svg-slight-smile-dims { width: 16px; height: 16px; }
- .svg-smile-dims { width: 16px; height: 16px; }
- .svg-smiley-dims { width: 16px; height: 16px; }
- .svg-snippet-dims { width: 16px; height: 16px; }
- .svg-spam-dims { width: 16px; height: 16px; }
- .svg-star-dims { width: 16px; height: 16px; }
- .svg-star-o-dims { width: 16px; height: 16px; }
- .svg-stop-dims { width: 16px; height: 16px; }
- .svg-talic-dims { width: 16px; height: 16px; }
- .svg-task-done-dims { width: 16px; height: 16px; }
- .svg-template-dims { width: 16px; height: 16px; }
- .svg-thump-down-dims { width: 16px; height: 16px; }
- .svg-thump-up-dims { width: 16px; height: 16px; }
- .svg-timer-dims { width: 16px; height: 16px; }
- .svg-todo-add-dims { width: 16px; height: 16px; }
- .svg-todo-done-dims { width: 16px; height: 16px; }
- .svg-token-dims { width: 16px; height: 16px; }
- .svg-unapproval-dims { width: 16px; height: 16px; }
- .svg-unassignee-dims { width: 16px; height: 16px; }
- .svg-unlink-dims { width: 16px; height: 16px; }
- .svg-user-dims { width: 16px; height: 16px; }
- .svg-users-dims { width: 16px; height: 16px; }
- .svg-volume-up-dims { width: 16px; height: 16px; }
- .svg-warning-dims { width: 16px; height: 16px; }
- .svg-work-dims { width: 16px; height: 16px; }
-</style>
-<!--
-====================================================================================================
--->
-
- </head>
- <body>
-
-<!--
-
-Inline <symbol> SVG sprite
-====================================================================================================
-This is an inlined version of the generated SVG sprite. The single images may be <use>d everywhere
-below within this document. Please see
-
- https://github.com/jkphl/svg-sprite/blob/master/docs/configuration.md#defs--symbol-mode
-
-for further details on how to create this embeddable sprite variant.
-
--->
-
-<svg width="0" height="0" style="position:absolute">
- <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-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-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="M2 15V1a1 1 0 0 1 1-1h4.604c.93 0 1.762.088 2.495.264.733.176 1.353.445 1.863.807.509.363.897.82 1.164 1.369.268.549.401 1.197.401 1.945 0 .366-.045.718-.137 1.055-.091.337-.23.652-.417.945a3.453 3.453 0 0 1-.71.796 3.645 3.645 0 0 1-1.021.588c.469.117.87.295 1.203.533.333.238.608.515.824.83.216.315.374.657.473 1.027.099.37.148.75.148 1.138 0 1.553-.5 2.725-1.5 3.516-1 .791-2.423 1.187-4.27 1.187H3a1 1 0 0 1-1-1zm3.297-5.967v4.319H8.12c.425 0 .791-.053 1.099-.16.307-.106.564-.252.769-.44.205-.186.357-.406.456-.659.099-.252.148-.529.148-.83a3.04 3.04 0 0 0-.131-.928 1.78 1.78 0 0 0-.413-.703 1.8 1.8 0 0 0-.73-.445c-.3-.103-.66-.154-1.077-.154H5.297zm0-2.33h2.44c.842-.014 1.468-.192 1.878-.533.41-.34.616-.826.616-1.456 0-.725-.21-1.247-.632-1.566-.421-.318-1.086-.478-1.995-.478H5.297v4.033z"/></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="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="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="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="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 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="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 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 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-additions" 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="M7.228 5l-.475-1.335A1 1 0 0 0 5.81 3H2v9a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H7.228zM13 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="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="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="M8.462 2.177a.505.505 0 0 1-.038.044l.038-.044zm-.787 0l.038.043a.5.5 0 0 1-.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="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="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-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="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="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="merge-request-close-m" 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="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="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 7V1a1 1 0 1 1 2 0v6h6a1 1 0 0 1 0 2H9v6a1 1 0 0 1-2 0V9H1a1 1 0 1 1 0-2h6z"/></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="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.666 4.423a5 5 0 1 1-.203 6.944 1 1 0 1 0-1.478 1.347 7 7 0 1 0 .12-9.556L1.842 2.137a.5.5 0 0 0-.815.385L1 7.26a.5.5 0 0 0 .607.492l4.629-1.013a.5.5 0 0 0 .207-.877L4.666 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.494 4.423a5 5 0 1 0 .203 6.944 1 1 0 1 1 1.478 1.347 7 7 0 1 1-.12-9.556l1.262-1.021a.5.5 0 0 1 .815.385l.028 4.738a.5.5 0 0 1-.607.492L9.924 6.739a.5.5 0 0 1-.207-.877l1.777-1.439z"/></symbol>
- <symbol viewBox="0 0 16 16" id="retry" xmlns="http://www.w3.org/2000/svg"><path d="M4.009 6.958a4 4 0 0 0 5.283 4.775 1 1 0 0 1 .712 1.87A6 6 0 0 1 2.077 6.44l-.741-.2a.5.5 0 0 1-.12-.915L3.41 4.058a.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-.711-1.87 6 6 0 0 1 7.927 7.162l.74.2a.5.5 0 0 1 .121.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 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 0h8a3 3 0 0 1 3 3v7.186a3 3 0 0 1-1.426 2.554l-4 2.465a3 3 0 0 1-3.148 0l-4-2.465A3 3 0 0 1 1 10.186V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v7.186a1 1 0 0 0 .475.852l4 2.464a1 1 0 0 0 1.05 0l4-2.464a1 1 0 0 0 .475-.852V3a1 1 0 0 0-1-1H4zm0 1.5a.5.5 0 0 1 .5-.5h4v8.837a.5.5 0 0 1-.753.431l-3.5-2.052A.5.5 0 0 1 4 9.785V3.5z"/></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="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 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 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="talic" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M6 0h7a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm2 2h3L8 14H5L8 2zM3 14h7a1 1 0 0 1 0 2H3a1 1 0 0 1 0-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="thump-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="thump-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="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="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.34 10.479A3 3 0 0 1 12.756 15h-9.51A3 3 0 0 1 .66 10.479l4.755-8.083a3 3 0 0 1 5.172 0l4.755 8.083zm-6.478-7.07a1 1 0 0 0-1.724 0l-4.755 8.084A1 1 0 0 0 3.245 13h9.51a1 1 0 0 0 .862-1.507L8.862 3.41zM8 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>
-
-<!--
-====================================================================================================
--->
-
- <header>
- <h1>SVG <code>&lt;symbol&gt;</code> sprite preview</h1>
- <p>This preview features two methods of using the generated sprite in conjunction with inline SVG. Please have a look at the HTML source for further details and be aware of the following constraints:</p>
- <ul>
- <li>Your browser has to <a href="http://caniuse.com/#feat=svg-html5" target="_blank">support inline SVG</a> for these techniques to work.</li>
- <li>The embedded sprite (A) slightly differs from the generated external one. Please <a href="https://github.com/jkphl/svg-sprite/blob/master/docs/configuration.md#defs--symbol-mode" target="_blank">see the documentation</a> for details on how to create such an embeddable sprite.</li>
- <li>Internet Explorer up to version 11 doesn't support external sprites for use with inline SVG. For IE 9-11, you may polyfill this functionality with <a href="https://github.com/jonathantneal/svg4everybody" target="_blank">SVG for Everybody</a>.</li>
- </ul>
- </header>
- <section>
-
-<!--
-
-A) Inline SVG with embedded sprite
-====================================================================================================
-These SVG images make use of fragment identifiers (IDs) and are extracted out of the inline sprite
-embedded above. They may be styled via CSS.
-
--->
-
- <h3>A) Inline SVG with embedded sprite</h3>
- <ul>
-
- <li title="abuse">
- <div class="icon-box">
-
- <!-- abuse -->
- <svg class="svg-abuse-dims">
- <use xlink:href="#abuse"></use>
- </svg>
-
- </div>
- <h2>abuse</h2>
- </li>
- <li title="account">
- <div class="icon-box">
-
- <!-- account -->
- <svg class="svg-account-dims">
- <use xlink:href="#account"></use>
- </svg>
-
- </div>
- <h2>account</h2>
- </li>
- <li title="admin">
- <div class="icon-box">
-
- <!-- admin -->
- <svg class="svg-admin-dims">
- <use xlink:href="#admin"></use>
- </svg>
-
- </div>
- <h2>admin</h2>
- </li>
- <li title="angle-double-left">
- <div class="icon-box">
-
- <!-- angle-double-left -->
- <svg class="svg-angle-double-left-dims">
- <use xlink:href="#angle-double-left"></use>
- </svg>
-
- </div>
- <h2>angle-double-left</h2>
- </li>
- <li title="angle-down">
- <div class="icon-box">
-
- <!-- angle-down -->
- <svg class="svg-angle-down-dims">
- <use xlink:href="#angle-down"></use>
- </svg>
-
- </div>
- <h2>angle-down</h2>
- </li>
- <li title="angle-left">
- <div class="icon-box">
-
- <!-- angle-left -->
- <svg class="svg-angle-left-dims">
- <use xlink:href="#angle-left"></use>
- </svg>
-
- </div>
- <h2>angle-left</h2>
- </li>
- <li title="angle-right">
- <div class="icon-box">
-
- <!-- angle-right -->
- <svg class="svg-angle-right-dims">
- <use xlink:href="#angle-right"></use>
- </svg>
-
- </div>
- <h2>angle-right</h2>
- </li>
- <li title="angle-up">
- <div class="icon-box">
-
- <!-- angle-up -->
- <svg class="svg-angle-up-dims">
- <use xlink:href="#angle-up"></use>
- </svg>
-
- </div>
- <h2>angle-up</h2>
- </li>
- <li title="appearance">
- <div class="icon-box">
-
- <!-- appearance -->
- <svg class="svg-appearance-dims">
- <use xlink:href="#appearance"></use>
- </svg>
-
- </div>
- <h2>appearance</h2>
- </li>
- <li title="applications">
- <div class="icon-box">
-
- <!-- applications -->
- <svg class="svg-applications-dims">
- <use xlink:href="#applications"></use>
- </svg>
-
- </div>
- <h2>applications</h2>
- </li>
- <li title="approval">
- <div class="icon-box">
-
- <!-- approval -->
- <svg class="svg-approval-dims">
- <use xlink:href="#approval"></use>
- </svg>
-
- </div>
- <h2>approval</h2>
- </li>
- <li title="arrow-right">
- <div class="icon-box">
-
- <!-- arrow-right -->
- <svg class="svg-arrow-right-dims">
- <use xlink:href="#arrow-right"></use>
- </svg>
-
- </div>
- <h2>arrow-right</h2>
- </li>
- <li title="assignee">
- <div class="icon-box">
-
- <!-- assignee -->
- <svg class="svg-assignee-dims">
- <use xlink:href="#assignee"></use>
- </svg>
-
- </div>
- <h2>assignee</h2>
- </li>
- <li title="bold">
- <div class="icon-box">
-
- <!-- bold -->
- <svg class="svg-bold-dims">
- <use xlink:href="#bold"></use>
- </svg>
-
- </div>
- <h2>bold</h2>
- </li>
- <li title="book">
- <div class="icon-box">
-
- <!-- book -->
- <svg class="svg-book-dims">
- <use xlink:href="#book"></use>
- </svg>
-
- </div>
- <h2>book</h2>
- </li>
- <li title="branch">
- <div class="icon-box">
-
- <!-- branch -->
- <svg class="svg-branch-dims">
- <use xlink:href="#branch"></use>
- </svg>
-
- </div>
- <h2>branch</h2>
- </li>
- <li title="calendar">
- <div class="icon-box">
-
- <!-- calendar -->
- <svg class="svg-calendar-dims">
- <use xlink:href="#calendar"></use>
- </svg>
-
- </div>
- <h2>calendar</h2>
- </li>
- <li title="cancel">
- <div class="icon-box">
-
- <!-- cancel -->
- <svg class="svg-cancel-dims">
- <use xlink:href="#cancel"></use>
- </svg>
-
- </div>
- <h2>cancel</h2>
- </li>
- <li title="chevron-down">
- <div class="icon-box">
-
- <!-- chevron-down -->
- <svg class="svg-chevron-down-dims">
- <use xlink:href="#chevron-down"></use>
- </svg>
-
- </div>
- <h2>chevron-down</h2>
- </li>
- <li title="chevron-left">
- <div class="icon-box">
-
- <!-- chevron-left -->
- <svg class="svg-chevron-left-dims">
- <use xlink:href="#chevron-left"></use>
- </svg>
-
- </div>
- <h2>chevron-left</h2>
- </li>
- <li title="chevron-right">
- <div class="icon-box">
-
- <!-- chevron-right -->
- <svg class="svg-chevron-right-dims">
- <use xlink:href="#chevron-right"></use>
- </svg>
-
- </div>
- <h2>chevron-right</h2>
- </li>
- <li title="chevron-up">
- <div class="icon-box">
-
- <!-- chevron-up -->
- <svg class="svg-chevron-up-dims">
- <use xlink:href="#chevron-up"></use>
- </svg>
-
- </div>
- <h2>chevron-up</h2>
- </li>
- <li title="clock">
- <div class="icon-box">
-
- <!-- clock -->
- <svg class="svg-clock-dims">
- <use xlink:href="#clock"></use>
- </svg>
-
- </div>
- <h2>clock</h2>
- </li>
- <li title="code">
- <div class="icon-box">
-
- <!-- code -->
- <svg class="svg-code-dims">
- <use xlink:href="#code"></use>
- </svg>
-
- </div>
- <h2>code</h2>
- </li>
- <li title="comment">
- <div class="icon-box">
-
- <!-- comment -->
- <svg class="svg-comment-dims">
- <use xlink:href="#comment"></use>
- </svg>
-
- </div>
- <h2>comment</h2>
- </li>
- <li title="comment-dots">
- <div class="icon-box">
-
- <!-- comment-dots -->
- <svg class="svg-comment-dots-dims">
- <use xlink:href="#comment-dots"></use>
- </svg>
-
- </div>
- <h2>comment-dots</h2>
- </li>
- <li title="comment-next">
- <div class="icon-box">
-
- <!-- comment-next -->
- <svg class="svg-comment-next-dims">
- <use xlink:href="#comment-next"></use>
- </svg>
-
- </div>
- <h2>comment-next</h2>
- </li>
- <li title="comments">
- <div class="icon-box">
-
- <!-- comments -->
- <svg class="svg-comments-dims">
- <use xlink:href="#comments"></use>
- </svg>
-
- </div>
- <h2>comments</h2>
- </li>
- <li title="commit">
- <div class="icon-box">
-
- <!-- commit -->
- <svg class="svg-commit-dims">
- <use xlink:href="#commit"></use>
- </svg>
-
- </div>
- <h2>commit</h2>
- </li>
- <li title="credit-card">
- <div class="icon-box">
-
- <!-- credit-card -->
- <svg class="svg-credit-card-dims">
- <use xlink:href="#credit-card"></use>
- </svg>
-
- </div>
- <h2>credit-card</h2>
- </li>
- <li title="disk">
- <div class="icon-box">
-
- <!-- disk -->
- <svg class="svg-disk-dims">
- <use xlink:href="#disk"></use>
- </svg>
-
- </div>
- <h2>disk</h2>
- </li>
- <li title="doc_code">
- <div class="icon-box">
-
- <!-- doc_code -->
- <svg class="svg-doc_code-dims">
- <use xlink:href="#doc_code"></use>
- </svg>
-
- </div>
- <h2>doc_code</h2>
- </li>
- <li title="doc_image">
- <div class="icon-box">
-
- <!-- doc_image -->
- <svg class="svg-doc_image-dims">
- <use xlink:href="#doc_image"></use>
- </svg>
-
- </div>
- <h2>doc_image</h2>
- </li>
- <li title="doc_text">
- <div class="icon-box">
-
- <!-- doc_text -->
- <svg class="svg-doc_text-dims">
- <use xlink:href="#doc_text"></use>
- </svg>
-
- </div>
- <h2>doc_text</h2>
- </li>
- <li title="download">
- <div class="icon-box">
-
- <!-- download -->
- <svg class="svg-download-dims">
- <use xlink:href="#download"></use>
- </svg>
-
- </div>
- <h2>download</h2>
- </li>
- <li title="duplicate">
- <div class="icon-box">
-
- <!-- duplicate -->
- <svg class="svg-duplicate-dims">
- <use xlink:href="#duplicate"></use>
- </svg>
-
- </div>
- <h2>duplicate</h2>
- </li>
- <li title="earth">
- <div class="icon-box">
-
- <!-- earth -->
- <svg class="svg-earth-dims">
- <use xlink:href="#earth"></use>
- </svg>
-
- </div>
- <h2>earth</h2>
- </li>
- <li title="eye">
- <div class="icon-box">
-
- <!-- eye -->
- <svg class="svg-eye-dims">
- <use xlink:href="#eye"></use>
- </svg>
-
- </div>
- <h2>eye</h2>
- </li>
- <li title="eye-slash">
- <div class="icon-box">
-
- <!-- eye-slash -->
- <svg class="svg-eye-slash-dims">
- <use xlink:href="#eye-slash"></use>
- </svg>
-
- </div>
- <h2>eye-slash</h2>
- </li>
- <li title="file-additions">
- <div class="icon-box">
-
- <!-- file-additions -->
- <svg class="svg-file-additions-dims">
- <use xlink:href="#file-additions"></use>
- </svg>
-
- </div>
- <h2>file-additions</h2>
- </li>
- <li title="file-deletion">
- <div class="icon-box">
-
- <!-- file-deletion -->
- <svg class="svg-file-deletion-dims">
- <use xlink:href="#file-deletion"></use>
- </svg>
-
- </div>
- <h2>file-deletion</h2>
- </li>
- <li title="file-modified">
- <div class="icon-box">
-
- <!-- file-modified -->
- <svg class="svg-file-modified-dims">
- <use xlink:href="#file-modified"></use>
- </svg>
-
- </div>
- <h2>file-modified</h2>
- </li>
- <li title="filter">
- <div class="icon-box">
-
- <!-- filter -->
- <svg class="svg-filter-dims">
- <use xlink:href="#filter"></use>
- </svg>
-
- </div>
- <h2>filter</h2>
- </li>
- <li title="folder">
- <div class="icon-box">
-
- <!-- folder -->
- <svg class="svg-folder-dims">
- <use xlink:href="#folder"></use>
- </svg>
-
- </div>
- <h2>folder</h2>
- </li>
- <li title="fork">
- <div class="icon-box">
-
- <!-- fork -->
- <svg class="svg-fork-dims">
- <use xlink:href="#fork"></use>
- </svg>
-
- </div>
- <h2>fork</h2>
- </li>
- <li title="git-merge">
- <div class="icon-box">
-
- <!-- git-merge -->
- <svg class="svg-git-merge-dims">
- <use xlink:href="#git-merge"></use>
- </svg>
-
- </div>
- <h2>git-merge</h2>
- </li>
- <li title="group">
- <div class="icon-box">
-
- <!-- group -->
- <svg class="svg-group-dims">
- <use xlink:href="#group"></use>
- </svg>
-
- </div>
- <h2>group</h2>
- </li>
- <li title="history">
- <div class="icon-box">
-
- <!-- history -->
- <svg class="svg-history-dims">
- <use xlink:href="#history"></use>
- </svg>
-
- </div>
- <h2>history</h2>
- </li>
- <li title="home">
- <div class="icon-box">
-
- <!-- home -->
- <svg class="svg-home-dims">
- <use xlink:href="#home"></use>
- </svg>
-
- </div>
- <h2>home</h2>
- </li>
- <li title="hook">
- <div class="icon-box">
-
- <!-- hook -->
- <svg class="svg-hook-dims">
- <use xlink:href="#hook"></use>
- </svg>
-
- </div>
- <h2>hook</h2>
- </li>
- <li title="issue-block">
- <div class="icon-box">
-
- <!-- issue-block -->
- <svg class="svg-issue-block-dims">
- <use xlink:href="#issue-block"></use>
- </svg>
-
- </div>
- <h2>issue-block</h2>
- </li>
- <li title="issue-child">
- <div class="icon-box">
-
- <!-- issue-child -->
- <svg class="svg-issue-child-dims">
- <use xlink:href="#issue-child"></use>
- </svg>
-
- </div>
- <h2>issue-child</h2>
- </li>
- <li title="issue-close">
- <div class="icon-box">
-
- <!-- issue-close -->
- <svg class="svg-issue-close-dims">
- <use xlink:href="#issue-close"></use>
- </svg>
-
- </div>
- <h2>issue-close</h2>
- </li>
- <li title="issue-duplicate">
- <div class="icon-box">
-
- <!-- issue-duplicate -->
- <svg class="svg-issue-duplicate-dims">
- <use xlink:href="#issue-duplicate"></use>
- </svg>
-
- </div>
- <h2>issue-duplicate</h2>
- </li>
- <li title="issue-new">
- <div class="icon-box">
-
- <!-- issue-new -->
- <svg class="svg-issue-new-dims">
- <use xlink:href="#issue-new"></use>
- </svg>
-
- </div>
- <h2>issue-new</h2>
- </li>
- <li title="issue-open">
- <div class="icon-box">
-
- <!-- issue-open -->
- <svg class="svg-issue-open-dims">
- <use xlink:href="#issue-open"></use>
- </svg>
-
- </div>
- <h2>issue-open</h2>
- </li>
- <li title="issue-open-m">
- <div class="icon-box">
-
- <!-- issue-open-m -->
- <svg class="svg-issue-open-m-dims">
- <use xlink:href="#issue-open-m"></use>
- </svg>
-
- </div>
- <h2>issue-open-m</h2>
- </li>
- <li title="issue-parent">
- <div class="icon-box">
-
- <!-- issue-parent -->
- <svg class="svg-issue-parent-dims">
- <use xlink:href="#issue-parent"></use>
- </svg>
-
- </div>
- <h2>issue-parent</h2>
- </li>
- <li title="issues">
- <div class="icon-box">
-
- <!-- issues -->
- <svg class="svg-issues-dims">
- <use xlink:href="#issues"></use>
- </svg>
-
- </div>
- <h2>issues</h2>
- </li>
- <li title="key">
- <div class="icon-box">
-
- <!-- key -->
- <svg class="svg-key-dims">
- <use xlink:href="#key"></use>
- </svg>
-
- </div>
- <h2>key</h2>
- </li>
- <li title="key-2">
- <div class="icon-box">
-
- <!-- key-2 -->
- <svg class="svg-key-2-dims">
- <use xlink:href="#key-2"></use>
- </svg>
-
- </div>
- <h2>key-2</h2>
- </li>
- <li title="label">
- <div class="icon-box">
-
- <!-- label -->
- <svg class="svg-label-dims">
- <use xlink:href="#label"></use>
- </svg>
-
- </div>
- <h2>label</h2>
- </li>
- <li title="labels">
- <div class="icon-box">
-
- <!-- labels -->
- <svg class="svg-labels-dims">
- <use xlink:href="#labels"></use>
- </svg>
-
- </div>
- <h2>labels</h2>
- </li>
- <li title="leave">
- <div class="icon-box">
-
- <!-- leave -->
- <svg class="svg-leave-dims">
- <use xlink:href="#leave"></use>
- </svg>
-
- </div>
- <h2>leave</h2>
- </li>
- <li title="level-up">
- <div class="icon-box">
-
- <!-- level-up -->
- <svg class="svg-level-up-dims">
- <use xlink:href="#level-up"></use>
- </svg>
-
- </div>
- <h2>level-up</h2>
- </li>
- <li title="license">
- <div class="icon-box">
-
- <!-- license -->
- <svg class="svg-license-dims">
- <use xlink:href="#license"></use>
- </svg>
-
- </div>
- <h2>license</h2>
- </li>
- <li title="link">
- <div class="icon-box">
-
- <!-- link -->
- <svg class="svg-link-dims">
- <use xlink:href="#link"></use>
- </svg>
-
- </div>
- <h2>link</h2>
- </li>
- <li title="list-bulleted">
- <div class="icon-box">
-
- <!-- list-bulleted -->
- <svg class="svg-list-bulleted-dims">
- <use xlink:href="#list-bulleted"></use>
- </svg>
-
- </div>
- <h2>list-bulleted</h2>
- </li>
- <li title="list-numbered">
- <div class="icon-box">
-
- <!-- list-numbered -->
- <svg class="svg-list-numbered-dims">
- <use xlink:href="#list-numbered"></use>
- </svg>
-
- </div>
- <h2>list-numbered</h2>
- </li>
- <li title="location">
- <div class="icon-box">
-
- <!-- location -->
- <svg class="svg-location-dims">
- <use xlink:href="#location"></use>
- </svg>
-
- </div>
- <h2>location</h2>
- </li>
- <li title="location-dot">
- <div class="icon-box">
-
- <!-- location-dot -->
- <svg class="svg-location-dot-dims">
- <use xlink:href="#location-dot"></use>
- </svg>
-
- </div>
- <h2>location-dot</h2>
- </li>
- <li title="lock">
- <div class="icon-box">
-
- <!-- lock -->
- <svg class="svg-lock-dims">
- <use xlink:href="#lock"></use>
- </svg>
-
- </div>
- <h2>lock</h2>
- </li>
- <li title="lock-open">
- <div class="icon-box">
-
- <!-- lock-open -->
- <svg class="svg-lock-open-dims">
- <use xlink:href="#lock-open"></use>
- </svg>
-
- </div>
- <h2>lock-open</h2>
- </li>
- <li title="log">
- <div class="icon-box">
-
- <!-- log -->
- <svg class="svg-log-dims">
- <use xlink:href="#log"></use>
- </svg>
-
- </div>
- <h2>log</h2>
- </li>
- <li title="mail">
- <div class="icon-box">
-
- <!-- mail -->
- <svg class="svg-mail-dims">
- <use xlink:href="#mail"></use>
- </svg>
-
- </div>
- <h2>mail</h2>
- </li>
- <li title="merge-request-close">
- <div class="icon-box">
-
- <!-- merge-request-close -->
- <svg class="svg-merge-request-close-dims">
- <use xlink:href="#merge-request-close"></use>
- </svg>
-
- </div>
- <h2>merge-request-close</h2>
- </li>
- <li title="merge-request-close-m">
- <div class="icon-box">
-
- <!-- merge-request-close-m -->
- <svg class="svg-merge-request-close-m-dims">
- <use xlink:href="#merge-request-close-m"></use>
- </svg>
-
- </div>
- <h2>merge-request-close-m</h2>
- </li>
- <li title="messages">
- <div class="icon-box">
-
- <!-- messages -->
- <svg class="svg-messages-dims">
- <use xlink:href="#messages"></use>
- </svg>
-
- </div>
- <h2>messages</h2>
- </li>
- <li title="mobile-issue-close">
- <div class="icon-box">
-
- <!-- mobile-issue-close -->
- <svg class="svg-mobile-issue-close-dims">
- <use xlink:href="#mobile-issue-close"></use>
- </svg>
-
- </div>
- <h2>mobile-issue-close</h2>
- </li>
- <li title="monitor">
- <div class="icon-box">
-
- <!-- monitor -->
- <svg class="svg-monitor-dims">
- <use xlink:href="#monitor"></use>
- </svg>
-
- </div>
- <h2>monitor</h2>
- </li>
- <li title="more">
- <div class="icon-box">
-
- <!-- more -->
- <svg class="svg-more-dims">
- <use xlink:href="#more"></use>
- </svg>
-
- </div>
- <h2>more</h2>
- </li>
- <li title="notifications">
- <div class="icon-box">
-
- <!-- notifications -->
- <svg class="svg-notifications-dims">
- <use xlink:href="#notifications"></use>
- </svg>
-
- </div>
- <h2>notifications</h2>
- </li>
- <li title="notifications-off">
- <div class="icon-box">
-
- <!-- notifications-off -->
- <svg class="svg-notifications-off-dims">
- <use xlink:href="#notifications-off"></use>
- </svg>
-
- </div>
- <h2>notifications-off</h2>
- </li>
- <li title="overview">
- <div class="icon-box">
-
- <!-- overview -->
- <svg class="svg-overview-dims">
- <use xlink:href="#overview"></use>
- </svg>
-
- </div>
- <h2>overview</h2>
- </li>
- <li title="pencil">
- <div class="icon-box">
-
- <!-- pencil -->
- <svg class="svg-pencil-dims">
- <use xlink:href="#pencil"></use>
- </svg>
-
- </div>
- <h2>pencil</h2>
- </li>
- <li title="pipeline">
- <div class="icon-box">
-
- <!-- pipeline -->
- <svg class="svg-pipeline-dims">
- <use xlink:href="#pipeline"></use>
- </svg>
-
- </div>
- <h2>pipeline</h2>
- </li>
- <li title="play">
- <div class="icon-box">
-
- <!-- play -->
- <svg class="svg-play-dims">
- <use xlink:href="#play"></use>
- </svg>
-
- </div>
- <h2>play</h2>
- </li>
- <li title="plus">
- <div class="icon-box">
-
- <!-- plus -->
- <svg class="svg-plus-dims">
- <use xlink:href="#plus"></use>
- </svg>
-
- </div>
- <h2>plus</h2>
- </li>
- <li title="plus-square">
- <div class="icon-box">
-
- <!-- plus-square -->
- <svg class="svg-plus-square-dims">
- <use xlink:href="#plus-square"></use>
- </svg>
-
- </div>
- <h2>plus-square</h2>
- </li>
- <li title="plus-square-o">
- <div class="icon-box">
-
- <!-- plus-square-o -->
- <svg class="svg-plus-square-o-dims">
- <use xlink:href="#plus-square-o"></use>
- </svg>
-
- </div>
- <h2>plus-square-o</h2>
- </li>
- <li title="preferences">
- <div class="icon-box">
-
- <!-- preferences -->
- <svg class="svg-preferences-dims">
- <use xlink:href="#preferences"></use>
- </svg>
-
- </div>
- <h2>preferences</h2>
- </li>
- <li title="profile">
- <div class="icon-box">
-
- <!-- profile -->
- <svg class="svg-profile-dims">
- <use xlink:href="#profile"></use>
- </svg>
-
- </div>
- <h2>profile</h2>
- </li>
- <li title="project">
- <div class="icon-box">
-
- <!-- project -->
- <svg class="svg-project-dims">
- <use xlink:href="#project"></use>
- </svg>
-
- </div>
- <h2>project</h2>
- </li>
- <li title="push-rules">
- <div class="icon-box">
-
- <!-- push-rules -->
- <svg class="svg-push-rules-dims">
- <use xlink:href="#push-rules"></use>
- </svg>
-
- </div>
- <h2>push-rules</h2>
- </li>
- <li title="question">
- <div class="icon-box">
-
- <!-- question -->
- <svg class="svg-question-dims">
- <use xlink:href="#question"></use>
- </svg>
-
- </div>
- <h2>question</h2>
- </li>
- <li title="question-o">
- <div class="icon-box">
-
- <!-- question-o -->
- <svg class="svg-question-o-dims">
- <use xlink:href="#question-o"></use>
- </svg>
-
- </div>
- <h2>question-o</h2>
- </li>
- <li title="quote">
- <div class="icon-box">
-
- <!-- quote -->
- <svg class="svg-quote-dims">
- <use xlink:href="#quote"></use>
- </svg>
-
- </div>
- <h2>quote</h2>
- </li>
- <li title="redo">
- <div class="icon-box">
-
- <!-- redo -->
- <svg class="svg-redo-dims">
- <use xlink:href="#redo"></use>
- </svg>
-
- </div>
- <h2>redo</h2>
- </li>
- <li title="remove">
- <div class="icon-box">
-
- <!-- remove -->
- <svg class="svg-remove-dims">
- <use xlink:href="#remove"></use>
- </svg>
-
- </div>
- <h2>remove</h2>
- </li>
- <li title="repeat">
- <div class="icon-box">
-
- <!-- repeat -->
- <svg class="svg-repeat-dims">
- <use xlink:href="#repeat"></use>
- </svg>
-
- </div>
- <h2>repeat</h2>
- </li>
- <li title="retry">
- <div class="icon-box">
-
- <!-- retry -->
- <svg class="svg-retry-dims">
- <use xlink:href="#retry"></use>
- </svg>
-
- </div>
- <h2>retry</h2>
- </li>
- <li title="scale">
- <div class="icon-box">
-
- <!-- scale -->
- <svg class="svg-scale-dims">
- <use xlink:href="#scale"></use>
- </svg>
-
- </div>
- <h2>scale</h2>
- </li>
- <li title="screen-full">
- <div class="icon-box">
-
- <!-- screen-full -->
- <svg class="svg-screen-full-dims">
- <use xlink:href="#screen-full"></use>
- </svg>
-
- </div>
- <h2>screen-full</h2>
- </li>
- <li title="screen-normal">
- <div class="icon-box">
-
- <!-- screen-normal -->
- <svg class="svg-screen-normal-dims">
- <use xlink:href="#screen-normal"></use>
- </svg>
-
- </div>
- <h2>screen-normal</h2>
- </li>
- <li title="search">
- <div class="icon-box">
-
- <!-- search -->
- <svg class="svg-search-dims">
- <use xlink:href="#search"></use>
- </svg>
-
- </div>
- <h2>search</h2>
- </li>
- <li title="settings">
- <div class="icon-box">
-
- <!-- settings -->
- <svg class="svg-settings-dims">
- <use xlink:href="#settings"></use>
- </svg>
-
- </div>
- <h2>settings</h2>
- </li>
- <li title="shield">
- <div class="icon-box">
-
- <!-- shield -->
- <svg class="svg-shield-dims">
- <use xlink:href="#shield"></use>
- </svg>
-
- </div>
- <h2>shield</h2>
- </li>
- <li title="slight-frown">
- <div class="icon-box">
-
- <!-- slight-frown -->
- <svg class="svg-slight-frown-dims">
- <use xlink:href="#slight-frown"></use>
- </svg>
-
- </div>
- <h2>slight-frown</h2>
- </li>
- <li title="slight-smile">
- <div class="icon-box">
-
- <!-- slight-smile -->
- <svg class="svg-slight-smile-dims">
- <use xlink:href="#slight-smile"></use>
- </svg>
-
- </div>
- <h2>slight-smile</h2>
- </li>
- <li title="smile">
- <div class="icon-box">
-
- <!-- smile -->
- <svg class="svg-smile-dims">
- <use xlink:href="#smile"></use>
- </svg>
-
- </div>
- <h2>smile</h2>
- </li>
- <li title="smiley">
- <div class="icon-box">
-
- <!-- smiley -->
- <svg class="svg-smiley-dims">
- <use xlink:href="#smiley"></use>
- </svg>
-
- </div>
- <h2>smiley</h2>
- </li>
- <li title="snippet">
- <div class="icon-box">
-
- <!-- snippet -->
- <svg class="svg-snippet-dims">
- <use xlink:href="#snippet"></use>
- </svg>
-
- </div>
- <h2>snippet</h2>
- </li>
- <li title="spam">
- <div class="icon-box">
-
- <!-- spam -->
- <svg class="svg-spam-dims">
- <use xlink:href="#spam"></use>
- </svg>
-
- </div>
- <h2>spam</h2>
- </li>
- <li title="star">
- <div class="icon-box">
-
- <!-- star -->
- <svg class="svg-star-dims">
- <use xlink:href="#star"></use>
- </svg>
-
- </div>
- <h2>star</h2>
- </li>
- <li title="star-o">
- <div class="icon-box">
-
- <!-- star-o -->
- <svg class="svg-star-o-dims">
- <use xlink:href="#star-o"></use>
- </svg>
-
- </div>
- <h2>star-o</h2>
- </li>
- <li title="stop">
- <div class="icon-box">
-
- <!-- stop -->
- <svg class="svg-stop-dims">
- <use xlink:href="#stop"></use>
- </svg>
-
- </div>
- <h2>stop</h2>
- </li>
- <li title="talic">
- <div class="icon-box">
-
- <!-- talic -->
- <svg class="svg-talic-dims">
- <use xlink:href="#talic"></use>
- </svg>
-
- </div>
- <h2>talic</h2>
- </li>
- <li title="task-done">
- <div class="icon-box">
-
- <!-- task-done -->
- <svg class="svg-task-done-dims">
- <use xlink:href="#task-done"></use>
- </svg>
-
- </div>
- <h2>task-done</h2>
- </li>
- <li title="template">
- <div class="icon-box">
-
- <!-- template -->
- <svg class="svg-template-dims">
- <use xlink:href="#template"></use>
- </svg>
-
- </div>
- <h2>template</h2>
- </li>
- <li title="thump-down">
- <div class="icon-box">
-
- <!-- thump-down -->
- <svg class="svg-thump-down-dims">
- <use xlink:href="#thump-down"></use>
- </svg>
-
- </div>
- <h2>thump-down</h2>
- </li>
- <li title="thump-up">
- <div class="icon-box">
-
- <!-- thump-up -->
- <svg class="svg-thump-up-dims">
- <use xlink:href="#thump-up"></use>
- </svg>
-
- </div>
- <h2>thump-up</h2>
- </li>
- <li title="timer">
- <div class="icon-box">
-
- <!-- timer -->
- <svg class="svg-timer-dims">
- <use xlink:href="#timer"></use>
- </svg>
-
- </div>
- <h2>timer</h2>
- </li>
- <li title="todo-add">
- <div class="icon-box">
-
- <!-- todo-add -->
- <svg class="svg-todo-add-dims">
- <use xlink:href="#todo-add"></use>
- </svg>
-
- </div>
- <h2>todo-add</h2>
- </li>
- <li title="todo-done">
- <div class="icon-box">
-
- <!-- todo-done -->
- <svg class="svg-todo-done-dims">
- <use xlink:href="#todo-done"></use>
- </svg>
-
- </div>
- <h2>todo-done</h2>
- </li>
- <li title="token">
- <div class="icon-box">
-
- <!-- token -->
- <svg class="svg-token-dims">
- <use xlink:href="#token"></use>
- </svg>
-
- </div>
- <h2>token</h2>
- </li>
- <li title="unapproval">
- <div class="icon-box">
-
- <!-- unapproval -->
- <svg class="svg-unapproval-dims">
- <use xlink:href="#unapproval"></use>
- </svg>
-
- </div>
- <h2>unapproval</h2>
- </li>
- <li title="unassignee">
- <div class="icon-box">
-
- <!-- unassignee -->
- <svg class="svg-unassignee-dims">
- <use xlink:href="#unassignee"></use>
- </svg>
-
- </div>
- <h2>unassignee</h2>
- </li>
- <li title="unlink">
- <div class="icon-box">
-
- <!-- unlink -->
- <svg class="svg-unlink-dims">
- <use xlink:href="#unlink"></use>
- </svg>
-
- </div>
- <h2>unlink</h2>
- </li>
- <li title="user">
- <div class="icon-box">
-
- <!-- user -->
- <svg class="svg-user-dims">
- <use xlink:href="#user"></use>
- </svg>
-
- </div>
- <h2>user</h2>
- </li>
- <li title="users">
- <div class="icon-box">
-
- <!-- users -->
- <svg class="svg-users-dims">
- <use xlink:href="#users"></use>
- </svg>
-
- </div>
- <h2>users</h2>
- </li>
- <li title="volume-up">
- <div class="icon-box">
-
- <!-- volume-up -->
- <svg class="svg-volume-up-dims">
- <use xlink:href="#volume-up"></use>
- </svg>
-
- </div>
- <h2>volume-up</h2>
- </li>
- <li title="warning">
- <div class="icon-box">
-
- <!-- warning -->
- <svg class="svg-warning-dims">
- <use xlink:href="#warning"></use>
- </svg>
-
- </div>
- <h2>warning</h2>
- </li>
- <li title="work">
- <div class="icon-box">
-
- <!-- work -->
- <svg class="svg-work-dims">
- <use xlink:href="#work"></use>
- </svg>
-
- </div>
- <h2>work</h2>
- </li>
- </ul>
-
-<!--
-====================================================================================================
--->
-
- </section>
- <section>
-
-<!--
-
-B) Inline SVG with external sprite (IE 9-11 with polyfill only)
-====================================================================================================
-These SVG images make use of an URL + fragment identifiers (IDs) and refer to the regular external
-SVG sprite. They may be styled via CSS. (IE 9-11 with polyfill only)
-
--->
-
- <h3>B) Inline SVG with external sprite (IE 9-11 with polyfill only)</h3>
- <ul>
-
- <li title="abuse">
- <div class="icon-box">
-
- <!-- abuse -->
- <svg class="svg-abuse-dims">
- <use xlink:href="icons.svg#abuse"></use>
- </svg>
-
- </div>
- <h2>abuse</h2>
- </li>
- <li title="account">
- <div class="icon-box">
-
- <!-- account -->
- <svg class="svg-account-dims">
- <use xlink:href="icons.svg#account"></use>
- </svg>
-
- </div>
- <h2>account</h2>
- </li>
- <li title="admin">
- <div class="icon-box">
-
- <!-- admin -->
- <svg class="svg-admin-dims">
- <use xlink:href="icons.svg#admin"></use>
- </svg>
-
- </div>
- <h2>admin</h2>
- </li>
- <li title="angle-double-left">
- <div class="icon-box">
-
- <!-- angle-double-left -->
- <svg class="svg-angle-double-left-dims">
- <use xlink:href="icons.svg#angle-double-left"></use>
- </svg>
-
- </div>
- <h2>angle-double-left</h2>
- </li>
- <li title="angle-down">
- <div class="icon-box">
-
- <!-- angle-down -->
- <svg class="svg-angle-down-dims">
- <use xlink:href="icons.svg#angle-down"></use>
- </svg>
-
- </div>
- <h2>angle-down</h2>
- </li>
- <li title="angle-left">
- <div class="icon-box">
-
- <!-- angle-left -->
- <svg class="svg-angle-left-dims">
- <use xlink:href="icons.svg#angle-left"></use>
- </svg>
-
- </div>
- <h2>angle-left</h2>
- </li>
- <li title="angle-right">
- <div class="icon-box">
-
- <!-- angle-right -->
- <svg class="svg-angle-right-dims">
- <use xlink:href="icons.svg#angle-right"></use>
- </svg>
-
- </div>
- <h2>angle-right</h2>
- </li>
- <li title="angle-up">
- <div class="icon-box">
-
- <!-- angle-up -->
- <svg class="svg-angle-up-dims">
- <use xlink:href="icons.svg#angle-up"></use>
- </svg>
-
- </div>
- <h2>angle-up</h2>
- </li>
- <li title="appearance">
- <div class="icon-box">
-
- <!-- appearance -->
- <svg class="svg-appearance-dims">
- <use xlink:href="icons.svg#appearance"></use>
- </svg>
-
- </div>
- <h2>appearance</h2>
- </li>
- <li title="applications">
- <div class="icon-box">
-
- <!-- applications -->
- <svg class="svg-applications-dims">
- <use xlink:href="icons.svg#applications"></use>
- </svg>
-
- </div>
- <h2>applications</h2>
- </li>
- <li title="approval">
- <div class="icon-box">
-
- <!-- approval -->
- <svg class="svg-approval-dims">
- <use xlink:href="icons.svg#approval"></use>
- </svg>
-
- </div>
- <h2>approval</h2>
- </li>
- <li title="arrow-right">
- <div class="icon-box">
-
- <!-- arrow-right -->
- <svg class="svg-arrow-right-dims">
- <use xlink:href="icons.svg#arrow-right"></use>
- </svg>
-
- </div>
- <h2>arrow-right</h2>
- </li>
- <li title="assignee">
- <div class="icon-box">
-
- <!-- assignee -->
- <svg class="svg-assignee-dims">
- <use xlink:href="icons.svg#assignee"></use>
- </svg>
-
- </div>
- <h2>assignee</h2>
- </li>
- <li title="bold">
- <div class="icon-box">
-
- <!-- bold -->
- <svg class="svg-bold-dims">
- <use xlink:href="icons.svg#bold"></use>
- </svg>
-
- </div>
- <h2>bold</h2>
- </li>
- <li title="book">
- <div class="icon-box">
-
- <!-- book -->
- <svg class="svg-book-dims">
- <use xlink:href="icons.svg#book"></use>
- </svg>
-
- </div>
- <h2>book</h2>
- </li>
- <li title="branch">
- <div class="icon-box">
-
- <!-- branch -->
- <svg class="svg-branch-dims">
- <use xlink:href="icons.svg#branch"></use>
- </svg>
-
- </div>
- <h2>branch</h2>
- </li>
- <li title="calendar">
- <div class="icon-box">
-
- <!-- calendar -->
- <svg class="svg-calendar-dims">
- <use xlink:href="icons.svg#calendar"></use>
- </svg>
-
- </div>
- <h2>calendar</h2>
- </li>
- <li title="cancel">
- <div class="icon-box">
-
- <!-- cancel -->
- <svg class="svg-cancel-dims">
- <use xlink:href="icons.svg#cancel"></use>
- </svg>
-
- </div>
- <h2>cancel</h2>
- </li>
- <li title="chevron-down">
- <div class="icon-box">
-
- <!-- chevron-down -->
- <svg class="svg-chevron-down-dims">
- <use xlink:href="icons.svg#chevron-down"></use>
- </svg>
-
- </div>
- <h2>chevron-down</h2>
- </li>
- <li title="chevron-left">
- <div class="icon-box">
-
- <!-- chevron-left -->
- <svg class="svg-chevron-left-dims">
- <use xlink:href="icons.svg#chevron-left"></use>
- </svg>
-
- </div>
- <h2>chevron-left</h2>
- </li>
- <li title="chevron-right">
- <div class="icon-box">
-
- <!-- chevron-right -->
- <svg class="svg-chevron-right-dims">
- <use xlink:href="icons.svg#chevron-right"></use>
- </svg>
-
- </div>
- <h2>chevron-right</h2>
- </li>
- <li title="chevron-up">
- <div class="icon-box">
-
- <!-- chevron-up -->
- <svg class="svg-chevron-up-dims">
- <use xlink:href="icons.svg#chevron-up"></use>
- </svg>
-
- </div>
- <h2>chevron-up</h2>
- </li>
- <li title="clock">
- <div class="icon-box">
-
- <!-- clock -->
- <svg class="svg-clock-dims">
- <use xlink:href="icons.svg#clock"></use>
- </svg>
-
- </div>
- <h2>clock</h2>
- </li>
- <li title="code">
- <div class="icon-box">
-
- <!-- code -->
- <svg class="svg-code-dims">
- <use xlink:href="icons.svg#code"></use>
- </svg>
-
- </div>
- <h2>code</h2>
- </li>
- <li title="comment">
- <div class="icon-box">
-
- <!-- comment -->
- <svg class="svg-comment-dims">
- <use xlink:href="icons.svg#comment"></use>
- </svg>
-
- </div>
- <h2>comment</h2>
- </li>
- <li title="comment-dots">
- <div class="icon-box">
-
- <!-- comment-dots -->
- <svg class="svg-comment-dots-dims">
- <use xlink:href="icons.svg#comment-dots"></use>
- </svg>
-
- </div>
- <h2>comment-dots</h2>
- </li>
- <li title="comment-next">
- <div class="icon-box">
-
- <!-- comment-next -->
- <svg class="svg-comment-next-dims">
- <use xlink:href="icons.svg#comment-next"></use>
- </svg>
-
- </div>
- <h2>comment-next</h2>
- </li>
- <li title="comments">
- <div class="icon-box">
-
- <!-- comments -->
- <svg class="svg-comments-dims">
- <use xlink:href="icons.svg#comments"></use>
- </svg>
-
- </div>
- <h2>comments</h2>
- </li>
- <li title="commit">
- <div class="icon-box">
-
- <!-- commit -->
- <svg class="svg-commit-dims">
- <use xlink:href="icons.svg#commit"></use>
- </svg>
-
- </div>
- <h2>commit</h2>
- </li>
- <li title="credit-card">
- <div class="icon-box">
-
- <!-- credit-card -->
- <svg class="svg-credit-card-dims">
- <use xlink:href="icons.svg#credit-card"></use>
- </svg>
-
- </div>
- <h2>credit-card</h2>
- </li>
- <li title="disk">
- <div class="icon-box">
-
- <!-- disk -->
- <svg class="svg-disk-dims">
- <use xlink:href="icons.svg#disk"></use>
- </svg>
-
- </div>
- <h2>disk</h2>
- </li>
- <li title="doc_code">
- <div class="icon-box">
-
- <!-- doc_code -->
- <svg class="svg-doc_code-dims">
- <use xlink:href="icons.svg#doc_code"></use>
- </svg>
-
- </div>
- <h2>doc_code</h2>
- </li>
- <li title="doc_image">
- <div class="icon-box">
-
- <!-- doc_image -->
- <svg class="svg-doc_image-dims">
- <use xlink:href="icons.svg#doc_image"></use>
- </svg>
-
- </div>
- <h2>doc_image</h2>
- </li>
- <li title="doc_text">
- <div class="icon-box">
-
- <!-- doc_text -->
- <svg class="svg-doc_text-dims">
- <use xlink:href="icons.svg#doc_text"></use>
- </svg>
-
- </div>
- <h2>doc_text</h2>
- </li>
- <li title="download">
- <div class="icon-box">
-
- <!-- download -->
- <svg class="svg-download-dims">
- <use xlink:href="icons.svg#download"></use>
- </svg>
-
- </div>
- <h2>download</h2>
- </li>
- <li title="duplicate">
- <div class="icon-box">
-
- <!-- duplicate -->
- <svg class="svg-duplicate-dims">
- <use xlink:href="icons.svg#duplicate"></use>
- </svg>
-
- </div>
- <h2>duplicate</h2>
- </li>
- <li title="earth">
- <div class="icon-box">
-
- <!-- earth -->
- <svg class="svg-earth-dims">
- <use xlink:href="icons.svg#earth"></use>
- </svg>
-
- </div>
- <h2>earth</h2>
- </li>
- <li title="eye">
- <div class="icon-box">
-
- <!-- eye -->
- <svg class="svg-eye-dims">
- <use xlink:href="icons.svg#eye"></use>
- </svg>
-
- </div>
- <h2>eye</h2>
- </li>
- <li title="eye-slash">
- <div class="icon-box">
-
- <!-- eye-slash -->
- <svg class="svg-eye-slash-dims">
- <use xlink:href="icons.svg#eye-slash"></use>
- </svg>
-
- </div>
- <h2>eye-slash</h2>
- </li>
- <li title="file-additions">
- <div class="icon-box">
-
- <!-- file-additions -->
- <svg class="svg-file-additions-dims">
- <use xlink:href="icons.svg#file-additions"></use>
- </svg>
-
- </div>
- <h2>file-additions</h2>
- </li>
- <li title="file-deletion">
- <div class="icon-box">
-
- <!-- file-deletion -->
- <svg class="svg-file-deletion-dims">
- <use xlink:href="icons.svg#file-deletion"></use>
- </svg>
-
- </div>
- <h2>file-deletion</h2>
- </li>
- <li title="file-modified">
- <div class="icon-box">
-
- <!-- file-modified -->
- <svg class="svg-file-modified-dims">
- <use xlink:href="icons.svg#file-modified"></use>
- </svg>
-
- </div>
- <h2>file-modified</h2>
- </li>
- <li title="filter">
- <div class="icon-box">
-
- <!-- filter -->
- <svg class="svg-filter-dims">
- <use xlink:href="icons.svg#filter"></use>
- </svg>
-
- </div>
- <h2>filter</h2>
- </li>
- <li title="folder">
- <div class="icon-box">
-
- <!-- folder -->
- <svg class="svg-folder-dims">
- <use xlink:href="icons.svg#folder"></use>
- </svg>
-
- </div>
- <h2>folder</h2>
- </li>
- <li title="fork">
- <div class="icon-box">
-
- <!-- fork -->
- <svg class="svg-fork-dims">
- <use xlink:href="icons.svg#fork"></use>
- </svg>
-
- </div>
- <h2>fork</h2>
- </li>
- <li title="git-merge">
- <div class="icon-box">
-
- <!-- git-merge -->
- <svg class="svg-git-merge-dims">
- <use xlink:href="icons.svg#git-merge"></use>
- </svg>
-
- </div>
- <h2>git-merge</h2>
- </li>
- <li title="group">
- <div class="icon-box">
-
- <!-- group -->
- <svg class="svg-group-dims">
- <use xlink:href="icons.svg#group"></use>
- </svg>
-
- </div>
- <h2>group</h2>
- </li>
- <li title="history">
- <div class="icon-box">
-
- <!-- history -->
- <svg class="svg-history-dims">
- <use xlink:href="icons.svg#history"></use>
- </svg>
-
- </div>
- <h2>history</h2>
- </li>
- <li title="home">
- <div class="icon-box">
-
- <!-- home -->
- <svg class="svg-home-dims">
- <use xlink:href="icons.svg#home"></use>
- </svg>
-
- </div>
- <h2>home</h2>
- </li>
- <li title="hook">
- <div class="icon-box">
-
- <!-- hook -->
- <svg class="svg-hook-dims">
- <use xlink:href="icons.svg#hook"></use>
- </svg>
-
- </div>
- <h2>hook</h2>
- </li>
- <li title="issue-block">
- <div class="icon-box">
-
- <!-- issue-block -->
- <svg class="svg-issue-block-dims">
- <use xlink:href="icons.svg#issue-block"></use>
- </svg>
-
- </div>
- <h2>issue-block</h2>
- </li>
- <li title="issue-child">
- <div class="icon-box">
-
- <!-- issue-child -->
- <svg class="svg-issue-child-dims">
- <use xlink:href="icons.svg#issue-child"></use>
- </svg>
-
- </div>
- <h2>issue-child</h2>
- </li>
- <li title="issue-close">
- <div class="icon-box">
-
- <!-- issue-close -->
- <svg class="svg-issue-close-dims">
- <use xlink:href="icons.svg#issue-close"></use>
- </svg>
-
- </div>
- <h2>issue-close</h2>
- </li>
- <li title="issue-duplicate">
- <div class="icon-box">
-
- <!-- issue-duplicate -->
- <svg class="svg-issue-duplicate-dims">
- <use xlink:href="icons.svg#issue-duplicate"></use>
- </svg>
-
- </div>
- <h2>issue-duplicate</h2>
- </li>
- <li title="issue-new">
- <div class="icon-box">
-
- <!-- issue-new -->
- <svg class="svg-issue-new-dims">
- <use xlink:href="icons.svg#issue-new"></use>
- </svg>
-
- </div>
- <h2>issue-new</h2>
- </li>
- <li title="issue-open">
- <div class="icon-box">
-
- <!-- issue-open -->
- <svg class="svg-issue-open-dims">
- <use xlink:href="icons.svg#issue-open"></use>
- </svg>
-
- </div>
- <h2>issue-open</h2>
- </li>
- <li title="issue-open-m">
- <div class="icon-box">
-
- <!-- issue-open-m -->
- <svg class="svg-issue-open-m-dims">
- <use xlink:href="icons.svg#issue-open-m"></use>
- </svg>
-
- </div>
- <h2>issue-open-m</h2>
- </li>
- <li title="issue-parent">
- <div class="icon-box">
-
- <!-- issue-parent -->
- <svg class="svg-issue-parent-dims">
- <use xlink:href="icons.svg#issue-parent"></use>
- </svg>
-
- </div>
- <h2>issue-parent</h2>
- </li>
- <li title="issues">
- <div class="icon-box">
-
- <!-- issues -->
- <svg class="svg-issues-dims">
- <use xlink:href="icons.svg#issues"></use>
- </svg>
-
- </div>
- <h2>issues</h2>
- </li>
- <li title="key">
- <div class="icon-box">
-
- <!-- key -->
- <svg class="svg-key-dims">
- <use xlink:href="icons.svg#key"></use>
- </svg>
-
- </div>
- <h2>key</h2>
- </li>
- <li title="key-2">
- <div class="icon-box">
-
- <!-- key-2 -->
- <svg class="svg-key-2-dims">
- <use xlink:href="icons.svg#key-2"></use>
- </svg>
-
- </div>
- <h2>key-2</h2>
- </li>
- <li title="label">
- <div class="icon-box">
-
- <!-- label -->
- <svg class="svg-label-dims">
- <use xlink:href="icons.svg#label"></use>
- </svg>
-
- </div>
- <h2>label</h2>
- </li>
- <li title="labels">
- <div class="icon-box">
-
- <!-- labels -->
- <svg class="svg-labels-dims">
- <use xlink:href="icons.svg#labels"></use>
- </svg>
-
- </div>
- <h2>labels</h2>
- </li>
- <li title="leave">
- <div class="icon-box">
-
- <!-- leave -->
- <svg class="svg-leave-dims">
- <use xlink:href="icons.svg#leave"></use>
- </svg>
-
- </div>
- <h2>leave</h2>
- </li>
- <li title="level-up">
- <div class="icon-box">
-
- <!-- level-up -->
- <svg class="svg-level-up-dims">
- <use xlink:href="icons.svg#level-up"></use>
- </svg>
-
- </div>
- <h2>level-up</h2>
- </li>
- <li title="license">
- <div class="icon-box">
-
- <!-- license -->
- <svg class="svg-license-dims">
- <use xlink:href="icons.svg#license"></use>
- </svg>
-
- </div>
- <h2>license</h2>
- </li>
- <li title="link">
- <div class="icon-box">
-
- <!-- link -->
- <svg class="svg-link-dims">
- <use xlink:href="icons.svg#link"></use>
- </svg>
-
- </div>
- <h2>link</h2>
- </li>
- <li title="list-bulleted">
- <div class="icon-box">
-
- <!-- list-bulleted -->
- <svg class="svg-list-bulleted-dims">
- <use xlink:href="icons.svg#list-bulleted"></use>
- </svg>
-
- </div>
- <h2>list-bulleted</h2>
- </li>
- <li title="list-numbered">
- <div class="icon-box">
-
- <!-- list-numbered -->
- <svg class="svg-list-numbered-dims">
- <use xlink:href="icons.svg#list-numbered"></use>
- </svg>
-
- </div>
- <h2>list-numbered</h2>
- </li>
- <li title="location">
- <div class="icon-box">
-
- <!-- location -->
- <svg class="svg-location-dims">
- <use xlink:href="icons.svg#location"></use>
- </svg>
-
- </div>
- <h2>location</h2>
- </li>
- <li title="location-dot">
- <div class="icon-box">
-
- <!-- location-dot -->
- <svg class="svg-location-dot-dims">
- <use xlink:href="icons.svg#location-dot"></use>
- </svg>
-
- </div>
- <h2>location-dot</h2>
- </li>
- <li title="lock">
- <div class="icon-box">
-
- <!-- lock -->
- <svg class="svg-lock-dims">
- <use xlink:href="icons.svg#lock"></use>
- </svg>
-
- </div>
- <h2>lock</h2>
- </li>
- <li title="lock-open">
- <div class="icon-box">
-
- <!-- lock-open -->
- <svg class="svg-lock-open-dims">
- <use xlink:href="icons.svg#lock-open"></use>
- </svg>
-
- </div>
- <h2>lock-open</h2>
- </li>
- <li title="log">
- <div class="icon-box">
-
- <!-- log -->
- <svg class="svg-log-dims">
- <use xlink:href="icons.svg#log"></use>
- </svg>
-
- </div>
- <h2>log</h2>
- </li>
- <li title="mail">
- <div class="icon-box">
-
- <!-- mail -->
- <svg class="svg-mail-dims">
- <use xlink:href="icons.svg#mail"></use>
- </svg>
-
- </div>
- <h2>mail</h2>
- </li>
- <li title="merge-request-close">
- <div class="icon-box">
-
- <!-- merge-request-close -->
- <svg class="svg-merge-request-close-dims">
- <use xlink:href="icons.svg#merge-request-close"></use>
- </svg>
-
- </div>
- <h2>merge-request-close</h2>
- </li>
- <li title="merge-request-close-m">
- <div class="icon-box">
-
- <!-- merge-request-close-m -->
- <svg class="svg-merge-request-close-m-dims">
- <use xlink:href="icons.svg#merge-request-close-m"></use>
- </svg>
-
- </div>
- <h2>merge-request-close-m</h2>
- </li>
- <li title="messages">
- <div class="icon-box">
-
- <!-- messages -->
- <svg class="svg-messages-dims">
- <use xlink:href="icons.svg#messages"></use>
- </svg>
-
- </div>
- <h2>messages</h2>
- </li>
- <li title="mobile-issue-close">
- <div class="icon-box">
-
- <!-- mobile-issue-close -->
- <svg class="svg-mobile-issue-close-dims">
- <use xlink:href="icons.svg#mobile-issue-close"></use>
- </svg>
-
- </div>
- <h2>mobile-issue-close</h2>
- </li>
- <li title="monitor">
- <div class="icon-box">
-
- <!-- monitor -->
- <svg class="svg-monitor-dims">
- <use xlink:href="icons.svg#monitor"></use>
- </svg>
-
- </div>
- <h2>monitor</h2>
- </li>
- <li title="more">
- <div class="icon-box">
-
- <!-- more -->
- <svg class="svg-more-dims">
- <use xlink:href="icons.svg#more"></use>
- </svg>
-
- </div>
- <h2>more</h2>
- </li>
- <li title="notifications">
- <div class="icon-box">
-
- <!-- notifications -->
- <svg class="svg-notifications-dims">
- <use xlink:href="icons.svg#notifications"></use>
- </svg>
-
- </div>
- <h2>notifications</h2>
- </li>
- <li title="notifications-off">
- <div class="icon-box">
-
- <!-- notifications-off -->
- <svg class="svg-notifications-off-dims">
- <use xlink:href="icons.svg#notifications-off"></use>
- </svg>
-
- </div>
- <h2>notifications-off</h2>
- </li>
- <li title="overview">
- <div class="icon-box">
-
- <!-- overview -->
- <svg class="svg-overview-dims">
- <use xlink:href="icons.svg#overview"></use>
- </svg>
-
- </div>
- <h2>overview</h2>
- </li>
- <li title="pencil">
- <div class="icon-box">
-
- <!-- pencil -->
- <svg class="svg-pencil-dims">
- <use xlink:href="icons.svg#pencil"></use>
- </svg>
-
- </div>
- <h2>pencil</h2>
- </li>
- <li title="pipeline">
- <div class="icon-box">
-
- <!-- pipeline -->
- <svg class="svg-pipeline-dims">
- <use xlink:href="icons.svg#pipeline"></use>
- </svg>
-
- </div>
- <h2>pipeline</h2>
- </li>
- <li title="play">
- <div class="icon-box">
-
- <!-- play -->
- <svg class="svg-play-dims">
- <use xlink:href="icons.svg#play"></use>
- </svg>
-
- </div>
- <h2>play</h2>
- </li>
- <li title="plus">
- <div class="icon-box">
-
- <!-- plus -->
- <svg class="svg-plus-dims">
- <use xlink:href="icons.svg#plus"></use>
- </svg>
-
- </div>
- <h2>plus</h2>
- </li>
- <li title="plus-square">
- <div class="icon-box">
-
- <!-- plus-square -->
- <svg class="svg-plus-square-dims">
- <use xlink:href="icons.svg#plus-square"></use>
- </svg>
-
- </div>
- <h2>plus-square</h2>
- </li>
- <li title="plus-square-o">
- <div class="icon-box">
-
- <!-- plus-square-o -->
- <svg class="svg-plus-square-o-dims">
- <use xlink:href="icons.svg#plus-square-o"></use>
- </svg>
-
- </div>
- <h2>plus-square-o</h2>
- </li>
- <li title="preferences">
- <div class="icon-box">
-
- <!-- preferences -->
- <svg class="svg-preferences-dims">
- <use xlink:href="icons.svg#preferences"></use>
- </svg>
-
- </div>
- <h2>preferences</h2>
- </li>
- <li title="profile">
- <div class="icon-box">
-
- <!-- profile -->
- <svg class="svg-profile-dims">
- <use xlink:href="icons.svg#profile"></use>
- </svg>
-
- </div>
- <h2>profile</h2>
- </li>
- <li title="project">
- <div class="icon-box">
-
- <!-- project -->
- <svg class="svg-project-dims">
- <use xlink:href="icons.svg#project"></use>
- </svg>
-
- </div>
- <h2>project</h2>
- </li>
- <li title="push-rules">
- <div class="icon-box">
-
- <!-- push-rules -->
- <svg class="svg-push-rules-dims">
- <use xlink:href="icons.svg#push-rules"></use>
- </svg>
-
- </div>
- <h2>push-rules</h2>
- </li>
- <li title="question">
- <div class="icon-box">
-
- <!-- question -->
- <svg class="svg-question-dims">
- <use xlink:href="icons.svg#question"></use>
- </svg>
-
- </div>
- <h2>question</h2>
- </li>
- <li title="question-o">
- <div class="icon-box">
-
- <!-- question-o -->
- <svg class="svg-question-o-dims">
- <use xlink:href="icons.svg#question-o"></use>
- </svg>
-
- </div>
- <h2>question-o</h2>
- </li>
- <li title="quote">
- <div class="icon-box">
-
- <!-- quote -->
- <svg class="svg-quote-dims">
- <use xlink:href="icons.svg#quote"></use>
- </svg>
-
- </div>
- <h2>quote</h2>
- </li>
- <li title="redo">
- <div class="icon-box">
-
- <!-- redo -->
- <svg class="svg-redo-dims">
- <use xlink:href="icons.svg#redo"></use>
- </svg>
-
- </div>
- <h2>redo</h2>
- </li>
- <li title="remove">
- <div class="icon-box">
-
- <!-- remove -->
- <svg class="svg-remove-dims">
- <use xlink:href="icons.svg#remove"></use>
- </svg>
-
- </div>
- <h2>remove</h2>
- </li>
- <li title="repeat">
- <div class="icon-box">
-
- <!-- repeat -->
- <svg class="svg-repeat-dims">
- <use xlink:href="icons.svg#repeat"></use>
- </svg>
-
- </div>
- <h2>repeat</h2>
- </li>
- <li title="retry">
- <div class="icon-box">
-
- <!-- retry -->
- <svg class="svg-retry-dims">
- <use xlink:href="icons.svg#retry"></use>
- </svg>
-
- </div>
- <h2>retry</h2>
- </li>
- <li title="scale">
- <div class="icon-box">
-
- <!-- scale -->
- <svg class="svg-scale-dims">
- <use xlink:href="icons.svg#scale"></use>
- </svg>
-
- </div>
- <h2>scale</h2>
- </li>
- <li title="screen-full">
- <div class="icon-box">
-
- <!-- screen-full -->
- <svg class="svg-screen-full-dims">
- <use xlink:href="icons.svg#screen-full"></use>
- </svg>
-
- </div>
- <h2>screen-full</h2>
- </li>
- <li title="screen-normal">
- <div class="icon-box">
-
- <!-- screen-normal -->
- <svg class="svg-screen-normal-dims">
- <use xlink:href="icons.svg#screen-normal"></use>
- </svg>
-
- </div>
- <h2>screen-normal</h2>
- </li>
- <li title="search">
- <div class="icon-box">
-
- <!-- search -->
- <svg class="svg-search-dims">
- <use xlink:href="icons.svg#search"></use>
- </svg>
-
- </div>
- <h2>search</h2>
- </li>
- <li title="settings">
- <div class="icon-box">
-
- <!-- settings -->
- <svg class="svg-settings-dims">
- <use xlink:href="icons.svg#settings"></use>
- </svg>
-
- </div>
- <h2>settings</h2>
- </li>
- <li title="shield">
- <div class="icon-box">
-
- <!-- shield -->
- <svg class="svg-shield-dims">
- <use xlink:href="icons.svg#shield"></use>
- </svg>
-
- </div>
- <h2>shield</h2>
- </li>
- <li title="slight-frown">
- <div class="icon-box">
-
- <!-- slight-frown -->
- <svg class="svg-slight-frown-dims">
- <use xlink:href="icons.svg#slight-frown"></use>
- </svg>
-
- </div>
- <h2>slight-frown</h2>
- </li>
- <li title="slight-smile">
- <div class="icon-box">
-
- <!-- slight-smile -->
- <svg class="svg-slight-smile-dims">
- <use xlink:href="icons.svg#slight-smile"></use>
- </svg>
-
- </div>
- <h2>slight-smile</h2>
- </li>
- <li title="smile">
- <div class="icon-box">
-
- <!-- smile -->
- <svg class="svg-smile-dims">
- <use xlink:href="icons.svg#smile"></use>
- </svg>
-
- </div>
- <h2>smile</h2>
- </li>
- <li title="smiley">
- <div class="icon-box">
-
- <!-- smiley -->
- <svg class="svg-smiley-dims">
- <use xlink:href="icons.svg#smiley"></use>
- </svg>
-
- </div>
- <h2>smiley</h2>
- </li>
- <li title="snippet">
- <div class="icon-box">
-
- <!-- snippet -->
- <svg class="svg-snippet-dims">
- <use xlink:href="icons.svg#snippet"></use>
- </svg>
-
- </div>
- <h2>snippet</h2>
- </li>
- <li title="spam">
- <div class="icon-box">
-
- <!-- spam -->
- <svg class="svg-spam-dims">
- <use xlink:href="icons.svg#spam"></use>
- </svg>
-
- </div>
- <h2>spam</h2>
- </li>
- <li title="star">
- <div class="icon-box">
-
- <!-- star -->
- <svg class="svg-star-dims">
- <use xlink:href="icons.svg#star"></use>
- </svg>
-
- </div>
- <h2>star</h2>
- </li>
- <li title="star-o">
- <div class="icon-box">
-
- <!-- star-o -->
- <svg class="svg-star-o-dims">
- <use xlink:href="icons.svg#star-o"></use>
- </svg>
-
- </div>
- <h2>star-o</h2>
- </li>
- <li title="stop">
- <div class="icon-box">
-
- <!-- stop -->
- <svg class="svg-stop-dims">
- <use xlink:href="icons.svg#stop"></use>
- </svg>
-
- </div>
- <h2>stop</h2>
- </li>
- <li title="talic">
- <div class="icon-box">
-
- <!-- talic -->
- <svg class="svg-talic-dims">
- <use xlink:href="icons.svg#talic"></use>
- </svg>
-
- </div>
- <h2>talic</h2>
- </li>
- <li title="task-done">
- <div class="icon-box">
-
- <!-- task-done -->
- <svg class="svg-task-done-dims">
- <use xlink:href="icons.svg#task-done"></use>
- </svg>
-
- </div>
- <h2>task-done</h2>
- </li>
- <li title="template">
- <div class="icon-box">
-
- <!-- template -->
- <svg class="svg-template-dims">
- <use xlink:href="icons.svg#template"></use>
- </svg>
-
- </div>
- <h2>template</h2>
- </li>
- <li title="thump-down">
- <div class="icon-box">
-
- <!-- thump-down -->
- <svg class="svg-thump-down-dims">
- <use xlink:href="icons.svg#thump-down"></use>
- </svg>
-
- </div>
- <h2>thump-down</h2>
- </li>
- <li title="thump-up">
- <div class="icon-box">
-
- <!-- thump-up -->
- <svg class="svg-thump-up-dims">
- <use xlink:href="icons.svg#thump-up"></use>
- </svg>
-
- </div>
- <h2>thump-up</h2>
- </li>
- <li title="timer">
- <div class="icon-box">
-
- <!-- timer -->
- <svg class="svg-timer-dims">
- <use xlink:href="icons.svg#timer"></use>
- </svg>
-
- </div>
- <h2>timer</h2>
- </li>
- <li title="todo-add">
- <div class="icon-box">
-
- <!-- todo-add -->
- <svg class="svg-todo-add-dims">
- <use xlink:href="icons.svg#todo-add"></use>
- </svg>
-
- </div>
- <h2>todo-add</h2>
- </li>
- <li title="todo-done">
- <div class="icon-box">
-
- <!-- todo-done -->
- <svg class="svg-todo-done-dims">
- <use xlink:href="icons.svg#todo-done"></use>
- </svg>
-
- </div>
- <h2>todo-done</h2>
- </li>
- <li title="token">
- <div class="icon-box">
-
- <!-- token -->
- <svg class="svg-token-dims">
- <use xlink:href="icons.svg#token"></use>
- </svg>
-
- </div>
- <h2>token</h2>
- </li>
- <li title="unapproval">
- <div class="icon-box">
-
- <!-- unapproval -->
- <svg class="svg-unapproval-dims">
- <use xlink:href="icons.svg#unapproval"></use>
- </svg>
-
- </div>
- <h2>unapproval</h2>
- </li>
- <li title="unassignee">
- <div class="icon-box">
-
- <!-- unassignee -->
- <svg class="svg-unassignee-dims">
- <use xlink:href="icons.svg#unassignee"></use>
- </svg>
-
- </div>
- <h2>unassignee</h2>
- </li>
- <li title="unlink">
- <div class="icon-box">
-
- <!-- unlink -->
- <svg class="svg-unlink-dims">
- <use xlink:href="icons.svg#unlink"></use>
- </svg>
-
- </div>
- <h2>unlink</h2>
- </li>
- <li title="user">
- <div class="icon-box">
-
- <!-- user -->
- <svg class="svg-user-dims">
- <use xlink:href="icons.svg#user"></use>
- </svg>
-
- </div>
- <h2>user</h2>
- </li>
- <li title="users">
- <div class="icon-box">
-
- <!-- users -->
- <svg class="svg-users-dims">
- <use xlink:href="icons.svg#users"></use>
- </svg>
-
- </div>
- <h2>users</h2>
- </li>
- <li title="volume-up">
- <div class="icon-box">
-
- <!-- volume-up -->
- <svg class="svg-volume-up-dims">
- <use xlink:href="icons.svg#volume-up"></use>
- </svg>
-
- </div>
- <h2>volume-up</h2>
- </li>
- <li title="warning">
- <div class="icon-box">
-
- <!-- warning -->
- <svg class="svg-warning-dims">
- <use xlink:href="icons.svg#warning"></use>
- </svg>
-
- </div>
- <h2>warning</h2>
- </li>
- <li title="work">
- <div class="icon-box">
-
- <!-- work -->
- <svg class="svg-work-dims">
- <use xlink:href="icons.svg#work"></use>
- </svg>
-
- </div>
- <h2>work</h2>
- </li>
- </ul>
-
-<!--
-====================================================================================================
--->
-
- </section>
- <footer>
- <p>Generated at Tue, 12 Sep 2017 09:08:46 GMT by <a href="https://github.com/jkphl/svg-sprite" target="_blank">svg-sprite</a>.</p>
- </footer>
- </body>
-</html>
diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js
index 286a758b8a9..3d27a3544eb 100644
--- a/app/assets/javascripts/build.js
+++ b/app/assets/javascripts/build.js
@@ -167,7 +167,7 @@ window.Build = (function () {
Build.prototype.getBuildTrace = function () {
return $.ajax({
url: `${this.pageUrl}/trace.json`,
- data: this.state,
+ data: { state: this.state },
})
.done((log) => {
setCiStatusFavicon(`${this.pageUrl}/status.json`);
diff --git a/app/assets/javascripts/copy_as_gfm.js b/app/assets/javascripts/copy_as_gfm.js
index e3e2c798570..93b0cbf4209 100644
--- a/app/assets/javascripts/copy_as_gfm.js
+++ b/app/assets/javascripts/copy_as_gfm.js
@@ -298,7 +298,7 @@ class CopyAsGFM {
const documentFragment = getSelectedFragment();
if (!documentFragment) return;
- const el = transformer(documentFragment.cloneNode(true));
+ const el = transformer(documentFragment.cloneNode(true), e.currentTarget);
if (!el) return;
e.preventDefault();
@@ -338,55 +338,64 @@ class CopyAsGFM {
}
static transformGFMSelection(documentFragment) {
- const gfmEls = documentFragment.querySelectorAll('.md, .wiki');
- switch (gfmEls.length) {
+ const gfmElements = documentFragment.querySelectorAll('.md, .wiki');
+ switch (gfmElements.length) {
case 0: {
return documentFragment;
}
case 1: {
- return gfmEls[0];
+ return gfmElements[0];
}
default: {
- const allGfmEl = document.createElement('div');
+ const allGfmElement = document.createElement('div');
- for (let i = 0; i < gfmEls.length; i += 1) {
- const lineEl = gfmEls[i];
- allGfmEl.appendChild(lineEl);
- allGfmEl.appendChild(document.createTextNode('\n\n'));
+ for (let i = 0; i < gfmElements.length; i += 1) {
+ const gfmElement = gfmElements[i];
+ allGfmElement.appendChild(gfmElement);
+ allGfmElement.appendChild(document.createTextNode('\n\n'));
}
- return allGfmEl;
+ return allGfmElement;
}
}
}
- static transformCodeSelection(documentFragment) {
- const lineEls = documentFragment.querySelectorAll('.line');
+ static transformCodeSelection(documentFragment, target) {
+ let lineSelector = '.line';
- let codeEl;
- if (lineEls.length > 1) {
- codeEl = document.createElement('pre');
- codeEl.className = 'code highlight';
+ if (target) {
+ const lineClass = ['left-side', 'right-side'].filter(name => target.classList.contains(name))[0];
+ if (lineClass) {
+ lineSelector = `.line_content.${lineClass} ${lineSelector}`;
+ }
+ }
+
+ const lineElements = documentFragment.querySelectorAll(lineSelector);
+
+ let codeElement;
+ if (lineElements.length > 1) {
+ codeElement = document.createElement('pre');
+ codeElement.className = 'code highlight';
- const lang = lineEls[0].getAttribute('lang');
+ const lang = lineElements[0].getAttribute('lang');
if (lang) {
- codeEl.setAttribute('lang', lang);
+ codeElement.setAttribute('lang', lang);
}
} else {
- codeEl = document.createElement('code');
+ codeElement = document.createElement('code');
}
- if (lineEls.length > 0) {
- for (let i = 0; i < lineEls.length; i += 1) {
- const lineEl = lineEls[i];
- codeEl.appendChild(lineEl);
- codeEl.appendChild(document.createTextNode('\n'));
+ if (lineElements.length > 0) {
+ for (let i = 0; i < lineElements.length; i += 1) {
+ const lineElement = lineElements[i];
+ codeElement.appendChild(lineElement);
+ codeElement.appendChild(document.createTextNode('\n'));
}
} else {
- codeEl.appendChild(documentFragment);
+ codeElement.appendChild(documentFragment);
}
- return codeEl;
+ return codeElement;
}
static nodeToGFM(node, respectWhitespaceParam = false) {
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
index e4d62b649e5..45930145b0a 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
@@ -1,5 +1,7 @@
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+ import limitWarning from './limit_warning_component.vue';
+ import totalTime from './total_time_component.vue';
export default {
props: {
@@ -8,6 +10,8 @@
},
components: {
userAvatarImage,
+ limitWarning,
+ totalTime,
},
};
</script>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
index ab730af8f5b..8c98bd249a1 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
@@ -1,5 +1,7 @@
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+ import limitWarning from './limit_warning_component.vue';
+ import totalTime from './total_time_component.vue';
export default {
props: {
@@ -8,6 +10,8 @@
},
components: {
userAvatarImage,
+ limitWarning,
+ totalTime,
},
};
</script>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
index 152c086a606..75d2f1fd70c 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
@@ -1,21 +1,25 @@
<script>
-import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
-import iconCommit from '../svg/icon_commit.svg';
+ import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+ import iconCommit from '../svg/icon_commit.svg';
+ import limitWarning from './limit_warning_component.vue';
+ import totalTime from './total_time_component.vue';
-export default {
- props: {
- items: Array,
- stage: Object,
- },
- components: {
- userAvatarImage,
- },
- computed: {
- iconCommit() {
- return iconCommit;
+ export default {
+ props: {
+ items: Array,
+ stage: Object,
},
- },
-};
+ components: {
+ userAvatarImage,
+ totalTime,
+ limitWarning,
+ },
+ computed: {
+ iconCommit() {
+ return iconCommit;
+ },
+ },
+ };
</script>
<template>
<div>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
index 9e66b690404..f54ea7df522 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
@@ -1,5 +1,7 @@
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+ import limitWarning from './limit_warning_component.vue';
+ import totalTime from './total_time_component.vue';
export default {
props: {
@@ -8,6 +10,8 @@
},
components: {
userAvatarImage,
+ totalTime,
+ limitWarning,
},
};
</script>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
index 2787b5ea47b..5d95ddcd90e 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
@@ -1,6 +1,8 @@
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
import iconBranch from '../svg/icon_branch.svg';
+ import limitWarning from './limit_warning_component.vue';
+ import totalTime from './total_time_component.vue';
export default {
props: {
@@ -9,6 +11,8 @@
},
components: {
userAvatarImage,
+ totalTime,
+ limitWarning,
},
computed: {
iconBranch() {
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
index 9c3d39ce011..04d5440b77b 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
@@ -1,21 +1,27 @@
<script>
-import iconBuildStatus from '../svg/icon_build_status.svg';
-import iconBranch from '../svg/icon_branch.svg';
+ import iconBuildStatus from '../svg/icon_build_status.svg';
+ import iconBranch from '../svg/icon_branch.svg';
+ import limitWarning from './limit_warning_component.vue';
+ import totalTime from './total_time_component.vue';
-export default {
- props: {
- items: Array,
- stage: Object,
- },
- computed: {
- iconBuildStatus() {
- return iconBuildStatus;
+ export default {
+ props: {
+ items: Array,
+ stage: Object,
},
- iconBranch() {
- return iconBranch;
+ components: {
+ totalTime,
+ limitWarning,
},
- },
-};
+ computed: {
+ iconBuildStatus() {
+ return iconBuildStatus;
+ },
+ iconBranch() {
+ return iconBranch;
+ },
+ },
+ };
</script>
<template>
<div>
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
index 8002b0b23c9..991fcf114da 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
@@ -3,14 +3,12 @@
import Vue from 'vue';
import Cookies from 'js-cookie';
import Translate from '../vue_shared/translate';
-import limitWarningComponent from './components/limit_warning_component.vue';
import stageCodeComponent from './components/stage_code_component.vue';
import stagePlanComponent from './components/stage_plan_component.vue';
import stageComponent from './components/stage_component.vue';
import stageReviewComponent from './components/stage_review_component.vue';
import stageStagingComponent from './components/stage_staging_component.vue';
import stageTestComponent from './components/stage_test_component.vue';
-import totalTime from './components/total_time_component.vue';
import CycleAnalyticsService from './cycle_analytics_service';
import CycleAnalyticsStore from './cycle_analytics_store';
@@ -133,8 +131,4 @@ $(() => {
},
},
});
-
- // Register global components
- Vue.component('limit-warning', limitWarningComponent);
- Vue.component('total-time', totalTime);
});
diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js
index 6a008112203..ae8338f5fd2 100644
--- a/app/assets/javascripts/diff.js
+++ b/app/assets/javascripts/diff.js
@@ -24,7 +24,8 @@ class Diff {
if (!isBound) {
$(document)
.on('click', '.js-unfold', this.handleClickUnfold.bind(this))
- .on('click', '.diff-line-num a', this.handleClickLineNum.bind(this));
+ .on('click', '.diff-line-num a', this.handleClickLineNum.bind(this))
+ .on('mousedown', 'td.line_content.parallel', this.handleParallelLineDown.bind(this));
isBound = true;
}
@@ -100,6 +101,18 @@ class Diff {
this.highlightSelectedLine();
}
+ handleParallelLineDown(e) {
+ const line = $(e.currentTarget);
+ const table = line.closest('table');
+
+ table.removeClass('left-side-selected right-side-selected');
+
+ const lineClass = ['left-side', 'right-side'].filter(name => line.hasClass(name))[0];
+ if (lineClass) {
+ table.addClass(`${lineClass}-selected`);
+ }
+ }
+
diffViewType() {
return $('.inline-parallel-buttons a.active').data('view-type');
}
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 31214818496..bbaa4e4d91e 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -14,7 +14,6 @@
/* global NotificationsDropdown */
/* global GroupAvatar */
/* global LineHighlighter */
-/* global ProjectFork */
/* global BuildArtifacts */
/* global GroupsSelect */
/* global Search */
@@ -476,7 +475,9 @@ import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
shortcut_handler = true;
break;
case 'projects:forks:new':
- new ProjectFork();
+ import(/* webpackChunkName: 'project_fork' */ './project_fork')
+ .then(fork => fork.default())
+ .catch(() => {});
break;
case 'projects:artifacts:browse':
new ShortcutsNavigation();
diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js
index 50d822eba5a..ff218ccad62 100644
--- a/app/assets/javascripts/gl_dropdown.js
+++ b/app/assets/javascripts/gl_dropdown.js
@@ -548,6 +548,7 @@ GitLabDropdown = (function() {
GitLabDropdown.prototype.positionMenuAbove = function() {
var $menu = this.dropdown.find('.dropdown-menu');
+ $menu.addClass('dropdown-open-top');
$menu.css('top', 'initial');
$menu.css('bottom', '100%');
};
diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js
index 70c364e51fe..1d305f1eb2f 100644
--- a/app/assets/javascripts/issuable_context.js
+++ b/app/assets/javascripts/issuable_context.js
@@ -67,10 +67,13 @@ const PARTICIPANTS_ROW_COUNT = 7;
originalText = $(this).data("original-text");
if (currentText === originalText) {
$(this).text(lessText);
+
+ if (gl.lazyLoader) gl.lazyLoader.loadCheck();
} else {
$(this).text(originalText);
}
- return $(".js-participants-hidden").toggle();
+
+ $(".js-participants-hidden").toggle();
};
return IssuableContext;
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index ea2d61af9be..423a25fbdfa 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -71,6 +71,7 @@ export const handleLocationHash = () => {
// This is required to handle non-unicode characters in hash
hash = decodeURIComponent(hash);
+ const target = document.getElementById(hash) || document.getElementById(`user-content-${hash}`);
const fixedTabs = document.querySelector('.js-tabs-affix');
const fixedDiffStats = document.querySelector('.js-diff-files-changed.is-stuck');
const fixedNav = document.querySelector('.navbar-gitlab');
@@ -78,25 +79,19 @@ export const handleLocationHash = () => {
let adjustment = 0;
if (fixedNav) adjustment -= fixedNav.offsetHeight;
- // scroll to user-generated markdown anchor if we cannot find a match
- if (document.getElementById(hash) === null) {
- const target = document.getElementById(`user-content-${hash}`);
- if (target && target.scrollIntoView) {
- target.scrollIntoView(true);
- window.scrollBy(0, adjustment);
- }
- } else {
- // only adjust for fixedTabs when not targeting user-generated content
- if (fixedTabs) {
- adjustment -= fixedTabs.offsetHeight;
- }
+ if (target && target.scrollIntoView) {
+ target.scrollIntoView(true);
+ }
- if (fixedDiffStats) {
- adjustment -= fixedDiffStats.offsetHeight;
- }
+ if (fixedTabs) {
+ adjustment -= fixedTabs.offsetHeight;
+ }
- window.scrollBy(0, adjustment);
+ if (fixedDiffStats) {
+ adjustment -= fixedDiffStats.offsetHeight;
}
+
+ window.scrollBy(0, adjustment);
};
// Check if element scrolled into viewport from above or below
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index 1d1763c3963..29fc91733b3 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -55,7 +55,7 @@ window.dateFormat = dateFormat;
if (!timeagoInstance) {
const localeRemaining = function(number, index) {
return [
- [s__('Timeago|less than a minute ago'), s__('Timeago|a while')],
+ [s__('Timeago|less than a minute ago'), s__('Timeago|in a while')],
[s__('Timeago|less than a minute ago'), s__('Timeago|%s seconds remaining')],
[s__('Timeago|about a minute ago'), s__('Timeago|1 minute remaining')],
[s__('Timeago|%s minutes ago'), s__('Timeago|%s minutes remaining')],
@@ -73,7 +73,7 @@ window.dateFormat = dateFormat;
};
locale = function(number, index) {
return [
- [s__('Timeago|less than a minute ago'), s__('Timeago|a while')],
+ [s__('Timeago|less than a minute ago'), s__('Timeago|in a while')],
[s__('Timeago|less than a minute ago'), s__('Timeago|in %s seconds')],
[s__('Timeago|about a minute ago'), s__('Timeago|in 1 minute')],
[s__('Timeago|%s minutes ago'), s__('Timeago|in %s minutes')],
diff --git a/app/assets/javascripts/locale/index.js b/app/assets/javascripts/locale/index.js
index 6a5084efeb8..ce05b3eabec 100644
--- a/app/assets/javascripts/locale/index.js
+++ b/app/assets/javascripts/locale/index.js
@@ -1,28 +1,12 @@
import Jed from 'jed';
-
-/**
- This is required to require all the translation folders in the current directory
- this saves us having to do this manually & keep up to date with new languages
-**/
-function requireAll(requireContext) { return requireContext.keys().map(requireContext); }
-
-const allLocales = requireAll(require.context('./', true, /^(?!.*(?:index.js$)).*\.js$/));
-const locales = allLocales.reduce((d, obj) => {
- const data = d;
- const localeKey = Object.keys(obj)[0];
-
- data[localeKey] = obj[localeKey];
-
- return data;
-}, {});
+import sprintf from './sprintf';
const langAttribute = document.querySelector('html').getAttribute('lang');
const lang = (langAttribute || 'en').replace(/-/g, '_');
-const locale = new Jed(locales[lang]);
+const locale = new Jed(window.translations || {});
/**
Translates `text`
-
@param text The text to be translated
@returns {String} The translated text
**/
@@ -66,4 +50,5 @@ export { lang };
export { gettext as __ };
export { ngettext as n__ };
export { pgettext as s__ };
+export { sprintf };
export default locale;
diff --git a/app/assets/javascripts/locale/sprintf.js b/app/assets/javascripts/locale/sprintf.js
new file mode 100644
index 00000000000..5f4a053f98e
--- /dev/null
+++ b/app/assets/javascripts/locale/sprintf.js
@@ -0,0 +1,26 @@
+import _ from 'underscore';
+
+/**
+ Very limited implementation of sprintf supporting only named parameters.
+
+ @param input (translated) text with parameters (e.g. '%{num_users} users use us')
+ @param parameters object mapping parameter names to values (e.g. { num_users: 5 })
+ @param escapeParameters whether parameter values should be escaped (see http://underscorejs.org/#escape)
+ @returns {String} the text with parameters replaces (e.g. '5 users use us')
+
+ @see https://ruby-doc.org/core-2.3.3/Kernel.html#method-i-sprintf
+ @see https://gitlab.com/gitlab-org/gitlab-ce/issues/37992
+**/
+export default (input, parameters, escapeParameters = true) => {
+ let output = input;
+
+ if (parameters) {
+ Object.keys(parameters).forEach((parameterName) => {
+ const parameterValue = parameters[parameterName];
+ const escapedParameterValue = escapeParameters ? _.escape(parameterValue) : parameterValue;
+ output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), escapedParameterValue);
+ });
+ }
+
+ return output;
+};
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 3b8e2c5b2f3..24abc5c5c9e 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -124,7 +124,6 @@ import './preview_markdown';
import './project';
import './project_avatar';
import './project_find_file';
-import './project_fork';
import './project_import';
import './project_label_subscription';
import './project_new';
diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js
index 0db2abe507d..af0658eb668 100644
--- a/app/assets/javascripts/merge_request.js
+++ b/app/assets/javascripts/merge_request.js
@@ -127,6 +127,21 @@ import IssuablesHelper from './helpers/issuables_helper';
$el.text(gl.text.addDelimiter(count));
};
+ MergeRequest.prototype.hideCloseButton = function() {
+ const el = document.querySelector('.merge-request .issuable-actions');
+ const closeDropdownItem = el.querySelector('li.close-item');
+ if (closeDropdownItem) {
+ closeDropdownItem.classList.add('hidden');
+ // Selects the next dropdown item
+ el.querySelector('li.report-item').click();
+ } else {
+ // No dropdown just hide the Close button
+ el.querySelector('.btn-close').classList.add('hidden');
+ }
+ // Dropdown for mobile screen
+ el.querySelector('li.js-close-item').classList.add('hidden');
+ };
+
return MergeRequest;
})();
}).call(window);
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index f80a26b3fd4..442ed86d50c 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -29,6 +29,7 @@
showEmptyState: true,
updateAspectRatio: false,
updatedAspectRatios: 0,
+ hoverData: {},
resizeThrottled: {},
};
},
@@ -64,6 +65,10 @@
this.updatedAspectRatios = 0;
}
},
+
+ hoverChanged(data) {
+ this.hoverData = data;
+ },
},
created() {
@@ -72,10 +77,12 @@
deploymentEndpoint: this.deploymentEndpoint,
});
eventHub.$on('toggleAspectRatio', this.toggleAspectRatio);
+ eventHub.$on('hoverChanged', this.hoverChanged);
},
beforeDestroy() {
eventHub.$off('toggleAspectRatio', this.toggleAspectRatio);
+ eventHub.$off('hoverChanged', this.hoverChanged);
window.removeEventListener('resize', this.resizeThrottled, false);
},
@@ -102,6 +109,7 @@
v-for="(graphData, index) in groupData.metrics"
:key="index"
:graph-data="graphData"
+ :hover-data="hoverData"
:update-aspect-ratio="updateAspectRatio"
:deployment-data="store.deploymentData"
/>
diff --git a/app/assets/javascripts/monitoring/components/empty_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue
index a7b483f6786..a18164482a2 100644
--- a/app/assets/javascripts/monitoring/components/empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/empty_state.vue
@@ -73,34 +73,22 @@
<template>
<div class="prometheus-state">
- <div class="row">
- <div class="col-md-4 col-md-offset-4 state-svg svg-content">
- <img :src="currentState.svgUrl"/>
- </div>
+ <div class="state-svg svg-content">
+ <img :src="currentState.svgUrl"/>
</div>
- <div class="row">
- <div class="col-md-6 col-md-offset-3">
- <h4 class="text-center state-title">
- {{currentState.title}}
- </h4>
- </div>
- </div>
- <div class="row">
- <div class="col-md-6 col-md-offset-3">
- <div class="description-text text-center state-description">
- {{currentState.description}}
- <a v-if="showButtonDescription" :href="settingsPath">
- Prometheus server
- </a>
- </div>
- </div>
- </div>
- <div class="row state-button-section">
- <div class="col-md-4 col-md-offset-4 text-center state-button">
- <a class="btn btn-success" :href="buttonPath">
- {{currentState.buttonText}}
- </a>
- </div>
+ <h4 class="state-title">
+ {{currentState.title}}
+ </h4>
+ <p class="state-description">
+ {{currentState.description}}
+ <a v-if="showButtonDescription" :href="settingsPath">
+ Prometheus server
+ </a>
+ </p>
+ <div class="state-button">
+ <a class="btn btn-success" :href="buttonPath">
+ {{currentState.buttonText}}
+ </a>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue
index 6b3e341f936..322e083a058 100644
--- a/app/assets/javascripts/monitoring/components/graph.vue
+++ b/app/assets/javascripts/monitoring/components/graph.vue
@@ -7,12 +7,10 @@
import MonitoringMixin from '../mixins/monitoring_mixins';
import eventHub from '../event_hub';
import measurements from '../utils/measurements';
- import { timeScaleFormat } from '../utils/date_time_formatters';
+ import { timeScaleFormat, bisectDate } from '../utils/date_time_formatters';
import createTimeSeries from '../utils/multiple_time_series';
import bp from '../../breakpoints';
- const bisectDate = d3.bisector(d => d.time).left;
-
export default {
props: {
graphData: {
@@ -27,6 +25,11 @@
type: Array,
required: true,
},
+ hoverData: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
},
mixins: [MonitoringMixin],
@@ -52,6 +55,7 @@
currentXCoordinate: 0,
currentFlagPosition: 0,
showFlag: false,
+ showFlagContent: false,
showDeployInfo: true,
timeSeries: [],
};
@@ -122,22 +126,14 @@
const d1 = firstTimeSeries.values[overlayIndex];
if (d0 === undefined || d1 === undefined) return;
const evalTime = timeValueOverlay - d0[0] > d1[0] - timeValueOverlay;
- this.currentData = evalTime ? d1 : d0;
- this.currentDataIndex = evalTime ? overlayIndex : (overlayIndex - 1);
- this.currentXCoordinate = Math.floor(firstTimeSeries.timeSeriesScaleX(this.currentData.time));
+ const hoveredDataIndex = evalTime ? overlayIndex : (overlayIndex - 1);
+ const hoveredDate = firstTimeSeries.values[hoveredDataIndex].time;
const currentDeployXPos = this.mouseOverDeployInfo(point.x);
- if (this.currentXCoordinate > (this.graphWidth - 200)) {
- this.currentFlagPosition = this.currentXCoordinate - 103;
- } else {
- this.currentFlagPosition = this.currentXCoordinate;
- }
-
- if (currentDeployXPos) {
- this.showFlag = false;
- } else {
- this.showFlag = true;
- }
+ eventHub.$emit('hoverChanged', {
+ hoveredDate,
+ currentDeployXPos,
+ });
},
renderAxesPaths() {
@@ -194,6 +190,10 @@
eventHub.$emit('toggleAspectRatio');
}
},
+
+ hoverData() {
+ this.positionFlag();
+ },
},
mounted() {
@@ -203,7 +203,10 @@
</script>
<template>
- <div class="prometheus-graph">
+ <div
+ class="prometheus-graph"
+ @mouseover="showFlagContent = true"
+ @mouseleave="showFlagContent = false">
<h5 class="text-center graph-title">
{{graphData.title}}
</h5>
@@ -257,6 +260,7 @@
:current-flag-position="currentFlagPosition"
:graph-height="graphHeight"
:graph-height-offset="graphHeightOffset"
+ :show-flag-content="showFlagContent"
/>
<rect
class="prometheus-graph-overlay"
diff --git a/app/assets/javascripts/monitoring/components/graph/flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue
index a98e3d06c18..10fb7ff6803 100644
--- a/app/assets/javascripts/monitoring/components/graph/flag.vue
+++ b/app/assets/javascripts/monitoring/components/graph/flag.vue
@@ -23,6 +23,10 @@
type: Number,
required: true,
},
+ showFlagContent: {
+ type: Boolean,
+ required: true,
+ },
},
data() {
@@ -57,6 +61,7 @@
transform="translate(-5, 20)">
</line>
<svg
+ v-if="showFlagContent"
class="rect-text-metric"
:x="currentFlagPosition"
y="0">
diff --git a/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js b/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js
index 345a0b37a76..31f38aca5d6 100644
--- a/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js
+++ b/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js
@@ -1,3 +1,5 @@
+import { bisectDate } from '../utils/date_time_formatters';
+
const mixins = {
methods: {
mouseOverDeployInfo(mouseXPos) {
@@ -18,6 +20,7 @@ const mixins = {
return dataFound;
},
+
formatDeployments() {
this.reducedDeploymentData = this.deploymentData.reduce((deploymentDataArray, deployment) => {
const time = new Date(deployment.created_at);
@@ -40,6 +43,25 @@ const mixins = {
return deploymentDataArray;
}, []);
},
+
+ positionFlag() {
+ const timeSeries = this.timeSeries[0];
+ const hoveredDataIndex = bisectDate(timeSeries.values, this.hoverData.hoveredDate, 1);
+ this.currentData = timeSeries.values[hoveredDataIndex];
+ this.currentDataIndex = hoveredDataIndex;
+ this.currentXCoordinate = Math.floor(timeSeries.timeSeriesScaleX(this.currentData.time));
+ if (this.currentXCoordinate > (this.graphWidth - 200)) {
+ this.currentFlagPosition = this.currentXCoordinate - 103;
+ } else {
+ this.currentFlagPosition = this.currentXCoordinate;
+ }
+
+ if (this.hoverData.currentDeployXPos) {
+ this.showFlag = false;
+ } else {
+ this.showFlag = true;
+ }
+ },
},
};
diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js
index ef280e02092..104432ef5de 100644
--- a/app/assets/javascripts/monitoring/monitoring_bundle.js
+++ b/app/assets/javascripts/monitoring/monitoring_bundle.js
@@ -3,8 +3,5 @@ import Dashboard from './components/dashboard.vue';
document.addEventListener('DOMContentLoaded', () => new Vue({
el: '#prometheus-graphs',
- components: {
- Dashboard,
- },
- render: createElement => createElement('dashboard'),
+ render: createElement => createElement(Dashboard),
}));
diff --git a/app/assets/javascripts/monitoring/stores/monitoring_store.js b/app/assets/javascripts/monitoring/stores/monitoring_store.js
index 7592af5878e..854636e9a89 100644
--- a/app/assets/javascripts/monitoring/stores/monitoring_store.js
+++ b/app/assets/javascripts/monitoring/stores/monitoring_store.js
@@ -13,7 +13,7 @@ function normalizeMetrics(metrics) {
...result,
values: result.values.map(([timestamp, value]) => ({
time: new Date(timestamp * 1000),
- value,
+ value: Number(value),
})),
})),
})),
diff --git a/app/assets/javascripts/monitoring/utils/date_time_formatters.js b/app/assets/javascripts/monitoring/utils/date_time_formatters.js
index 26bcaa02511..c4c6b1ac1f5 100644
--- a/app/assets/javascripts/monitoring/utils/date_time_formatters.js
+++ b/app/assets/javascripts/monitoring/utils/date_time_formatters.js
@@ -2,6 +2,7 @@ import d3 from 'd3';
export const dateFormat = d3.time.format('%b %-d, %Y');
export const timeFormat = d3.time.format('%-I:%M%p');
+export const bisectDate = d3.bisector(d => d.time).left;
export const timeScaleFormat = d3.time.format.multi([
['.%L', d => d.getMilliseconds()],
diff --git a/app/assets/javascripts/notebook/cells/code.vue b/app/assets/javascripts/notebook/cells/code.vue
index b8a16356576..b4067d229aa 100644
--- a/app/assets/javascripts/notebook/cells/code.vue
+++ b/app/assets/javascripts/notebook/cells/code.vue
@@ -1,18 +1,3 @@
-<template>
- <div class="cell">
- <code-cell
- type="input"
- :raw-code="rawInputCode"
- :count="cell.execution_count"
- :code-css-class="codeCssClass" />
- <output-cell
- v-if="hasOutput"
- :count="cell.execution_count"
- :output="output"
- :code-css-class="codeCssClass" />
- </div>
-</template>
-
<script>
import CodeCell from './code/index.vue';
import OutputCell from './output/index.vue';
@@ -51,6 +36,21 @@ export default {
};
</script>
+<template>
+ <div class="cell">
+ <code-cell
+ type="input"
+ :raw-code="rawInputCode"
+ :count="cell.execution_count"
+ :code-css-class="codeCssClass" />
+ <output-cell
+ v-if="hasOutput"
+ :count="cell.execution_count"
+ :output="output"
+ :code-css-class="codeCssClass" />
+ </div>
+</template>
+
<style scoped>
.cell {
flex-direction: column;
diff --git a/app/assets/javascripts/notebook/cells/code/index.vue b/app/assets/javascripts/notebook/cells/code/index.vue
index 31b30f601e2..0f3083f05b2 100644
--- a/app/assets/javascripts/notebook/cells/code/index.vue
+++ b/app/assets/javascripts/notebook/cells/code/index.vue
@@ -1,17 +1,3 @@
-<template>
- <div :class="type">
- <prompt
- :type="promptType"
- :count="count" />
- <pre
- class="language-python"
- :class="codeCssClass"
- ref="code"
- v-text="code">
- </pre>
- </div>
-</template>
-
<script>
import Prism from '../../lib/highlight';
import Prompt from '../prompt.vue';
@@ -55,3 +41,17 @@
},
};
</script>
+
+<template>
+ <div :class="type">
+ <prompt
+ :type="promptType"
+ :count="count" />
+ <pre
+ class="language-python"
+ :class="codeCssClass"
+ ref="code"
+ v-text="code">
+ </pre>
+ </div>
+</template>
diff --git a/app/assets/javascripts/notebook/cells/markdown.vue b/app/assets/javascripts/notebook/cells/markdown.vue
index 814d2ea92b4..82c51a1068c 100644
--- a/app/assets/javascripts/notebook/cells/markdown.vue
+++ b/app/assets/javascripts/notebook/cells/markdown.vue
@@ -1,10 +1,3 @@
-<template>
- <div class="cell text-cell">
- <prompt />
- <div class="markdown" v-html="markdown"></div>
- </div>
-</template>
-
<script>
/* global katex */
import marked from 'marked';
@@ -95,6 +88,13 @@
};
</script>
+<template>
+ <div class="cell text-cell">
+ <prompt />
+ <div class="markdown" v-html="markdown"></div>
+ </div>
+</template>
+
<style>
.markdown .katex {
display: block;
diff --git a/app/assets/javascripts/notebook/cells/output/html.vue b/app/assets/javascripts/notebook/cells/output/html.vue
index 0f39cd138df..2110a9de7ed 100644
--- a/app/assets/javascripts/notebook/cells/output/html.vue
+++ b/app/assets/javascripts/notebook/cells/output/html.vue
@@ -1,10 +1,3 @@
-<template>
- <div class="output">
- <prompt />
- <div v-html="rawCode"></div>
- </div>
-</template>
-
<script>
import Prompt from '../prompt.vue';
@@ -20,3 +13,10 @@ export default {
},
};
</script>
+
+<template>
+ <div class="output">
+ <prompt />
+ <div v-html="rawCode"></div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/notebook/cells/output/image.vue b/app/assets/javascripts/notebook/cells/output/image.vue
index f3b873bbc0f..fbb39ea6e2d 100644
--- a/app/assets/javascripts/notebook/cells/output/image.vue
+++ b/app/assets/javascripts/notebook/cells/output/image.vue
@@ -1,11 +1,3 @@
-<template>
- <div class="output">
- <prompt />
- <img
- :src="'data:' + outputType + ';base64,' + rawCode" />
- </div>
-</template>
-
<script>
import Prompt from '../prompt.vue';
@@ -25,3 +17,11 @@ export default {
},
};
</script>
+
+<template>
+ <div class="output">
+ <prompt />
+ <img
+ :src="'data:' + outputType + ';base64,' + rawCode" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index 23c9ea78939..05af0bf1e8e 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -1,12 +1,3 @@
-<template>
- <component :is="componentName"
- type="output"
- :outputType="outputType"
- :count="count"
- :raw-code="rawCode"
- :code-css-class="codeCssClass" />
-</template>
-
<script>
import CodeCell from '../code/index.vue';
import Html from './html.vue';
@@ -81,3 +72,12 @@ export default {
},
};
</script>
+
+<template>
+ <component :is="componentName"
+ type="output"
+ :outputType="outputType"
+ :count="count"
+ :raw-code="rawCode"
+ :code-css-class="codeCssClass" />
+</template>
diff --git a/app/assets/javascripts/notebook/cells/prompt.vue b/app/assets/javascripts/notebook/cells/prompt.vue
index 4540e4248d8..039fb99293d 100644
--- a/app/assets/javascripts/notebook/cells/prompt.vue
+++ b/app/assets/javascripts/notebook/cells/prompt.vue
@@ -1,11 +1,3 @@
-<template>
- <div class="prompt">
- <span v-if="type && count">
- {{ type }} [{{ count }}]:
- </span>
- </div>
-</template>
-
<script>
export default {
props: {
@@ -21,6 +13,14 @@
};
</script>
+<template>
+ <div class="prompt">
+ <span v-if="type && count">
+ {{ type }} [{{ count }}]:
+ </span>
+ </div>
+</template>
+
<style scoped>
.prompt {
padding: 0 10px;
diff --git a/app/assets/javascripts/notebook/index.vue b/app/assets/javascripts/notebook/index.vue
index fd62c1231ef..e88806431af 100644
--- a/app/assets/javascripts/notebook/index.vue
+++ b/app/assets/javascripts/notebook/index.vue
@@ -1,14 +1,3 @@
-<template>
- <div v-if="hasNotebook">
- <component
- v-for="(cell, index) in cells"
- :is="cellType(cell.cell_type)"
- :cell="cell"
- :key="index"
- :code-css-class="codeCssClass" />
- </div>
-</template>
-
<script>
import {
MarkdownCell,
@@ -59,6 +48,17 @@
};
</script>
+<template>
+ <div v-if="hasNotebook">
+ <component
+ v-for="(cell, index) in cells"
+ :is="cellType(cell.cell_type)"
+ :cell="cell"
+ :key="index"
+ :code-css-class="codeCssClass" />
+ </div>
+</template>
+
<style>
.cell,
.input,
diff --git a/app/assets/javascripts/notes/components/issue_comment_form.vue b/app/assets/javascripts/notes/components/issue_comment_form.vue
index fa7ac994058..1a7da84a424 100644
--- a/app/assets/javascripts/notes/components/issue_comment_form.vue
+++ b/app/assets/javascripts/notes/components/issue_comment_form.vue
@@ -272,6 +272,7 @@
v-model="note"
ref="textarea"
slot="textarea"
+ :disabled="isSubmitting"
placeholder="Write a comment or drag your files here..."
@keydown.up="editCurrentUserLastNote()"
@keydown.meta.enter="handleSave()">
diff --git a/app/assets/javascripts/notes/components/issue_note.vue b/app/assets/javascripts/notes/components/issue_note.vue
index 3483f6c7538..1f43b8a16ad 100644
--- a/app/assets/javascripts/notes/components/issue_note.vue
+++ b/app/assets/javascripts/notes/components/issue_note.vue
@@ -62,7 +62,7 @@
},
deleteHandler() {
// eslint-disable-next-line no-alert
- if (confirm('Are you sure you want to delete this list?')) {
+ if (confirm('Are you sure you want to delete this comment?')) {
this.isDeleting = true;
this.deleteNote(this.note)
diff --git a/app/assets/javascripts/pdf/index.vue b/app/assets/javascripts/pdf/index.vue
index b874e484d45..c8a2f778ee8 100644
--- a/app/assets/javascripts/pdf/index.vue
+++ b/app/assets/javascripts/pdf/index.vue
@@ -1,13 +1,3 @@
-<template>
- <div class="pdf-viewer" v-if="hasPDF">
- <page v-for="(page, index) in pages"
- :key="index"
- :v-if="!loading"
- :page="page"
- :number="index + 1" />
- </div>
-</template>
-
<script>
import pdfjsLib from 'vendor/pdf';
import workerSrc from 'vendor/pdf.worker.min';
@@ -64,6 +54,16 @@
};
</script>
+<template>
+ <div class="pdf-viewer" v-if="hasPDF">
+ <page v-for="(page, index) in pages"
+ :key="index"
+ :v-if="!loading"
+ :page="page"
+ :number="index + 1" />
+ </div>
+</template>
+
<style>
.pdf-viewer {
background: url('./assets/img/bg.gif');
diff --git a/app/assets/javascripts/pdf/page/index.vue b/app/assets/javascripts/pdf/page/index.vue
index 7b74ee4eb2e..be38f7cc129 100644
--- a/app/assets/javascripts/pdf/page/index.vue
+++ b/app/assets/javascripts/pdf/page/index.vue
@@ -1,10 +1,3 @@
-<template>
- <canvas
- class="pdf-page"
- ref="canvas"
- :data-page="number" />
-</template>
-
<script>
export default {
props: {
@@ -48,6 +41,13 @@
};
</script>
+<template>
+ <canvas
+ class="pdf-page"
+ ref="canvas"
+ :data-page="number" />
+</template>
+
<style>
.pdf-page {
margin: 8px auto 0 auto;
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index f0b44dfa6d8..76b97af39f1 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -28,8 +28,7 @@
popoverOptions() {
return {
html: true,
- delay: { hide: 600 },
- trigger: 'hover',
+ trigger: 'focus',
placement: 'top',
title: '<div class="autodevops-title">This pipeline makes use of a predefined CI/CD configuration enabled by <b>Auto DevOps.</b></div>',
content: `<a class="autodevops-link" href="${this.autoDevopsHelpPath}" target="_blank" rel="noopener noreferrer nofollow">Learn more about Auto DevOps</a>`,
@@ -75,6 +74,7 @@
</span>
<a
v-if="pipeline.flags.auto_devops"
+ tabindex="0"
class="js-pipeline-url-autodevops label label-info autodevops-badge"
v-popover="popoverOptions"
role="button">
diff --git a/app/assets/javascripts/project_fork.js b/app/assets/javascripts/project_fork.js
index 47197db39d3..65d46fa9a73 100644
--- a/app/assets/javascripts/project_fork.js
+++ b/app/assets/javascripts/project_fork.js
@@ -1,13 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, max-len */
-(function() {
- this.ProjectFork = (function() {
- function ProjectFork() {
- $('.fork-thumbnail a').on('click', function() {
- $('.fork-namespaces').hide();
- return $('.save-project-loader').show();
- });
- }
+export default () => {
+ $('.js-fork-thumbnail').on('click', function forkThumbnailClicked() {
+ if ($(this).hasClass('disabled')) return false;
- return ProjectFork;
- })();
-}).call(window);
+ return $('.js-fork-content').toggle();
+ });
+};
diff --git a/app/assets/javascripts/projects_dropdown/service/projects_service.js b/app/assets/javascripts/projects_dropdown/service/projects_service.js
index fad956b4c26..9cbd8f21f2a 100644
--- a/app/assets/javascripts/projects_dropdown/service/projects_service.js
+++ b/app/assets/javascripts/projects_dropdown/service/projects_service.js
@@ -19,7 +19,7 @@ export default class ProjectsService {
getSearchedProjects(searchQuery) {
return this.projectsPath.get({
- simple: false,
+ simple: true,
per_page: 20,
membership: !!gon.current_user_id,
order_by: 'last_activity_at',
diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue
new file mode 100644
index 00000000000..2d8ca443ea7
--- /dev/null
+++ b/app/assets/javascripts/registry/components/app.vue
@@ -0,0 +1,62 @@
+<script>
+ /* globals Flash */
+ import { mapGetters, mapActions } from 'vuex';
+ import '../../flash';
+ import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+ import store from '../stores';
+ import collapsibleContainer from './collapsible_container.vue';
+ import { errorMessages, errorMessagesTypes } from '../constants';
+
+ export default {
+ name: 'registryListApp',
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ },
+ store,
+ components: {
+ collapsibleContainer,
+ loadingIcon,
+ },
+ computed: {
+ ...mapGetters([
+ 'isLoading',
+ 'repos',
+ ]),
+ },
+ methods: {
+ ...mapActions([
+ 'setMainEndpoint',
+ 'fetchRepos',
+ ]),
+ },
+ created() {
+ this.setMainEndpoint(this.endpoint);
+ },
+ mounted() {
+ this.fetchRepos()
+ .catch(() => Flash(errorMessages[errorMessagesTypes.FETCH_REPOS]));
+ },
+ };
+</script>
+<template>
+ <div>
+ <loading-icon
+ v-if="isLoading"
+ size="3"
+ />
+
+ <collapsible-container
+ v-else-if="!isLoading && repos.length"
+ v-for="(item, index) in repos"
+ :key="index"
+ :repo="item"
+ />
+
+ <p v-else-if="!isLoading && !repos.length">
+ {{__("No container images stored for this project. Add one by following the instructions above.")}}
+ </p>
+ </div>
+</template>
diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue
new file mode 100644
index 00000000000..41ea9742406
--- /dev/null
+++ b/app/assets/javascripts/registry/components/collapsible_container.vue
@@ -0,0 +1,131 @@
+<script>
+ /* globals Flash */
+ import { mapActions } from 'vuex';
+ import '../../flash';
+ import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
+ import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+ import tooltip from '../../vue_shared/directives/tooltip';
+ import tableRegistry from './table_registry.vue';
+ import { errorMessages, errorMessagesTypes } from '../constants';
+
+ export default {
+ name: 'collapsibeContainerRegisty',
+ props: {
+ repo: {
+ type: Object,
+ required: true,
+ },
+ },
+ components: {
+ clipboardButton,
+ loadingIcon,
+ tableRegistry,
+ },
+ directives: {
+ tooltip,
+ },
+ data() {
+ return {
+ isOpen: false,
+ };
+ },
+ computed: {
+ clipboardText() {
+ return `docker pull ${this.repo.location}`;
+ },
+ },
+ methods: {
+ ...mapActions([
+ 'fetchRepos',
+ 'fetchList',
+ 'deleteRepo',
+ ]),
+
+ toggleRepo() {
+ this.isOpen = !this.isOpen;
+
+ if (this.isOpen) {
+ this.fetchList({ repo: this.repo })
+ .catch(() => this.showError(errorMessagesTypes.FETCH_REGISTRY));
+ }
+ },
+
+ handleDeleteRepository() {
+ this.deleteRepo(this.repo)
+ .then(() => this.fetchRepos())
+ .catch(() => this.showError(errorMessagesTypes.DELETE_REPO));
+ },
+
+ showError(message) {
+ Flash((errorMessages[message]));
+ },
+ },
+ };
+</script>
+
+<template>
+ <div class="container-image">
+ <div
+ class="container-image-head">
+ <button
+ type="button"
+ @click="toggleRepo"
+ class="js-toggle-repo btn-link">
+ <i
+ class="fa"
+ :class="{
+ 'fa-chevron-right': !isOpen,
+ 'fa-chevron-up': isOpen,
+ }"
+ aria-hidden="true">
+ </i>
+ {{repo.name}}
+ </button>
+
+ <clipboard-button
+ v-if="repo.location"
+ :text="clipboardText"
+ :title="repo.location"
+ />
+
+ <div class="controls hidden-xs pull-right">
+ <button
+ v-if="repo.canDelete"
+ type="button"
+ class="js-remove-repo btn btn-danger"
+ :title="s__('ContainerRegistry|Remove repository')"
+ :aria-label="s__('ContainerRegistry|Remove repository')"
+ v-tooltip
+ @click="handleDeleteRepository">
+ <i
+ class="fa fa-trash"
+ aria-hidden="true">
+ </i>
+ </button>
+ </div>
+
+ </div>
+
+ <loading-icon
+ v-if="repo.isLoading"
+ class="append-bottom-20"
+ size="2"
+ />
+
+ <div
+ v-else-if="!repo.isLoading && isOpen"
+ class="container-image-tags">
+
+ <table-registry
+ v-if="repo.list.length"
+ :repo="repo"
+ />
+
+ <div
+ v-else
+ class="nothing-here-block">
+ {{s__("ContainerRegistry|No tags in Container Registry for this container image.")}}
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue
new file mode 100644
index 00000000000..4ce1571b0aa
--- /dev/null
+++ b/app/assets/javascripts/registry/components/table_registry.vue
@@ -0,0 +1,137 @@
+<script>
+ /* globals Flash */
+ import { mapActions } from 'vuex';
+ import { n__ } from '../../locale';
+ import '../../flash';
+ import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
+ import tablePagination from '../../vue_shared/components/table_pagination.vue';
+ import tooltip from '../../vue_shared/directives/tooltip';
+ import timeagoMixin from '../../vue_shared/mixins/timeago';
+ import { errorMessages, errorMessagesTypes } from '../constants';
+
+ export default {
+ props: {
+ repo: {
+ type: Object,
+ required: true,
+ },
+ },
+ components: {
+ clipboardButton,
+ tablePagination,
+ },
+ mixins: [
+ timeagoMixin,
+ ],
+ directives: {
+ tooltip,
+ },
+ computed: {
+ shouldRenderPagination() {
+ return this.repo.pagination.total > this.repo.pagination.perPage;
+ },
+ },
+ methods: {
+ ...mapActions([
+ 'fetchList',
+ 'deleteRegistry',
+ ]),
+
+ layers(item) {
+ return item.layers ? n__('%d layer', '%d layers', item.layers) : '';
+ },
+
+ handleDeleteRegistry(registry) {
+ this.deleteRegistry(registry)
+ .then(() => this.fetchList({ repo: this.repo }))
+ .catch(() => this.showError(errorMessagesTypes.DELETE_REGISTRY));
+ },
+
+ onPageChange(pageNumber) {
+ this.fetchList({ repo: this.repo, page: pageNumber })
+ .catch(() => this.showError(errorMessagesTypes.FETCH_REGISTRY));
+ },
+
+ clipboardText(text) {
+ return `docker pull ${text}`;
+ },
+
+ showError(message) {
+ Flash((errorMessages[message]));
+ },
+ },
+ };
+</script>
+<template>
+<div>
+ <table class="table tags">
+ <thead>
+ <tr>
+ <th>{{s__('ContainerRegistry|Tag')}}</th>
+ <th>{{s__('ContainerRegistry|Tag ID')}}</th>
+ <th>{{s__("ContainerRegistry|Size")}}</th>
+ <th>{{s__("ContainerRegistry|Created")}}</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr
+ v-for="(item, i) in repo.list"
+ :key="i">
+ <td>
+
+ {{item.tag}}
+
+ <clipboard-button
+ v-if="item.location"
+ :title="item.location"
+ :text="clipboardText(item.location)"
+ />
+ </td>
+ <td>
+ <span
+ v-tooltip
+ :title="item.revision"
+ data-placement="bottom">
+ {{item.shortRevision}}
+ </span>
+ </td>
+ <td>
+ {{item.size}}
+ <template v-if="item.size && item.layers">
+ &middot;
+ </template>
+ {{layers(item)}}
+ </td>
+
+ <td>
+ {{timeFormated(item.createdAt)}}
+ </td>
+
+ <td class="content">
+ <button
+ v-if="item.canDelete"
+ type="button"
+ class="js-delete-registry btn btn-danger hidden-xs pull-right"
+ :title="s__('ContainerRegistry|Remove tag')"
+ :aria-label="s__('ContainerRegistry|Remove tag')"
+ data-container="body"
+ v-tooltip
+ @click="handleDeleteRegistry(item)">
+ <i
+ class="fa fa-trash"
+ aria-hidden="true">
+ </i>
+ </button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <table-pagination
+ v-if="shouldRenderPagination"
+ :change="onPageChange"
+ :page-info="repo.pagination"
+ />
+</div>
+</template>
diff --git a/app/assets/javascripts/registry/constants.js b/app/assets/javascripts/registry/constants.js
new file mode 100644
index 00000000000..712b0fade3d
--- /dev/null
+++ b/app/assets/javascripts/registry/constants.js
@@ -0,0 +1,15 @@
+import { __ } from '../locale';
+
+export const errorMessagesTypes = {
+ FETCH_REGISTRY: 'FETCH_REGISTRY',
+ FETCH_REPOS: 'FETCH_REPOS',
+ DELETE_REPO: 'DELETE_REPO',
+ DELETE_REGISTRY: 'DELETE_REGISTRY',
+};
+
+export const errorMessages = {
+ [errorMessagesTypes.FETCH_REGISTRY]: __('Something went wrong while fetching the registry list.'),
+ [errorMessagesTypes.FETCH_REPOS]: __('Something went wrong while fetching the projects.'),
+ [errorMessagesTypes.DELETE_REPO]: __('Something went wrong on our end.'),
+ [errorMessagesTypes.DELETE_REGISTRY]: __('Something went wrong on our end.'),
+};
diff --git a/app/assets/javascripts/registry/index.js b/app/assets/javascripts/registry/index.js
new file mode 100644
index 00000000000..d8edff73f72
--- /dev/null
+++ b/app/assets/javascripts/registry/index.js
@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import registryApp from './components/app.vue';
+import Translate from '../vue_shared/translate';
+
+Vue.use(Translate);
+
+document.addEventListener('DOMContentLoaded', () => new Vue({
+ el: '#js-vue-registry-images',
+ components: {
+ registryApp,
+ },
+ data() {
+ const dataset = document.querySelector(this.$options.el).dataset;
+ return {
+ endpoint: dataset.endpoint,
+ };
+ },
+ render(createElement) {
+ return createElement('registry-app', {
+ props: {
+ endpoint: this.endpoint,
+ },
+ });
+ },
+}));
diff --git a/app/assets/javascripts/registry/stores/actions.js b/app/assets/javascripts/registry/stores/actions.js
new file mode 100644
index 00000000000..34ed40b8b65
--- /dev/null
+++ b/app/assets/javascripts/registry/stores/actions.js
@@ -0,0 +1,39 @@
+import Vue from 'vue';
+import VueResource from 'vue-resource';
+import * as types from './mutation_types';
+
+Vue.use(VueResource);
+
+export const fetchRepos = ({ commit, state }) => {
+ commit(types.TOGGLE_MAIN_LOADING);
+
+ return Vue.http.get(state.endpoint)
+ .then(res => res.json())
+ .then((response) => {
+ commit(types.TOGGLE_MAIN_LOADING);
+ commit(types.SET_REPOS_LIST, response);
+ });
+};
+
+export const fetchList = ({ commit }, { repo, page }) => {
+ commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo);
+
+ return Vue.http.get(repo.tagsPath, { params: { page } })
+ .then((response) => {
+ const headers = response.headers;
+
+ return response.json().then((resp) => {
+ commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo);
+ commit(types.SET_REGISTRY_LIST, { repo, resp, headers });
+ });
+ });
+};
+
+export const deleteRepo = ({ commit }, repo) => Vue.http.delete(repo.destroyPath)
+ .then(res => res.json());
+
+export const deleteRegistry = ({ commit }, image) => Vue.http.delete(image.destroyPath)
+ .then(res => res.json());
+
+export const setMainEndpoint = ({ commit }, data) => commit(types.SET_MAIN_ENDPOINT, data);
+export const toggleLoading = ({ commit }) => commit(types.TOGGLE_MAIN_LOADING);
diff --git a/app/assets/javascripts/registry/stores/getters.js b/app/assets/javascripts/registry/stores/getters.js
new file mode 100644
index 00000000000..588f479c492
--- /dev/null
+++ b/app/assets/javascripts/registry/stores/getters.js
@@ -0,0 +1,2 @@
+export const isLoading = state => state.isLoading;
+export const repos = state => state.repos;
diff --git a/app/assets/javascripts/registry/stores/index.js b/app/assets/javascripts/registry/stores/index.js
new file mode 100644
index 00000000000..78b67881210
--- /dev/null
+++ b/app/assets/javascripts/registry/stores/index.js
@@ -0,0 +1,39 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import * as actions from './actions';
+import * as getters from './getters';
+import mutations from './mutations';
+
+Vue.use(Vuex);
+
+export default new Vuex.Store({
+ state: {
+ isLoading: false,
+ endpoint: '', // initial endpoint to fetch the repos list
+ /**
+ * Each object in `repos` has the following strucure:
+ * {
+ * name: String,
+ * isLoading: Boolean,
+ * tagsPath: String // endpoint to request the list
+ * destroyPath: String // endpoit to delete the repo
+ * list: Array // List of the registry images
+ * }
+ *
+ * Each registry image inside `list` has the following structure:
+ * {
+ * tag: String,
+ * revision: String
+ * shortRevision: String
+ * size: Number
+ * layers: Number
+ * createdAt: String
+ * destroyPath: String // endpoit to delete each image
+ * }
+ */
+ repos: [],
+ },
+ actions,
+ getters,
+ mutations,
+});
diff --git a/app/assets/javascripts/registry/stores/mutation_types.js b/app/assets/javascripts/registry/stores/mutation_types.js
new file mode 100644
index 00000000000..2c69bf11807
--- /dev/null
+++ b/app/assets/javascripts/registry/stores/mutation_types.js
@@ -0,0 +1,7 @@
+export const SET_MAIN_ENDPOINT = 'SET_MAIN_ENDPOINT';
+
+export const SET_REPOS_LIST = 'SET_REPOS_LIST';
+export const TOGGLE_MAIN_LOADING = 'TOGGLE_MAIN_LOADING';
+
+export const SET_REGISTRY_LIST = 'SET_REGISTRY_LIST';
+export const TOGGLE_REGISTRY_LIST_LOADING = 'TOGGLE_REGISTRY_LIST_LOADING';
diff --git a/app/assets/javascripts/registry/stores/mutations.js b/app/assets/javascripts/registry/stores/mutations.js
new file mode 100644
index 00000000000..e40382e7afc
--- /dev/null
+++ b/app/assets/javascripts/registry/stores/mutations.js
@@ -0,0 +1,54 @@
+import * as types from './mutation_types';
+import { parseIntPagination, normalizeHeaders } from '../../lib/utils/common_utils';
+
+export default {
+
+ [types.SET_MAIN_ENDPOINT](state, endpoint) {
+ Object.assign(state, { endpoint });
+ },
+
+ [types.SET_REPOS_LIST](state, list) {
+ Object.assign(state, {
+ repos: list.map(el => ({
+ canDelete: !!el.destroy_path,
+ destroyPath: el.destroy_path,
+ id: el.id,
+ isLoading: false,
+ list: [],
+ location: el.location,
+ name: el.path,
+ tagsPath: el.tags_path,
+ })),
+ });
+ },
+
+ [types.TOGGLE_MAIN_LOADING](state) {
+ Object.assign(state, { isLoading: !state.isLoading });
+ },
+
+ [types.SET_REGISTRY_LIST](state, { repo, resp, headers }) {
+ const listToUpdate = state.repos.find(el => el.id === repo.id);
+
+ const normalizedHeaders = normalizeHeaders(headers);
+ const pagination = parseIntPagination(normalizedHeaders);
+
+ listToUpdate.pagination = pagination;
+
+ listToUpdate.list = resp.map(element => ({
+ tag: element.name,
+ revision: element.revision,
+ shortRevision: element.short_revision,
+ size: element.size,
+ layers: element.layers,
+ location: element.location,
+ createdAt: element.created_at,
+ destroyPath: element.destroy_path,
+ canDelete: !!element.destroy_path,
+ }));
+ },
+
+ [types.TOGGLE_REGISTRY_LIST_LOADING](state, list) {
+ const listToUpdate = state.repos.find(el => el.id === list.id);
+ listToUpdate.isLoading = !listToUpdate.isLoading;
+ },
+};
diff --git a/app/assets/javascripts/repo/components/repo_commit_section.vue b/app/assets/javascripts/repo/components/repo_commit_section.vue
index f3db1742253..119e38c583d 100644
--- a/app/assets/javascripts/repo/components/repo_commit_section.vue
+++ b/app/assets/javascripts/repo/components/repo_commit_section.vue
@@ -37,7 +37,7 @@ export default {
content: f.newContent,
}));
const payload = {
- branch: Store.targetBranch,
+ branch: Store.currentBranch,
commit_message: commitMessage,
actions,
};
@@ -105,7 +105,7 @@ export default {
</label>
<div class="col-md-6">
<span class="help-block">
- {{targetBranch}}
+ {{currentBranch}}
</span>
</div>
</div>
diff --git a/app/assets/javascripts/repo/components/repo_edit_button.vue b/app/assets/javascripts/repo/components/repo_edit_button.vue
index 29b76975561..353142edeb7 100644
--- a/app/assets/javascripts/repo/components/repo_edit_button.vue
+++ b/app/assets/javascripts/repo/components/repo_edit_button.vue
@@ -26,16 +26,6 @@ export default {
this.editMode = !this.editMode;
Store.toggleBlobView();
},
- toggleProjectRefsForm() {
- $('.project-refs-form').toggleClass('disabled', this.editMode);
- $('.js-tree-ref-target-holder').toggle(this.editMode);
- },
- },
-
- watch: {
- editMode() {
- this.toggleProjectRefsForm();
- },
},
};
</script>
diff --git a/app/assets/javascripts/repo/components/repo_file.vue b/app/assets/javascripts/repo/components/repo_file.vue
index 20ebf840774..8b9cbd23456 100644
--- a/app/assets/javascripts/repo/components/repo_file.vue
+++ b/app/assets/javascripts/repo/components/repo_file.vue
@@ -95,7 +95,7 @@ export default RepoFile;
</div>
</td>
- <td class="hidden-xs">
+ <td class="hidden-xs text-right">
<span
class="commit-update"
:title="tooltipTitle(file.lastCommitUpdate)">
diff --git a/app/assets/javascripts/repo/components/repo_sidebar.vue b/app/assets/javascripts/repo/components/repo_sidebar.vue
index dc1bda95a01..685f6ff806f 100644
--- a/app/assets/javascripts/repo/components/repo_sidebar.vue
+++ b/app/assets/javascripts/repo/components/repo_sidebar.vue
@@ -74,8 +74,8 @@ export default {
<thead v-if="!isMini">
<tr>
<th class="name">Name</th>
- <th class="hidden-sm hidden-xs last-commit">Last Commit</th>
- <th class="hidden-xs last-update">Last Update</th>
+ <th class="hidden-sm hidden-xs last-commit">Last commit</th>
+ <th class="hidden-xs last-update text-right">Last update</th>
</tr>
</thead>
<tbody>
diff --git a/app/assets/javascripts/repo/helpers/repo_helper.js b/app/assets/javascripts/repo/helpers/repo_helper.js
index 62e61ad3090..1e640546d63 100644
--- a/app/assets/javascripts/repo/helpers/repo_helper.js
+++ b/app/assets/javascripts/repo/helpers/repo_helper.js
@@ -59,13 +59,13 @@ const RepoHelper = {
return langs.find(lang => lang.extensions && lang.extensions.indexOf(`.${ext}`) > -1);
},
- setDirectoryOpen(tree) {
+ setDirectoryOpen(tree, title) {
const file = tree;
if (!file) return undefined;
file.opened = true;
file.icon = 'fa-folder-open';
- RepoHelper.updateHistoryEntry(file.url, file.name);
+ RepoHelper.updateHistoryEntry(file.url, title);
return file;
},
@@ -136,6 +136,8 @@ const RepoHelper = {
return Service.getContent()
.then((response) => {
const data = response.data;
+ if (response.headers && response.headers['page-title']) data.pageTitle = response.headers['page-title'];
+
Store.isTree = RepoHelper.isTree(data);
if (!Store.isTree) {
if (!file) file = data;
@@ -179,7 +181,7 @@ const RepoHelper = {
} else {
// it's a tree
if (!file) Store.isRoot = RepoHelper.isRoot(Service.url);
- file = RepoHelper.setDirectoryOpen(file);
+ file = RepoHelper.setDirectoryOpen(file, data.pageTitle || data.name);
const newDirectory = RepoHelper.dataToListOfFiles(data);
Store.addFilesToDirectory(file, Store.files, newDirectory);
Store.prevURL = Service.blobURLtoParentTree(Service.url);
@@ -266,7 +268,7 @@ const RepoHelper = {
history.pushState({ key: RepoHelper.key }, '', url);
if (title) {
- document.title = `${title} · GitLab`;
+ document.title = title;
}
},
diff --git a/app/assets/javascripts/repo/index.js b/app/assets/javascripts/repo/index.js
index 6c1d468e937..7d0123e3d3a 100644
--- a/app/assets/javascripts/repo/index.js
+++ b/app/assets/javascripts/repo/index.js
@@ -11,10 +11,6 @@ function initDropdowns() {
}
function addEventsForNonVueEls() {
- $(document).on('change', '.dropdown', () => {
- Store.targetBranch = $('.project-refs-target-form input[name="ref"]').val();
- });
-
window.onbeforeunload = function confirmUnload(e) {
const hasChanged = Store.openedFiles
.some(file => file.changed);
diff --git a/app/assets/javascripts/repo/stores/repo_store.js b/app/assets/javascripts/repo/stores/repo_store.js
index 632d53b9c44..705dcb78473 100644
--- a/app/assets/javascripts/repo/stores/repo_store.js
+++ b/app/assets/javascripts/repo/stores/repo_store.js
@@ -32,7 +32,6 @@ const RepoStore = {
isCommitable: false,
binary: false,
currentBranch: '',
- targetBranch: 'new-branch',
commitMessage: '',
binaryTypes: {
png: false,
@@ -79,7 +78,7 @@ const RepoStore = {
}).catch(Helper.loadingError);
}
- if (!file.loading) Helper.updateHistoryEntry(file.url, file.name);
+ if (!file.loading) Helper.updateHistoryEntry(file.url, file.pageTitle || file.name);
RepoStore.binary = file.binary;
},
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 0c1ec276baf..a41548bd694 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -29,30 +29,32 @@ import Cookies from 'js-cookie';
$('.dropdown').on('loading.gl.dropdown', this.sidebarDropdownLoading);
$('.dropdown').on('loaded.gl.dropdown', this.sidebarDropdownLoaded);
- $document.on('click', '.js-sidebar-toggle', function(e, triggered) {
- var $allGutterToggleIcons, $this, $thisIcon;
- e.preventDefault();
- $this = $(this);
- $thisIcon = $this.find('i');
- $allGutterToggleIcons = $('.js-sidebar-toggle i');
- if ($thisIcon.hasClass('fa-angle-double-right')) {
- $allGutterToggleIcons.removeClass('fa-angle-double-right').addClass('fa-angle-double-left');
- $('aside.right-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed');
- $('.page-with-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed');
- } else {
- $allGutterToggleIcons.removeClass('fa-angle-double-left').addClass('fa-angle-double-right');
- $('aside.right-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
- $('.page-with-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
-
- if (gl.lazyLoader) gl.lazyLoader.loadCheck();
- }
- if (!triggered) {
- return Cookies.set("collapsed_gutter", $('.right-sidebar').hasClass('right-sidebar-collapsed'));
- }
- });
+ $document.on('click', '.js-sidebar-toggle', this.sidebarToggleClicked);
return $(document).off('click', '.js-issuable-todo').on('click', '.js-issuable-todo', this.toggleTodo);
};
+ Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
+ var $allGutterToggleIcons, $this, $thisIcon;
+ e.preventDefault();
+ $this = $(this);
+ $thisIcon = $this.find('i');
+ $allGutterToggleIcons = $('.js-sidebar-toggle i');
+ if ($thisIcon.hasClass('fa-angle-double-right')) {
+ $allGutterToggleIcons.removeClass('fa-angle-double-right').addClass('fa-angle-double-left');
+ $('aside.right-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed');
+ $('.page-with-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed');
+ } else {
+ $allGutterToggleIcons.removeClass('fa-angle-double-left').addClass('fa-angle-double-right');
+ $('aside.right-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
+ $('.page-with-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
+
+ if (gl.lazyLoader) gl.lazyLoader.loadCheck();
+ }
+ if (!triggered) {
+ Cookies.set("collapsed_gutter", $('.right-sidebar').hasClass('right-sidebar-collapsed'));
+ }
+ };
+
Sidebar.prototype.toggleTodo = function(e) {
var $btnText, $this, $todoLoading, ajaxType, url;
$this = $(e.currentTarget);
diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js
index 38c9a71dd20..f15452ec683 100644
--- a/app/assets/javascripts/search_autocomplete.js
+++ b/app/assets/javascripts/search_autocomplete.js
@@ -287,6 +287,7 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '.
onClearInputClick(e) {
e.preventDefault();
+ this.wrap.toggleClass('has-value', !!e.target.value);
return this.searchInput.val('').focus();
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js
index 703f3a56a34..4998a47b691 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js
@@ -27,7 +27,7 @@ export default {
<button
v-if="showDisabledButton"
type="button"
- class="btn btn-success btn-sm"
+ class="js-disabled-merge-button btn btn-success btn-sm"
disabled="true">
Merge
</button>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js
index aaf9d3304a4..09561694939 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js
@@ -7,7 +7,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="loading" showDisabledButton />
+ <status-icon status="loading" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
Checking ability to merge automatically
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js
index 4078aad7f83..b25cc3443ef 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js
@@ -16,9 +16,9 @@ export default {
<div class="media-body">
<mr-widget-author-and-time
actionText="Closed by"
- :author="mr.closedBy"
- :dateTitle="mr.updatedAt"
- :dateReadable="mr.closedAt"
+ :author="mr.closedEvent.author"
+ :dateTitle="mr.closedEvent.updatedAt"
+ :dateReadable="mr.closedEvent.formattedUpdatedAt"
/>
<section class="mr-info-list">
<p>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js
index f9cb79a0bc1..5d468a085cb 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js
@@ -10,27 +10,37 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon
+ status="failed"
+ :show-disabled-button="true" />
<div class="media-body space-children">
- <span class="bold">
- There are merge conflicts<span v-if="!mr.canMerge">.</span>
- <span v-if="!mr.canMerge">
- Resolve these conflicts or ask someone with write access to this repository to merge it locally
- </span>
+ <span
+ v-if="mr.shouldBeRebased"
+ class="bold">
+ Fast-forward merge is not possible.
+ To merge this request, first rebase locally.
</span>
- <a
- v-if="mr.canMerge && mr.conflictResolutionPath"
- :href="mr.conflictResolutionPath"
- class="btn btn-default btn-xs js-resolve-conflicts-button">
- Resolve conflicts
- </a>
- <a
- v-if="mr.canMerge"
- class="btn btn-default btn-xs js-merge-locally-button"
- data-toggle="modal"
- href="#modal_merge_info">
- Merge locally
- </a>
+ <template v-else>
+ <span class="bold">
+ There are merge conflicts<span v-if="!mr.canMerge">.</span>
+ <span v-if="!mr.canMerge">
+ Resolve these conflicts or ask someone with write access to this repository to merge it locally
+ </span>
+ </span>
+ <a
+ v-if="mr.canMerge && mr.conflictResolutionPath"
+ :href="mr.conflictResolutionPath"
+ class="js-resolve-conflicts-button btn btn-default btn-xs">
+ Resolve conflicts
+ </a>
+ <a
+ v-if="mr.canMerge"
+ class="js-merge-locally-button btn btn-default btn-xs"
+ data-toggle="modal"
+ href="#modal_merge_info">
+ Merge locally
+ </a>
+ </template>
</div>
</div>
`,
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js
index 1cb24549d53..c25d6c359bb 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.js
@@ -51,7 +51,7 @@ export default {
</span>
</template>
<template v-else>
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="failed" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
<span
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js
index e452260a4d0..74fc52796a0 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.js
@@ -69,9 +69,9 @@ export default {
<div class="space-children">
<mr-widget-author-and-time
actionText="Merged by"
- :author="mr.mergedBy"
- :dateTitle="mr.updatedAt"
- :dateReadable="mr.mergedAt" />
+ :author="mr.mergedEvent.author"
+ :date-title="mr.mergedEvent.updatedAt"
+ :date-readable="mr.mergedEvent.formattedUpdatedAt" />
<a
v-if="mr.canRevertInCurrentMR"
v-tooltip
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js
index 9f0a359d01a..1bc0b7e0819 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js
@@ -24,7 +24,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="failed" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold js-branch-text">
<span class="capitalize">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js
index 797511d4e3a..00047718201 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.js
@@ -7,7 +7,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="success" showDisabledButton />
+ <status-icon status="success" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
Ready to be merged automatically.
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js
index 167a0d4613a..1cedf86e811 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.js
@@ -7,7 +7,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="failed" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
Pipeline blocked. The pipeline for this merge request requires a manual action to proceed
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js
index c5be9a0530a..6853ba4b9f8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_failed.js
@@ -7,7 +7,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="failed" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure
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 ad709da51ee..edc1d191bf2 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
@@ -38,24 +38,40 @@ export default {
return this.useCommitMessageWithDescription ? withoutDesc : withDesc;
},
- mergeButtonClass() {
- const defaultClass = 'btn btn-sm btn-success accept-merge-request';
- const failedClass = `${defaultClass} btn-danger`;
- const inActionClass = `${defaultClass} btn-info`;
+ status() {
const { pipeline, isPipelineActive, isPipelineFailed, hasCI, ciStatus } = this.mr;
if (hasCI && !ciStatus) {
- return failedClass;
+ return 'failed';
} else if (!pipeline) {
- return defaultClass;
+ return 'success';
} else if (isPipelineActive) {
- return inActionClass;
+ return 'pending';
} else if (isPipelineFailed) {
+ return 'failed';
+ }
+
+ return 'success';
+ },
+ mergeButtonClass() {
+ const defaultClass = 'btn btn-sm btn-success accept-merge-request';
+ const failedClass = `${defaultClass} btn-danger`;
+ const inActionClass = `${defaultClass} btn-info`;
+
+ if (this.status === 'failed') {
return failedClass;
+ } else if (this.status === 'pending') {
+ return inActionClass;
}
return defaultClass;
},
+ iconClass() {
+ if (this.status === 'failed' || !this.commitMessage.length || !this.isMergeAllowed() || this.mr.preventMerge) {
+ return 'failed';
+ }
+ return 'success';
+ },
mergeButtonText() {
if (this.isMergingImmediately) {
return 'Merge in progress';
@@ -156,6 +172,7 @@ export default {
eventHub.$emit('FetchActionsContent');
if (window.mergeRequest) {
window.mergeRequest.updateStatusText('status-box-open', 'status-box-merged', 'Merged');
+ window.mergeRequest.hideCloseButton();
window.mergeRequest.decreaseCounter();
}
stopPolling();
@@ -208,7 +225,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="success" />
+ <status-icon :status="iconClass" />
<div class="media-body">
<div class="mr-widget-body-controls media space-children">
<span class="btn-group append-bottom-5">
@@ -284,10 +301,16 @@ export default {
:mr="mr"
:is-merge-button-disabled="isMergeButtonDisabled" />
+ <span
+ v-if="mr.ffOnlyEnabled"
+ class="js-fast-forward-message">
+ Fast-forward merge without a merge commit
+ </span>
<button
+ v-else
@click="toggleCommitMessageEditor"
:disabled="isMergeButtonDisabled"
- class="btn btn-default btn-xs"
+ class="js-modify-commit-message-button btn btn-default btn-xs"
type="button">
Modify commit message
</button>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js
index 89f38e5bd2a..af19cf6ab87 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_sha_mismatch.js
@@ -7,7 +7,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="failed" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
The source branch HEAD has recently changed. Please reload the page and review the changes before merging
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js
index d762ca6e640..a119ecbbdfe 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_unresolved_discussions.js
@@ -10,7 +10,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon status="failed" :show-disabled-button="true" />
<div class="media-body space-children">
<span class="bold">
There are unresolved discussions. Please resolve these discussions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js
index b11a06899cf..54be1fbe675 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_wip.js
@@ -38,7 +38,7 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" :showDisabledButton="Boolean(mr.removeWIPPath)" />
+ <status-icon status="failed" :show-disabled-button="Boolean(mr.removeWIPPath)" />
<div class="media-body space-children">
<span class="bold">
This is a Work in Progress
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 29464662578..e554082149b 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
@@ -37,10 +37,8 @@ export default class MergeRequestStore {
}
this.updatedAt = data.updated_at;
- this.mergedAt = MergeRequestStore.getEventDate(data.merge_event);
- this.closedAt = MergeRequestStore.getEventDate(data.closed_event);
- this.mergedBy = MergeRequestStore.getAuthorObject(data.merge_event);
- this.closedBy = MergeRequestStore.getAuthorObject(data.closed_event);
+ this.mergedEvent = MergeRequestStore.getEventObject(data.merge_event);
+ this.closedEvent = MergeRequestStore.getEventObject(data.closed_event);
this.setToMWPSBy = MergeRequestStore.getAuthorObject({ author: data.merge_user || {} });
this.mergeUserId = data.merge_user_id;
this.currentUserId = gon.current_user_id;
@@ -57,6 +55,8 @@ export default class MergeRequestStore {
this.onlyAllowMergeIfPipelineSucceeds = data.only_allow_merge_if_pipeline_succeeds || false;
this.mergeWhenPipelineSucceeds = data.merge_when_pipeline_succeeds || false;
this.mergePath = data.merge_path;
+ this.ffOnlyEnabled = data.ff_only_enabled;
+ this.shouldBeRebased = !!data.should_be_rebased;
this.statusPath = data.status_path;
this.emailPatchesPath = data.email_patches_path;
this.plainDiffPath = data.plain_diff_path;
@@ -118,6 +118,14 @@ export default class MergeRequestStore {
}
}
+ static getEventObject(event) {
+ return {
+ author: MergeRequestStore.getAuthorObject(event),
+ updatedAt: gl.utils.formatDate(MergeRequestStore.getEventUpdatedAtDate(event)),
+ formattedUpdatedAt: MergeRequestStore.getEventDate(event),
+ };
+ }
+
static getAuthorObject(event) {
if (!event) {
return {};
@@ -131,6 +139,14 @@ export default class MergeRequestStore {
};
}
+ static getEventUpdatedAtDate(event) {
+ if (!event) {
+ return '';
+ }
+
+ return event.updated_at;
+ }
+
static getEventDate(event) {
const timeagoInstance = new Timeago();
@@ -138,7 +154,7 @@ export default class MergeRequestStore {
return '';
}
- return timeagoInstance.format(event.updated_at);
+ return timeagoInstance.format(MergeRequestStore.getEventUpdatedAtDate(event));
}
}
diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
new file mode 100644
index 00000000000..3a7143c450e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
@@ -0,0 +1,32 @@
+<script>
+ /**
+ * Falls back to the code used in `copy_to_clipboard.js`
+ */
+
+ export default {
+ name: 'clipboardButton',
+ props: {
+ text: {
+ type: String,
+ required: true,
+ },
+ title: {
+ type: String,
+ required: true,
+ },
+ },
+ };
+</script>
+
+<template>
+ <button
+ type="button"
+ class="btn btn-transparent btn-clipboard"
+ :data-title="title"
+ :data-clipboard-text="text">
+ <i
+ aria-hidden="true"
+ class="fa fa-clipboard">
+ </i>
+ </button>
+</template>
diff --git a/app/assets/javascripts/vue_shared/translate.js b/app/assets/javascripts/vue_shared/translate.js
index f83c4b00761..2c7886ec308 100644
--- a/app/assets/javascripts/vue_shared/translate.js
+++ b/app/assets/javascripts/vue_shared/translate.js
@@ -2,6 +2,7 @@ import {
__,
n__,
s__,
+ sprintf,
} from '../locale';
export default (Vue) => {
@@ -37,6 +38,7 @@ export default (Vue) => {
@returns {String} Translated context based text
**/
s__,
+ sprintf,
},
});
};
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index bdcbd4021b3..f1aedc227f3 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -23,6 +23,7 @@
&.s60 { @include avatar-size(60px, 12px); }
&.s70 { @include avatar-size(70px, 14px); }
&.s90 { @include avatar-size(90px, 15px); }
+ &.s100 { @include avatar-size(100px, 15px); }
&.s110 { @include avatar-size(110px, 15px); }
&.s140 { @include avatar-size(140px, 15px); }
&.s160 { @include avatar-size(160px, 20px); }
@@ -78,6 +79,7 @@
&.s60 { font-size: 32px; line-height: 58px; }
&.s70 { font-size: 34px; line-height: 70px; }
&.s90 { font-size: 36px; line-height: 88px; }
+ &.s100 { font-size: 36px; line-height: 98px; }
&.s110 { font-size: 40px; line-height: 108px; font-weight: $gl-font-weight-normal; }
&.s140 { font-size: 72px; line-height: 138px; }
&.s160 { font-size: 96px; line-height: 158px; }
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 706a9cffe87..96f9dda26c4 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -11,6 +11,7 @@
.prepend-top-10 { margin-top: 10px; }
.prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-20 { margin-top: 20px; }
+.prepend-left-4 { margin-left: 4px; }
.prepend-left-5 { margin-left: 5px; }
.prepend-left-10 { margin-left: 10px; }
.prepend-left-default { margin-left: $gl-padding; }
@@ -129,11 +130,6 @@ span.update-author {
}
}
-.user-mention {
- color: $user-mention-color;
- font-weight: $gl-font-weight-bold;
-}
-
.field_with_errors {
display: inline;
}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index c0d8e6c328c..fa92d4ccf4f 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -745,6 +745,10 @@
#{$selector}.dropdown-menu-nav {
margin-bottom: 24px;
+ &.dropdown-open-top {
+ margin-bottom: $dropdown-vertical-offset;
+ }
+
li {
display: block;
padding: 0 1px;
@@ -873,6 +877,13 @@
min-width: 100%;
}
}
+
+ header.navbar-gitlab-new .header-content .dropdown {
+ .dropdown-menu {
+ left: 0;
+ min-width: 100%;
+ }
+ }
}
@include new-style-dropdown('.breadcrumbs-list .dropdown ');
diff --git a/app/assets/stylesheets/framework/gfm.scss b/app/assets/stylesheets/framework/gfm.scss
index dbdd5a4464b..34a35734acc 100644
--- a/app/assets/stylesheets/framework/gfm.scss
+++ b/app/assets/stylesheets/framework/gfm.scss
@@ -6,3 +6,14 @@
.gfm-commit_range {
@extend .commit-sha;
}
+
+.gfm-project_member {
+ padding: 0 2px;
+ border-radius: #{$border-radius-default / 2};
+ background-color: $user-mention-bg;
+
+ &:hover {
+ background-color: $user-mention-bg-hover;
+ text-decoration: none;
+ }
+}
diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss
index 0d1c04026b8..6b69e8018be 100644
--- a/app/assets/stylesheets/framework/gitlab-theme.scss
+++ b/app/assets/stylesheets/framework/gitlab-theme.scss
@@ -126,7 +126,7 @@
.search-input-wrap {
.search-icon,
.clear-icon {
- color: rgba($color-200, .8);
+ fill: rgba($color-200, .8);
}
}
@@ -141,7 +141,7 @@
.search-input-wrap {
.search-icon {
- color: rgba($color-200, .8);
+ fill: rgba($color-200, .8);
}
}
}
@@ -252,7 +252,7 @@ body {
.search-input-wrap {
.search-icon {
- color: $theme-gray-200;
+ fill: $theme-gray-200;
}
.search-input {
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index ab3c34df1fb..d932ea8794f 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -109,8 +109,7 @@ header {
.user-counter {
svg {
- height: 16px;
- width: 23px;
+ margin-right: 3px;
}
}
@@ -133,16 +132,16 @@ header {
}
&.navbar-gitlab-new {
- .fa-times {
+ .close-icon {
display: none;
}
.menu-expanded {
- .fa-ellipsis-v {
+ .more-icon {
display: none;
}
- .fa-times {
+ .close-icon {
display: block;
}
}
diff --git a/app/assets/stylesheets/framework/images.scss b/app/assets/stylesheets/framework/images.scss
index 60d61c68d63..59bfc5a8d77 100644
--- a/app/assets/stylesheets/framework/images.scss
+++ b/app/assets/stylesheets/framework/images.scss
@@ -27,7 +27,9 @@
}
svg {
+ &.s8 { @include svg-size(8px); }
&.s16 { @include svg-size(16px); }
+ &.s18 { @include svg-size(18px); }
&.s24 { @include svg-size(24px); }
&.s32 { @include svg-size(32px); }
&.s48 { @include svg-size(48px); }
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index 0fb19344510..badc7b0eba3 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -229,6 +229,10 @@ ul.content-list {
.label-default {
color: $gl-text-color-secondary;
}
+
+ .avatar-cell {
+ align-self: flex-start;
+ }
}
.panel > .content-list > li {
diff --git a/app/assets/stylesheets/framework/new-nav.scss b/app/assets/stylesheets/framework/new-nav.scss
index 81022d4af2a..7899be2c2d3 100644
--- a/app/assets/stylesheets/framework/new-nav.scss
+++ b/app/assets/stylesheets/framework/new-nav.scss
@@ -120,17 +120,24 @@ header.navbar-gitlab-new {
.container-fluid {
.navbar-toggle {
min-width: 45px;
- padding: 4px $gl-padding;
+ padding: 0 $gl-padding;
margin-right: -7px;
- font-size: 14px;
text-align: center;
color: currentColor;
+ svg {
+ fill: currentColor;
+ }
+
&:hover,
&:focus,
&.active {
color: currentColor;
background-color: transparent;
+
+ svg {
+ fill: currentColor;
+ }
}
}
@@ -279,10 +286,6 @@ header.navbar-gitlab-new {
}
}
-.admin-icon i {
- font-size: 18px;
-}
-
.caret-down {
height: 11px;
width: 11px;
@@ -292,7 +295,7 @@ header.navbar-gitlab-new {
.header-user .dropdown-menu-nav,
.header-new .dropdown-menu-nav {
- margin-top: 4px;
+ margin-top: $dropdown-vertical-offset;
}
.breadcrumbs {
diff --git a/app/assets/stylesheets/framework/new-sidebar.scss b/app/assets/stylesheets/framework/new-sidebar.scss
index 3f1cb97aebc..8332cec2962 100644
--- a/app/assets/stylesheets/framework/new-sidebar.scss
+++ b/app/assets/stylesheets/framework/new-sidebar.scss
@@ -56,8 +56,8 @@ $new-sidebar-collapsed-width: 50px;
color: $hover-color;
.settings-avatar {
- i {
- color: $hover-color;
+ svg {
+ fill: $hover-color;
}
}
}
@@ -76,12 +76,9 @@ $new-sidebar-collapsed-width: 50px;
.settings-avatar {
background-color: $white-light;
- i {
- font-size: 20px;
- width: 100%;
- color: $gl-text-color-secondary;
- text-align: center;
- align-self: center;
+ svg {
+ fill: $gl-text-color-secondary;
+ margin: auto;
}
}
@@ -177,16 +174,16 @@ $new-sidebar-collapsed-width: 50px;
.nav-icon-container {
display: flex;
margin-right: 8px;
-
- svg {
- height: 16px;
- width: 16px;
- }
}
.fly-out-top-item {
display: none;
}
+
+ svg {
+ height: 16px;
+ width: 16px;
+ }
}
.nav-sidebar-inner-scroll {
@@ -354,18 +351,22 @@ $new-sidebar-collapsed-width: 50px;
display: flex;
align-items: center;
- i {
- font-size: 20px;
+ svg {
+ fill: $gl-text-color-secondary;
margin-right: 8px;
}
- .fa-angle-double-right {
+ .icon-angle-double-right {
display: none;
}
&:hover {
background-color: $border-color;
color: $gl-text-color;
+
+ svg {
+ fill: $gl-text-color;
+ }
}
}
@@ -407,15 +408,16 @@ $new-sidebar-collapsed-width: 50px;
.toggle-sidebar-button {
width: $new-sidebar-collapsed-width - 2px;
- padding: 16px 18px;
+ padding: 16px;
.collapse-text,
- .fa-angle-double-left {
+ .icon-angle-double-left {
display: none;
}
- .fa-angle-double-right {
+ .icon-angle-double-right {
display: block;
+ margin: 0;
}
}
}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 6c14e8b97e0..50f1445bc2e 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -48,31 +48,24 @@
}
&:hover {
- background-color: $white-normal;
- border-color: $border-white-normal;
+ border-color: $gray-darkest;
color: $gl-text-color;
}
}
}
-.select2-drop {
- box-shadow: $select2-drop-shadow1 0 0 1px 0, $select2-drop-shadow2 0 2px 18px 0;
- border-radius: $border-radius-default;
- border: none;
+.select2-drop,
+.select2-drop.select2-drop-above {
+ box-shadow: 0 2px 4px $dropdown-shadow-color;
+ border-radius: $border-radius-base;
+ border: 1px solid $dropdown-border-color;
min-width: 175px;
+ color: $gl-text-color;
}
-.select2-results .select2-result-label,
-.select2-more-results {
- padding: 10px 15px;
-}
-
-.select2-drop {
- color: $gl-grayish-blue;
-}
-
-.select2-highlighted {
- background: $gl-link-color !important;
+.select2-drop.select2-drop-above.select2-drop-active {
+ border-top: 1px solid $dropdown-border-color;
+ margin-top: -6px;
}
.select2-results li.select2-result-with-children > .select2-result-label {
@@ -87,13 +80,11 @@
}
}
-.select2-dropdown-open {
+.select2-dropdown-open,
+.select2-dropdown-open.select2-drop-above {
.select2-choice {
- border-color: $border-white-normal;
+ border-color: $gray-darkest;
outline: 0;
- background-image: none;
- background-color: $white-dark;
- box-shadow: $gl-btn-active-gradient;
}
}
@@ -131,28 +122,14 @@
}
}
}
-
- &.select2-container-active .select2-choices,
- &.select2-dropdown-open .select2-choices {
- border-color: $border-white-normal;
- box-shadow: $gl-btn-active-gradient;
- }
}
.select2-drop-active {
- margin-top: 6px;
+ margin-top: $dropdown-vertical-offset;
font-size: 14px;
- &.select2-drop-above {
- margin-bottom: 8px;
- }
-
.select2-results {
max-height: 350px;
-
- .select2-highlighted {
- background: $gl-primary;
- }
}
}
@@ -186,19 +163,35 @@
background-size: 16px 16px !important;
}
-.select2-results .select2-no-results,
-.select2-results .select2-searching,
-.select2-results .select2-ajax-error,
-.select2-results .select2-selection-limit {
- background: $gray-light;
- display: list-item;
- padding: 10px 15px;
-}
-
-
.select2-results {
margin: 0;
- padding: 10px 0;
+ padding: #{$gl-padding / 2} 0;
+
+ .select2-no-results,
+ .select2-searching,
+ .select2-ajax-error,
+ .select2-selection-limit {
+ background: transparent;
+ padding: #{$gl-padding / 2} $gl-padding;
+ }
+
+ .select2-result-label,
+ .select2-more-results {
+ padding: #{$gl-padding / 2} $gl-padding;
+ }
+
+ .select2-highlighted {
+ background: transparent;
+ color: $gl-text-color;
+
+ .select2-result-label {
+ background: $dropdown-item-hover-bg;
+ }
+ }
+
+ .select2-result {
+ padding: 0 1px;
+ }
}
.ajax-users-select {
@@ -265,56 +258,10 @@
min-width: 250px !important;
}
-// TODO: change global style
-.ajax-project-dropdown,
-.ajax-users-dropdown,
-body[data-page="projects:edit"] #select2-drop,
-body[data-page="projects:new"] #select2-drop,
-body[data-page="projects:merge_requests:edit"] #select2-drop,
-body[data-page="projects:blob:new"] #select2-drop,
-body[data-page="profiles:show"] #select2-drop,
-body[data-page="admin:groups:show"] #select2-drop,
-body[data-page="projects:issues:show"] #select2-drop,
-body[data-page="projects:blob:edit"] #select2-drop {
- &.select2-drop {
- border: 1px solid $dropdown-border-color;
- border-radius: $border-radius-base;
- color: $gl-text-color;
- }
-
- &.select2-drop-above {
- border-top: none;
- margin-top: -4px;
- }
-
- .select2-results {
- .select2-no-results,
- .select2-searching,
- .select2-ajax-error,
- .select2-selection-limit {
- background: transparent;
- }
-
- .select2-result {
- padding: 0 1px;
-
- .select2-match {
- font-weight: $gl-font-weight-bold;
- text-decoration: none;
- }
-
- .select2-result-label {
- padding: #{$gl-padding / 2} $gl-padding;
- }
-
- &.select2-highlighted {
- background-color: transparent !important;
- color: $gl-text-color;
-
- .select2-result-label {
- background-color: $dropdown-item-hover-bg;
- }
- }
- }
+.select2-result-selectable,
+.select2-result-unselectable {
+ .select2-match {
+ font-weight: $gl-font-weight-bold;
+ text-decoration: none;
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index e8bb42f4a8c..60260355765 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -262,7 +262,8 @@ $well-pre-bg: #eee;
$well-pre-color: #555;
$loading-color: #555;
$update-author-color: #999;
-$user-mention-color: #2fa0bb;
+$user-mention-bg: rgba($blue-500, 0.044);
+$user-mention-bg-hover: rgba($blue-500, 0.15);
$time-color: #999;
$project-member-show-color: #aaa;
$gl-promo-color: #aaa;
@@ -327,6 +328,7 @@ $regular_font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-San
* Dropdowns
*/
$dropdown-width: 300px;
+$dropdown-vertical-offset: 4px;
$dropdown-link-color: #555;
$dropdown-link-hover-bg: $row-hover;
$dropdown-empty-row-bg: rgba(#000, .04);
diff --git a/app/assets/stylesheets/pages/container_registry.scss b/app/assets/stylesheets/pages/container_registry.scss
index 3266714396e..dfff3e15556 100644
--- a/app/assets/stylesheets/pages/container_registry.scss
+++ b/app/assets/stylesheets/pages/container_registry.scss
@@ -9,6 +9,14 @@
.container-image-head {
padding: 0 16px;
line-height: 4em;
+
+ .btn-link {
+ padding: 0;
+
+ &:focus {
+ outline: none;
+ }
+ }
}
.table.tags {
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index e4bd783c8bc..fb23343b966 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -77,6 +77,18 @@
word-wrap: break-word;
}
}
+
+ &.left-side-selected {
+ td.line_content.parallel.right-side {
+ @include user-select(none);
+ }
+ }
+
+ &.right-side-selected {
+ td.line_content.parallel.left-side {
+ @include user-select(none);
+ }
+ }
}
tr.line_holder.parallel {
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 9362d80d4e6..6a9c2578d95 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -207,10 +207,13 @@
}
.prometheus-state {
- margin-top: 10px;
+ max-width: 430px;
+ margin: 10px auto;
+ text-align: center;
- .state-button-section {
- margin-top: 10px;
+ .state-svg {
+ max-width: 80vw;
+ margin: 0 auto;
}
}
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index be4db597689..74d9acb5490 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -362,7 +362,7 @@
.dropdown-menu {
top: initial;
- bottom: 40px;
+ bottom: 100%;
width: 298px;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 6400b72742c..a086c11324d 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -499,64 +499,56 @@ a.deploy-project-label {
}
}
-.fork-namespaces {
- .row {
- -webkit-flex-wrap: wrap;
- display: -webkit-flex;
- display: flex;
- flex-wrap: wrap;
- justify-content: flex-start;
+.fork-thumbnail {
+ height: 200px;
+ width: calc((100% / 2) - #{$gl-padding * 2});
- .fork-thumbnail {
- border-radius: $border-radius-base;
- background-color: $white-light;
- border: 1px solid $border-white-light;
- height: 202px;
- margin: $gl-padding;
- text-align: center;
- width: 169px;
+ @media (min-width: $screen-md-min) {
+ width: calc((100% / 4) - #{$gl-padding * 2});
+ }
- &:hover,
- &.forked {
- background-color: $row-hover;
- border-color: $row-hover-border;
- }
+ @media (min-width: $screen-lg-min) {
+ width: calc((100% / 5) - #{$gl-padding * 2});
+ }
- .no-avatar {
- width: 100px;
- height: 100px;
- background-color: $gray-light;
- border: 1px solid $white-normal;
- margin: 0 auto;
- border-radius: 50%;
-
- i {
- font-size: 100px;
- color: $white-normal;
- }
- }
+ &:hover:not(.disabled),
+ &.forked {
+ background-color: $row-hover;
+ border-color: $row-hover-border;
+ }
- a {
- display: block;
- width: 100%;
- height: 100%;
- padding-top: $gl-padding;
- color: $gl-text-color;
-
- .caption {
- min-height: 30px;
- padding: $gl-padding 0;
- }
- }
+ .avatar-container,
+ .identicon {
+ float: none;
+ margin-left: auto;
+ margin-right: auto;
+ }
- img {
- border-radius: 50%;
- max-width: 100px;
- }
+ a {
+ display: block;
+ width: 100%;
+ height: 100%;
+ padding-top: $gl-padding;
+ text-decoration: none;
+
+ &.disabled {
+ opacity: .3;
+ cursor: not-allowed;
}
}
}
+.fork-thumbnail-container {
+ display: flex;
+ flex-wrap: wrap;
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+
+ > h5 {
+ width: 100%;
+ }
+}
+
.project-template,
.project-import {
.form-group {
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 2fa710a05b5..89ebe3f9917 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -81,17 +81,10 @@ input[type="checkbox"]:hover {
.clear-icon {
position: absolute;
right: 5px;
- top: 0;
-
- &::before {
- font-family: FontAwesome;
- font-weight: $gl-font-weight-normal;
- font-style: normal;
- }
+ top: 4px;
}
.search-icon {
- @extend .fa-search;
transition: color $default-transition-duration;
-webkit-user-select: none;
-moz-user-select: none;
@@ -99,7 +92,6 @@ input[type="checkbox"]:hover {
}
.clear-icon {
- @extend .fa-times;
display: none;
}
diff --git a/app/assets/stylesheets/pages/settings_ci_cd.scss b/app/assets/stylesheets/pages/settings_ci_cd.scss
index fe22d186af1..a355e2dee24 100644
--- a/app/assets/stylesheets/pages/settings_ci_cd.scss
+++ b/app/assets/stylesheets/pages/settings_ci_cd.scss
@@ -12,3 +12,7 @@
margin-left: 10px;
}
}
+
+.registry-placeholder {
+ min-height: 60px;
+}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 97922e39ba8..967fe39256a 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -25,6 +25,8 @@ class ApplicationController < ActionController::Base
around_action :set_locale
+ after_action :set_page_title_header, if: -> { request.format == :json }
+
protect_from_forgery with: :exception
helper_method :can?, :current_application_settings
@@ -83,12 +85,21 @@ class ApplicationController < ActionController::Base
super
payload[:remote_ip] = request.remote_ip
- if current_user.present?
- payload[:user_id] = current_user.id
- payload[:username] = current_user.username
+ logged_user = auth_user
+
+ if logged_user.present?
+ payload[:user_id] = logged_user.try(:id)
+ payload[:username] = logged_user.try(:username)
end
end
+ # Controllers such as GitHttpController may use alternative methods
+ # (e.g. tokens) to authenticate the user, whereas Devise sets current_user
+ def auth_user
+ return current_user if current_user.present?
+ return try(:authenticated_user)
+ end
+
# This filter handles both private tokens and personal access tokens
def authenticate_user_from_private_token!
token = params[:private_token].presence || request.headers['PRIVATE-TOKEN'].presence
@@ -335,4 +346,9 @@ class ApplicationController < ActionController::Base
sign_in user, store: false
end
end
+
+ def set_page_title_header
+ # Per https://tools.ietf.org/html/rfc5987, headers need to be ISO-8859-1, not UTF-8
+ response.headers['Page-Title'] = page_title('GitLab').encode('ISO-8859-1')
+ end
end
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index b75e401a8df..db8c362f125 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -59,6 +59,7 @@ module AuthenticatesWithTwoFactor
sign_in(user)
else
user.increment_failed_attempts!
+ Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=OTP")
flash.now[:alert] = 'Invalid two-factor code.'
prompt_for_two_factor(user)
end
@@ -75,6 +76,7 @@ module AuthenticatesWithTwoFactor
sign_in(user)
else
user.increment_failed_attempts!
+ Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=U2F")
flash.now[:alert] = 'Authentication via U2F device failed.'
prompt_for_two_factor(user)
end
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index 18fd8eb114d..915f32b4c33 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -15,9 +15,9 @@ module NotesActions
notes = notes_finder.execute
.inc_relations_for_view
- .reject { |n| n.cross_reference_not_visible_for?(current_user) }
notes = prepare_notes_for_rendering(notes)
+ notes = notes.reject { |n| n.cross_reference_not_visible_for?(current_user) }
notes_json[:notes] =
if noteable.discussions_rendered_on_frontend?
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index 10d2665c06a..0c2646d7bf0 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -14,6 +14,7 @@ class ConfirmationsController < Devise::ConfirmationsController
if signed_in?(resource_name)
after_sign_in(resource)
else
+ Gitlab::AppLogger.info("Email Confirmed: username=#{resource.username} email=#{resource.email} ip=#{request.remote_ip}")
flash[:notice] += " Please sign in."
new_session_path(resource_name)
end
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index c1cc509a748..4146deefa89 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -1,6 +1,7 @@
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
def index
set_index_vars
+ @personal_access_token = finder.build
end
def create
@@ -40,7 +41,6 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
def set_index_vars
@scopes = Gitlab::Auth.available_scopes
- @personal_access_token = finder.build
@inactive_personal_access_tokens = finder(state: 'inactive').execute
@active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at)
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 1cfee229473..6e424c7c3f8 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -45,6 +45,8 @@ class Projects::BlobController < Projects::ApplicationController
end
format.json do
+ page_title @blob.path, @ref, @project.name_with_namespace
+
render json: BlobSerializer.new(project: @project, repository: @repository, ref: @ref, commit: @commit, params: params).represent(@blob)
end
end
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index a9cce578366..7f03ce07dec 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -9,7 +9,7 @@ class Projects::BranchesController < Projects::ApplicationController
def index
@sort = params[:sort].presence || sort_value_recently_updated
- @branches = BranchesFinder.new(@repository, params).execute
+ @branches = BranchesFinder.new(@repository, params.merge(sort: @sort)).execute
@branches = Kaminari.paginate_array(@branches).page(params[:page])
respond_to do |format|
diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb
index 7d0e2b3e2ef..95d7a02e9e9 100644
--- a/app/controllers/projects/git_http_client_controller.rb
+++ b/app/controllers/projects/git_http_client_controller.rb
@@ -9,6 +9,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
delegate :actor, :authentication_abilities, to: :authentication_result, allow_nil: true
alias_method :user, :actor
+ alias_method :authenticated_user, :actor
# Git clients will not know what authenticity token to send along
skip_before_action :verify_authenticity_token
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index a3ec79a56d9..ee6e6f80cdd 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -16,7 +16,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :authorize_create_issue!, only: [:new, :create]
# Allow modify issue
- before_action :authorize_update_issue!, only: [:edit, :update, :move]
+ before_action :authorize_update_issue!, only: [:update, :move]
# Allow create a new branch and empty WIP merge request from current issue
before_action :authorize_create_merge_request!, only: [:create_merge_request]
@@ -63,10 +63,6 @@ class Projects::IssuesController < Projects::ApplicationController
respond_with(@issue)
end
- def edit
- respond_with(@issue)
- end
-
def show
@noteable = @issue
@note = @project.notes.new(noteable: @issue)
@@ -126,10 +122,6 @@ class Projects::IssuesController < Projects::ApplicationController
@issue = Issues::UpdateService.new(project, current_user, update_params).execute(issue)
respond_to do |format|
- format.html do
- recaptcha_check_with_fallback { render :edit }
- end
-
format.json do
render_issue_json
end
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
index 71e7dc70a4d..32c0fc6d14a 100644
--- a/app/controllers/projects/registry/repositories_controller.rb
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -6,17 +6,26 @@ module Projects
def index
@images = project.container_repositories
+
+ respond_to do |format|
+ format.html
+ format.json do
+ render json: ContainerRepositoriesSerializer
+ .new(project: project, current_user: current_user)
+ .represent(@images)
+ end
+ end
end
def destroy
if image.destroy
- redirect_to project_container_registry_index_path(@project),
- status: 302,
- notice: 'Image repository has been removed successfully!'
+ respond_to do |format|
+ format.json { head :no_content }
+ end
else
- redirect_to project_container_registry_index_path(@project),
- status: 302,
- alert: 'Failed to remove image repository!'
+ respond_to do |format|
+ format.json { head :bad_request }
+ end
end
end
diff --git a/app/controllers/projects/registry/tags_controller.rb b/app/controllers/projects/registry/tags_controller.rb
index ae72bd03cfb..e602aa3f393 100644
--- a/app/controllers/projects/registry/tags_controller.rb
+++ b/app/controllers/projects/registry/tags_controller.rb
@@ -3,20 +3,35 @@ module Projects
class TagsController < ::Projects::Registry::ApplicationController
before_action :authorize_update_container_image!, only: [:destroy]
+ def index
+ respond_to do |format|
+ format.json do
+ render json: ContainerTagsSerializer
+ .new(project: @project, current_user: @current_user)
+ .with_pagination(request, response)
+ .represent(tags)
+ end
+ end
+ end
+
def destroy
if tag.delete
- redirect_to project_container_registry_index_path(@project),
- status: 302,
- notice: 'Registry tag has been removed successfully!'
+ respond_to do |format|
+ format.json { head :no_content }
+ end
else
- redirect_to project_container_registry_index_path(@project),
- status: 302,
- alert: 'Failed to remove registry tag!'
+ respond_to do |format|
+ format.json { head :bad_request }
+ end
end
end
private
+ def tags
+ Kaminari::PaginatableArray.new(image.tags, limit: 15)
+ end
+
def image
@image ||= project.container_repositories
.find(params[:repository_id])
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index f3784f4e07c..f3719059f88 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -35,6 +35,8 @@ class Projects::TreeController < Projects::ApplicationController
end
format.json do
+ page_title @path.presence || _("Files"), @ref, @project.name_with_namespace
+
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/38261
Gitlab::GitalyClient.allow_n_plus_1_calls do
render json: TreeSerializer.new(project: @project, repository: @repository, ref: @ref).represent(@tree)
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 968d880886c..a8ebdf5a4a9 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -18,16 +18,12 @@ class Projects::WikisController < Projects::ApplicationController
response.headers['Content-Security-Policy'] = "default-src 'none'"
response.headers['X-Content-Security-Policy'] = "default-src 'none'"
- if file.on_disk?
- send_file file.on_disk_path, disposition: 'inline'
- else
- send_data(
- file.raw_data,
- type: file.mime_type,
- disposition: 'inline',
- filename: file.name
- )
- end
+ send_data(
+ file.raw_data,
+ type: file.mime_type,
+ disposition: 'inline',
+ filename: file.name
+ )
else
return render('empty') unless can?(current_user, :create_wiki, @project)
@page = WikiPage.new(@project_wiki)
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index b13034d3333..a738ca9f361 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -344,6 +344,7 @@ class ProjectsController < Projects::ApplicationController
:tag_list,
:visibility_level,
:template_name,
+ :merge_method,
project_feature_attributes: %i[
builds_access_level
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 1bc6520370a..5ea3a5d5562 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -42,10 +42,12 @@ class RegistrationsController < Devise::RegistrationsController
end
def after_sign_up_path_for(user)
+ Gitlab::AppLogger.info("User Created: username=#{user.username} email=#{user.email} ip=#{request.remote_ip} confirmed:#{user.confirmed?}")
user.confirmed? ? dashboard_projects_path : users_almost_there_path
end
- def after_inactive_sign_up_path_for(_resource)
+ def after_inactive_sign_up_path_for(resource)
+ Gitlab::AppLogger.info("User Created: username=#{resource.username} email=#{resource.email} ip=#{request.remote_ip} confirmed:false")
users_almost_there_path
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index fe3bb117410..4223c6171a6 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -13,6 +13,8 @@ class SessionsController < Devise::SessionsController
before_action :auto_sign_in_with_provider, only: [:new]
before_action :load_recaptcha
+ after_action :log_failed_login, only: [:new]
+
def new
set_minimum_password_length
@ldap_servers = Gitlab::LDAP::Config.available_servers
@@ -29,12 +31,13 @@ class SessionsController < Devise::SessionsController
end
# hide the signed-in notification
flash[:notice] = nil
- log_audit_event(current_user, with: authentication_method)
+ log_audit_event(current_user, resource, with: authentication_method)
log_user_activity(current_user)
end
end
def destroy
+ Gitlab::AppLogger.info("User Logout: username=#{current_user.username} ip=#{request.remote_ip}")
super
# hide the signed_out notice
flash[:notice] = nil
@@ -42,6 +45,16 @@ class SessionsController < Devise::SessionsController
private
+ def log_failed_login
+ return unless failed_login?
+
+ Gitlab::AppLogger.info("Failed Login: username=#{user_params[:login]} ip=#{request.remote_ip}")
+ end
+
+ def failed_login?
+ (options = env["warden.options"]) && options[:action] == "unauthenticated"
+ end
+
def login_counter
@login_counter ||= Gitlab::Metrics.counter(:user_session_logins_total, 'User sign in count')
end
@@ -123,7 +136,8 @@ class SessionsController < Devise::SessionsController
user.invalidate_otp_backup_code!(user_params[:otp_attempt])
end
- def log_audit_event(user, options = {})
+ def log_audit_event(user, resource, options = {})
+ Gitlab::AppLogger.info("Successful Login: username=#{resource.username} ip=#{request.remote_ip} method=#{options[:with]} admin=#{resource.admin?}")
AuditEventService.new(user, user, options)
.for_authentication.security_event
end
diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb
index ee1b7ed083e..e88fe6bcd7e 100644
--- a/app/helpers/breadcrumbs_helper.rb
+++ b/app/helpers/breadcrumbs_helper.rb
@@ -10,11 +10,7 @@ module BreadcrumbsHelper
def breadcrumb_title_link
return @breadcrumb_link if @breadcrumb_link
- if controller.available_action?(:index)
- url_for(action: "index")
- else
- request.path
- end
+ request.path
end
def breadcrumb_title(title)
@@ -25,7 +21,7 @@ module BreadcrumbsHelper
def breadcrumb_list_item(link)
content_tag "li" do
- link + icon("angle-right", class: "breadcrumbs-list-angle")
+ link + sprite_icon("angle-right", size: 8, css_class: "breadcrumbs-list-angle")
end
end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 28f591a4e22..4e4a66e8a02 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -33,19 +33,21 @@ module DiffHelper
end
def diff_match_line(old_pos, new_pos, text: '', view: :inline, bottom: false)
- content = content_tag :td, text, class: "line_content match #{view == :inline ? '' : view}"
- cls = ['diff-line-num', 'unfold', 'js-unfold']
- cls << 'js-unfold-bottom' if bottom
+ content_line_class = %w[line_content match]
+ content_line_class << 'parallel' if view == :parallel
+
+ line_num_class = %w[diff-line-num unfold js-unfold]
+ line_num_class << 'js-unfold-bottom' if bottom
html = ''
if old_pos
- html << content_tag(:td, '...', class: cls + ['old_line'], data: { linenumber: old_pos })
- html << content unless view == :inline
+ html << content_tag(:td, '...', class: [*line_num_class, 'old_line'], data: { linenumber: old_pos })
+ html << content_tag(:td, text, class: [*content_line_class, 'left-side']) if view == :parallel
end
if new_pos
- html << content_tag(:td, '...', class: cls + ['new_line'], data: { linenumber: new_pos })
- html << content
+ html << content_tag(:td, '...', class: [*line_num_class, 'new_line'], data: { linenumber: new_pos })
+ html << content_tag(:td, text, class: [*content_line_class, ('right-side' if view == :parallel)])
end
html.html_safe
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index b331693c789..fd88e0d794a 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -1,13 +1,15 @@
module EventsHelper
ICON_NAMES_BY_EVENT_TYPE = {
- 'pushed to' => 'icon_commit',
- 'pushed new' => 'icon_commit',
- 'created' => 'icon_status_open',
- 'opened' => 'icon_status_open',
- 'closed' => 'icon_status_closed',
- 'accepted' => 'icon_code_fork',
- 'commented on' => 'icon_comment_o',
- 'deleted' => 'icon_trash_o'
+ 'pushed to' => 'commit',
+ 'pushed new' => 'commit',
+ 'created' => 'status_open',
+ 'opened' => 'status_open',
+ 'closed' => 'status_closed',
+ 'accepted' => 'fork',
+ 'commented on' => 'comment',
+ 'deleted' => 'remove',
+ 'imported' => 'import',
+ 'joined' => 'users'
}.freeze
def link_to_author(event, self_added: false)
@@ -197,7 +199,7 @@ module EventsHelper
def icon_for_event(note)
icon_name = ICON_NAMES_BY_EVENT_TYPE[note]
- custom_icon(icon_name) if icon_name
+ sprite_icon(icon_name) if icon_name
end
def icon_for_profile_event(event)
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 08e6443bd0f..ec779c1c447 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -24,9 +24,9 @@ module IconsHelper
end
def sprite_icon(icon_name, size: nil, css_class: nil)
- css_classes = size ? "s#{size}" : nil
+ css_classes = size ? "s#{size}" : ""
css_classes << " #{css_class}" unless css_class.blank?
- content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{image_path('icons.svg')}##{icon_name}" } ), class: css_classes)
+ content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{image_path('icons.svg')}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes)
end
def audit_icon(names, options = {})
diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb
index 5946c475835..18b9bf214a3 100644
--- a/app/helpers/page_layout_helper.rb
+++ b/app/helpers/page_layout_helper.rb
@@ -9,7 +9,7 @@ module PageLayoutHelper
end
# Segments are seperated by middot
- @page_title.join(" \u00b7 ")
+ @page_title.join(" · ")
end
# Define or get a description for the current page
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 21fb17e06d6..4c0cce54527 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -21,11 +21,14 @@ module ProjectsHelper
classes = %W[avatar avatar-inline s#{opts[:size]}]
classes << opts[:avatar_class] if opts[:avatar_class]
- image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: classes, alt: '')
+ avatar = avatar_icon(author, opts[:size])
+ src = opts[:lazy_load] ? nil : avatar
+
+ image_tag(src, width: opts[:size], class: classes, alt: '', "data-src" => avatar)
end
def link_to_member(project, author, opts = {}, &block)
- default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name", tooltip: false }
+ default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name", tooltip: false, lazy_load: false }
opts = default_opts.merge(opts)
return "(deleted)" unless author
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index ee544d8ac56..dd315866e60 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -229,6 +229,10 @@ module Ci
variables
end
+ def features
+ { trace_sections: true }
+ end
+
def merge_request
return @merge_request if defined?(@merge_request)
diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb
index 44deae4234b..54bd5b68777 100644
--- a/app/models/gpg_key.rb
+++ b/app/models/gpg_key.rb
@@ -73,7 +73,7 @@ class GpgKey < ActiveRecord::Base
end
def verified_and_belongs_to_email?(email)
- emails_with_verified_status.fetch(email, false)
+ emails_with_verified_status.fetch(email.downcase, false)
end
def update_invalid_gpg_signatures
diff --git a/app/models/key.rb b/app/models/key.rb
index 0c41e34d969..f119b15c737 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -34,6 +34,7 @@ class Key < ActiveRecord::Base
value&.delete!("\n\r")
value.strip! unless value.blank?
write_attribute(:key, value)
+ @public_key = nil
end
def publishable_key
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 8d9a30397a9..0ba00d447e8 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -524,6 +524,14 @@ class MergeRequest < ActiveRecord::Base
true
end
+ def ff_merge_possible?
+ project.repository.ancestor?(target_branch_sha, diff_head_sha)
+ end
+
+ def should_be_rebased?
+ project.ff_merge_must_be_possible? && !ff_merge_possible?
+ end
+
def can_cancel_merge_when_pipeline_succeeds?(current_user)
can_be_merged_by?(current_user) || self.author == current_user
end
@@ -552,14 +560,20 @@ class MergeRequest < ActiveRecord::Base
commits_for_notes_limit = 100
commit_ids = commit_shas.take(commits_for_notes_limit)
- Note.where(
- "(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" +
- "((project_id = :source_project_id OR project_id = :target_project_id) AND noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
- mr_id: id,
- commit_ids: commit_ids,
- target_project_id: target_project_id,
- source_project_id: source_project_id
- )
+ commit_notes = Note
+ .except(:order)
+ .where(project_id: [source_project_id, target_project_id])
+ .where(noteable_type: 'Commit', commit_id: commit_ids)
+
+ # We're using a UNION ALL here since this results in better performance
+ # compared to using OR statements. We're using UNION ALL since the queries
+ # used won't produce any duplicates (e.g. a note for a commit can't also be
+ # a note for an MR).
+ union = Gitlab::SQL::Union
+ .new([notes, commit_notes], remove_duplicates: false)
+ .to_sql
+
+ Note.from("(#{union}) #{Note.table_name}")
end
alias_method :discussion_notes, :related_notes
@@ -734,10 +748,9 @@ class MergeRequest < ActiveRecord::Base
end
def has_ci?
- has_ci_integration = source_project.try(:ci_service)
- uses_gitlab_ci = all_pipelines.any?
+ return false if has_no_commits?
- (has_ci_integration || uses_gitlab_ci) && commits.any?
+ !!(head_pipeline_id || all_pipelines.any? || source_project&.ci_service)
end
def branch_missing?
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index 1f9d712ef84..cfcb03138b7 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -17,6 +17,8 @@ class PersonalAccessToken < ActiveRecord::Base
validates :scopes, presence: true
validate :validate_scopes
+ after_initialize :set_default_scopes, if: :persisted?
+
def revoke!
update!(revoked: true)
end
@@ -32,4 +34,8 @@ class PersonalAccessToken < ActiveRecord::Base
errors.add :scopes, "can only contain available scopes"
end
end
+
+ def set_default_scopes
+ self.scopes = Gitlab::Auth::DEFAULT_SCOPES if self.scopes.empty?
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 9b10401f5b8..59b5a5b3cd7 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -64,6 +64,7 @@ class Project < ActiveRecord::Base
# Storage specific hooks
after_initialize :use_hashed_storage
+ after_create :check_repository_absence!
after_create :ensure_storage_path_exists
after_save :ensure_storage_path_exists, if: :namespace_id_changed?
@@ -72,6 +73,7 @@ class Project < ActiveRecord::Base
attr_accessor :old_path_with_namespace
attr_accessor :template_name
attr_writer :pipeline_status
+ attr_accessor :skip_disk_validation
alias_attribute :title, :name
@@ -227,7 +229,7 @@ class Project < ActiveRecord::Base
validates :import_url, importable_url: true, if: [:external_import?, :import_url_changed?]
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create
- validate :can_create_repository?, on: [:create, :update], if: ->(project) { !project.persisted? || project.renamed? }
+ validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? }
validate :avatar_type,
if: ->(project) { project.avatar.present? && project.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
@@ -1018,12 +1020,15 @@ class Project < ActiveRecord::Base
end
# Check if repository already exists on disk
- def can_create_repository?
+ def check_repository_path_availability
+ return true if skip_disk_validation
return false unless repository_storage_path
expires_full_path_cache # we need to clear cache to validate renames correctly
- if gitlab_shell.exists?(repository_storage_path, "#{disk_path}.git")
+ # Check if repository with same path already exists on disk we can
+ # skip this for the hashed storage because the path does not change
+ if legacy_storage? && repository_with_same_path_already_exists?
errors.add(:base, 'There is already a repository with that name on disk')
return false
end
@@ -1035,7 +1040,7 @@ class Project < ActiveRecord::Base
# Forked import is handled asynchronously
return if forked? && !force
- if gitlab_shell.add_repository(repository_storage_path, disk_path)
+ if gitlab_shell.add_repository(repository_storage, disk_path)
repository.after_create
true
else
@@ -1564,6 +1569,34 @@ class Project < ActiveRecord::Base
persisted? && path_changed?
end
+ def merge_method
+ if self.merge_requests_ff_only_enabled
+ :ff
+ elsif self.merge_requests_rebase_enabled
+ :rebase_merge
+ else
+ :merge
+ end
+ end
+
+ def merge_method=(method)
+ case method.to_s
+ when "ff"
+ self.merge_requests_ff_only_enabled = true
+ self.merge_requests_rebase_enabled = true
+ when "rebase_merge"
+ self.merge_requests_ff_only_enabled = false
+ self.merge_requests_rebase_enabled = true
+ when "merge"
+ self.merge_requests_ff_only_enabled = false
+ self.merge_requests_rebase_enabled = false
+ end
+ end
+
+ def ff_merge_must_be_possible?
+ self.merge_requests_ff_only_enabled || self.merge_requests_rebase_enabled
+ end
+
def migrate_to_hashed_storage!
return if hashed_storage?
@@ -1611,6 +1644,19 @@ class Project < ActiveRecord::Base
Gitlab::ReferenceCounter.new(gl_repository(is_wiki: true)).value
end
+ def check_repository_absence!
+ return if skip_disk_validation
+
+ if repository_storage_path.blank? || repository_with_same_path_already_exists?
+ errors.add(:base, 'There is already a repository with that name on disk')
+ throw :abort
+ end
+ end
+
+ def repository_with_same_path_already_exists?
+ gitlab_shell.exists?(repository_storage_path, "#{disk_path}.git")
+ end
+
# set last_activity_at to the same as created_at
def set_last_activity_at
update_column(:last_activity_at, self.created_at)
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index 698fdf7a20c..bb7be29ef66 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -54,12 +54,15 @@ class ProjectWiki
[Gitlab.config.gitlab.relative_url_root, '/', @project.full_path, '/wikis'].join('')
end
- # Returns the Gollum::Wiki object.
+ # Returns the Gitlab::Git::Wiki object.
def wiki
@wiki ||= begin
- Gollum::Wiki.new(path_to_repo)
- rescue Rugged::OSError
- create_repo!
+ gl_repository = Gitlab::GlRepository.gl_repository(project, true)
+ raw_repository = Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git', gl_repository)
+
+ create_repo!(raw_repository) unless raw_repository.exists?
+
+ Gitlab::Git::Wiki.new(raw_repository)
end
end
@@ -86,20 +89,14 @@ class ProjectWiki
# Returns an initialized WikiPage instance or nil
def find_page(title, version = nil)
page_title, page_dir = page_title_and_dir(title)
- if page = wiki.page(page_title, version, page_dir)
+
+ if page = wiki.page(title: page_title, version: version, dir: page_dir)
WikiPage.new(self, page, true)
- else
- nil
end
end
- def find_file(name, version = nil, try_on_disk = true)
- version = wiki.ref if version.nil? # Gollum::Wiki#file ?
- if wiki_file = wiki.file(name, version, try_on_disk)
- wiki_file
- else
- nil
- end
+ def find_file(name, version = nil)
+ wiki.file(name, version)
end
def create_page(title, content, format = :markdown, message = nil)
@@ -108,7 +105,7 @@ class ProjectWiki
wiki.write_page(title, format.to_sym, content, commit)
update_project_activity
- rescue Gollum::DuplicatePageError => e
+ rescue Gitlab::Git::Wiki::DuplicatePageError => e
@error_message = "Duplicate page: #{e.message}"
return false
end
@@ -116,13 +113,13 @@ class ProjectWiki
def update_page(page, content:, title: nil, format: :markdown, message: nil)
commit = commit_details(:updated, message, page.title)
- wiki.update_page(page, title || page.name, format.to_sym, content, commit)
+ wiki.update_page(page.path, title || page.name, format.to_sym, content, commit)
update_project_activity
end
def delete_page(page, message = nil)
- wiki.delete_page(page, commit_details(:deleted, message, page.title))
+ wiki.delete_page(page.path, commit_details(:deleted, message, page.title))
update_project_activity
end
@@ -145,20 +142,8 @@ class ProjectWiki
wiki.class.default_ref
end
- def create_repo!
- if init_repo(disk_path)
- wiki = Gollum::Wiki.new(path_to_repo)
- else
- raise CouldNotCreateWikiError
- end
-
- repository.after_create
-
- wiki
- end
-
def ensure_repository
- create_repo! unless repository_exists?
+ raise CouldNotCreateWikiError unless wiki.repository_exists?
end
def hook_attrs
@@ -173,24 +158,24 @@ class ProjectWiki
private
- def init_repo(disk_path)
- gitlab_shell.add_repository(project.repository_storage_path, disk_path)
+ def create_repo!(raw_repository)
+ gitlab_shell.add_repository(project.repository_storage, disk_path)
+
+ raise CouldNotCreateWikiError unless raw_repository.exists?
+
+ repository.after_create
end
def commit_details(action, message = nil, title = nil)
commit_message = message || default_message(action, title)
- { email: @user.email, name: @user.name, message: commit_message }
+ Gitlab::Git::Wiki::CommitDetails.new(@user.name, @user.email, commit_message)
end
def default_message(action, title)
"#{@user.username} #{action} page: #{title}"
end
- def path_to_repo
- @path_to_repo ||= File.join(project.repository_storage_path, "#{disk_path}.git")
- end
-
def update_project_activity
@project.touch(:last_activity_at, :last_repository_updated_at)
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index f0de2697dfc..d725c65081d 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -34,7 +34,10 @@ 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).freeze
+ tag_count avatar exists? empty? root_ref has_visible_content?).freeze
+
+ # Methods that use cache_method but only memoize the value
+ MEMOIZED_CACHED_METHODS = %i(license empty_repo?).freeze
# Certain method caches should be refreshed when certain types of files are
# changed. This Hash maps file types (as returned by Gitlab::FileDetector) to
@@ -91,12 +94,6 @@ class Repository
)
end
- # we need to have this method here because it is not cached in ::Git and
- # the method is called multiple times for every request
- def has_visible_content?
- branch_count > 0
- end
-
def inspect
"#<#{self.class.name}:#{@disk_path}>"
end
@@ -275,7 +272,7 @@ class Repository
end
def expire_branches_cache
- expire_method_caches(%i(branch_names branch_count))
+ expire_method_caches(%i(branch_names branch_count has_visible_content?))
@local_branches = nil
@branch_exists_memo = nil
end
@@ -346,7 +343,7 @@ class Repository
def expire_emptiness_caches
return unless empty?
- expire_method_caches(%i(empty?))
+ expire_method_caches(%i(empty? has_visible_content?))
end
def lookup_cache
@@ -523,9 +520,10 @@ class Repository
delegate :tag_names, to: :raw_repository
cache_method :tag_names, fallback: []
- delegate :branch_count, :tag_count, to: :raw_repository
+ delegate :branch_count, :tag_count, :has_visible_content?, to: :raw_repository
cache_method :branch_count, fallback: 0
cache_method :tag_count, fallback: 0
+ cache_method :has_visible_content?, fallback: false
def avatar
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/38327
@@ -852,6 +850,25 @@ class Repository
end
end
+ def ff_merge(user, source, target_branch, merge_request: nil)
+ our_commit = rugged.branches[target_branch].target
+ their_commit =
+ if source.is_a?(Gitlab::Git::Commit)
+ source.raw_commit
+ else
+ rugged.lookup(source)
+ end
+
+ raise 'Invalid merge target' if our_commit.nil?
+ raise 'Invalid merge source' if their_commit.nil?
+
+ with_branch(user, target_branch) do |start_commit|
+ merge_request&.update(in_progress_merge_commit_sha: their_commit.oid)
+
+ their_commit.oid
+ end
+ end
+
def revert(
user, commit, branch_name, message,
start_branch_name: nil, start_project: project)
@@ -972,7 +989,7 @@ class Repository
end
def create_ref(ref, ref_path)
- fetch_ref(path_to_repo, ref, ref_path)
+ raw_repository.write_ref(ref_path, ref)
end
def ls_files(ref)
diff --git a/app/models/user.rb b/app/models/user.rb
index 4d523aa983f..4e71a3e11c2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -692,7 +692,11 @@ class User < ActiveRecord::Base
end
def ldap_user?
- identities.exists?(["provider LIKE ? AND extern_uid IS NOT NULL", "ldap%"])
+ if identities.loaded?
+ identities.find { |identity| identity.provider.start_with?('ldap') && !identity.extern_uid.nil? }
+ else
+ identities.exists?(["provider LIKE ? AND extern_uid IS NOT NULL", "ldap%"])
+ end
end
def ldap_identity
@@ -1063,6 +1067,12 @@ class User < ActiveRecord::Base
user_synced_attributes_metadata&.read_only?(attribute)
end
+ # override, from Devise
+ def lock_access!
+ Gitlab::AppLogger.info("Account Locked: username=#{username}")
+ super
+ end
+
protected
# override, from Devise::Validatable
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index f2315bb3dbb..5f710961f95 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -50,7 +50,7 @@ class WikiPage
# The Gitlab ProjectWiki instance.
attr_reader :wiki
- # The raw Gollum::Page instance.
+ # The raw Gitlab::Git::WikiPage instance.
attr_reader :page
# The attributes Hash used for storing and validating
@@ -75,7 +75,7 @@ class WikiPage
if @attributes[:slug].present?
@attributes[:slug]
else
- wiki.wiki.preview_page(title, '', format).url_path
+ wiki.wiki.preview_slug(title, format)
end
end
@@ -131,7 +131,7 @@ class WikiPage
def versions
return [] unless persisted?
- @page.versions
+ wiki.wiki.page_versions(@page.path)
end
def commit
@@ -264,8 +264,8 @@ class WikiPage
end
page_title, page_dir = wiki.page_title_and_dir(page_details)
- gollum_wiki = wiki.wiki
- @page = gollum_wiki.paged(page_title, page_dir)
+ gitlab_git_wiki = wiki.wiki
+ @page = gitlab_git_wiki.page(title: page_title, dir: page_dir)
set_attributes
@persisted = errors.blank?
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index 8f7c01bb71f..64e550d19d0 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -11,6 +11,8 @@ class GlobalPolicy < BasePolicy
with_options scope: :user, score: 0
condition(:access_locked) { @user.access_locked? }
+ condition(:can_create_fork, scope: :user) { @user.manageable_namespaces.any? { |namespace| @user.can?(:create_projects, namespace) } }
+
rule { anonymous }.policy do
prevent :log_in
prevent :access_api
@@ -40,6 +42,10 @@ class GlobalPolicy < BasePolicy
enable :create_group
end
+ rule { can_create_fork }.policy do
+ enable :create_fork
+ end
+
rule { access_locked }.policy do
prevent :log_in
end
diff --git a/app/policies/namespace_policy.rb b/app/policies/namespace_policy.rb
index 85b67f0a237..92213f0155e 100644
--- a/app/policies/namespace_policy.rb
+++ b/app/policies/namespace_policy.rb
@@ -1,10 +1,14 @@
class NamespacePolicy < BasePolicy
rule { anonymous }.prevent_all
+ condition(:personal_project, scope: :subject) { @subject.kind == 'user' }
+ condition(:can_create_personal_project, scope: :user) { @user.can_create_project? }
condition(:owner) { @subject.owner == @user }
rule { owner | admin }.policy do
enable :create_projects
enable :admin_namespace
end
+
+ rule { personal_project & ~can_create_personal_project }.prevent :create_projects
end
diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb
index 2df84e58575..a25882cbb62 100644
--- a/app/presenters/merge_request_presenter.rb
+++ b/app/presenters/merge_request_presenter.rb
@@ -31,7 +31,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
def remove_wip_path
- if can?(current_user, :update_merge_request, merge_request.project)
+ if work_in_progress? && can?(current_user, :update_merge_request, merge_request.project)
remove_wip_project_merge_request_path(project, merge_request)
end
end
diff --git a/app/serializers/commit_entity.rb b/app/serializers/commit_entity.rb
index e4e9d8ef90a..c8dd98cc04d 100644
--- a/app/serializers/commit_entity.rb
+++ b/app/serializers/commit_entity.rb
@@ -1,4 +1,4 @@
-class CommitEntity < API::Entities::RepoCommit
+class CommitEntity < API::Entities::Commit
include RequestAwareEntity
expose :author, using: UserEntity
diff --git a/app/serializers/container_repositories_serializer.rb b/app/serializers/container_repositories_serializer.rb
new file mode 100644
index 00000000000..56dc70b5687
--- /dev/null
+++ b/app/serializers/container_repositories_serializer.rb
@@ -0,0 +1,3 @@
+class ContainerRepositoriesSerializer < BaseSerializer
+ entity ContainerRepositoryEntity
+end
diff --git a/app/serializers/container_repository_entity.rb b/app/serializers/container_repository_entity.rb
new file mode 100644
index 00000000000..1103cf30a07
--- /dev/null
+++ b/app/serializers/container_repository_entity.rb
@@ -0,0 +1,25 @@
+class ContainerRepositoryEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id, :path, :location
+
+ expose :tags_path do |repository|
+ project_registry_repository_tags_path(project, repository, format: :json)
+ end
+
+ expose :destroy_path, if: -> (*) { can_destroy? } do |repository|
+ project_container_registry_path(project, repository, format: :json)
+ end
+
+ private
+
+ alias_method :repository, :object
+
+ def project
+ request.project
+ end
+
+ def can_destroy?
+ can?(request.current_user, :update_container_image, project)
+ end
+end
diff --git a/app/serializers/container_tag_entity.rb b/app/serializers/container_tag_entity.rb
new file mode 100644
index 00000000000..ec1fc349586
--- /dev/null
+++ b/app/serializers/container_tag_entity.rb
@@ -0,0 +1,23 @@
+class ContainerTagEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :name, :location, :revision, :total_size, :created_at
+
+ expose :destroy_path, if: -> (*) { can_destroy? } do |tag|
+ project_registry_repository_tag_path(project, tag.repository, tag.name, format: :json)
+ end
+
+ private
+
+ alias_method :tag, :object
+
+ def project
+ request.project
+ end
+
+ def can_destroy?
+ # TODO: We check permission against @project, not tag,
+ # as tag is no AR object that is attached to project
+ can?(request.current_user, :update_container_image, project)
+ end
+end
diff --git a/app/serializers/container_tags_serializer.rb b/app/serializers/container_tags_serializer.rb
new file mode 100644
index 00000000000..6ff3adff135
--- /dev/null
+++ b/app/serializers/container_tags_serializer.rb
@@ -0,0 +1,17 @@
+class ContainerTagsSerializer < BaseSerializer
+ entity ContainerTagEntity
+
+ def with_pagination(request, response)
+ tap { @paginator = Gitlab::Serializer::Pagination.new(request, response) }
+ end
+
+ def paginated?
+ @paginator.present?
+ end
+
+ def represent(resource, opts = {})
+ resource = @paginator.paginate(resource) if paginated?
+
+ super(resource, opts)
+ end
+end
diff --git a/app/serializers/merge_request_entity.rb b/app/serializers/merge_request_entity.rb
index 07650ce6f20..36537c5bd02 100644
--- a/app/serializers/merge_request_entity.rb
+++ b/app/serializers/merge_request_entity.rb
@@ -13,12 +13,16 @@ class MergeRequestEntity < IssuableEntity
expose :target_branch
expose :target_project_id
+ expose :should_be_rebased?, as: :should_be_rebased
+ expose :ff_only_enabled do |merge_request|
+ merge_request.project.merge_requests_ff_only_enabled
+ end
+
# Events
expose :merge_event, using: EventEntity
expose :closed_event, using: EventEntity
# User entities
- expose :author, using: UserEntity
expose :merge_user, using: UserEntity
# Diff sha's
@@ -26,7 +30,6 @@ class MergeRequestEntity < IssuableEntity
merge_request.diff_head_sha if merge_request.diff_head_commit
end
- expose :merge_commit_sha
expose :merge_commit_message
expose :head_pipeline, with: PipelineDetailsEntity, as: :pipeline
diff --git a/app/services/merge_requests/ff_merge_service.rb b/app/services/merge_requests/ff_merge_service.rb
new file mode 100644
index 00000000000..ba6853b835a
--- /dev/null
+++ b/app/services/merge_requests/ff_merge_service.rb
@@ -0,0 +1,24 @@
+module MergeRequests
+ # MergeService class
+ #
+ # Do git fast-forward merge and in case of success
+ # mark merge request as merged and execute all hooks and notifications
+ # Executed when you do fast-forward merge via GitLab UI
+ #
+ class FfMergeService < MergeRequests::MergeService
+ private
+
+ def commit
+ repository.ff_merge(current_user,
+ source,
+ merge_request.target_branch,
+ merge_request: merge_request)
+ rescue Gitlab::Git::HooksService::PreReceiveError => e
+ raise MergeError, e.message
+ rescue StandardError => e
+ raise MergeError, "Something went wrong during merge: #{e.message}"
+ ensure
+ merge_request.update(in_progress_merge_commit_sha: nil)
+ end
+ end
+end
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index bf26859dd6d..a110abf8256 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -11,6 +11,11 @@ module MergeRequests
attr_reader :merge_request, :source
def execute(merge_request)
+ if project.merge_requests_ff_only_enabled && !self.is_a?(FfMergeService)
+ FfMergeService.new(project, current_user, params).execute(merge_request)
+ return
+ end
+
@merge_request = merge_request
unless @merge_request.mergeable?
diff --git a/app/services/tags/create_service.rb b/app/services/tags/create_service.rb
index b3f4a72d6fe..cc76d0df3a1 100644
--- a/app/services/tags/create_service.rb
+++ b/app/services/tags/create_service.rb
@@ -11,7 +11,7 @@ module Tags
begin
new_tag = repository.add_tag(current_user, tag_name, target, message)
- rescue Rugged::TagError
+ rescue Gitlab::Git::Repository::TagExistsError
return error("Tag #{tag_name} already exists")
rescue Gitlab::Git::HooksService::PreReceiveError => ex
return error(ex.message)
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index e3a9e99250e..0d5350f873b 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -37,9 +37,9 @@
- if content_for?(:library_javascripts)
= yield :library_javascripts
+ = javascript_include_tag asset_path("locale/#{I18n.locale.to_s || I18n.default_locale.to_s}/app.js")
= webpack_bundle_tag "webpack_runtime"
= webpack_bundle_tag "common"
- = webpack_bundle_tag "locale"
= webpack_bundle_tag "main"
= webpack_bundle_tag "raven" if current_application_settings.clientside_sentry_enabled
= webpack_bundle_tag "test" if Rails.env.test?
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index cd7a47da4a1..29387d6627e 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -21,8 +21,8 @@
%a
Loading...
= dropdown_loading
- %i.search-icon
- %i.clear-icon.js-clear-input
+ = sprite_icon('search', size: 16, css_class: 'search-icon')
+ = sprite_icon('close', size: 16, css_class: 'clear-icon js-clear-input')
= hidden_field_tag :group_id, @group.try(:id), class: 'js-search-group-options', data: group_data_attrs
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index d8fc371497d..7e9b76da570 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -22,29 +22,29 @@
= render 'layouts/search' unless current_controller?(:search)
%li.visible-sm-inline-block.visible-xs-inline-block
= link_to search_path, title: 'Search', aria: { label: "Search" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = icon('search')
+ = sprite_icon('search', size: 16)
- if current_user
- %li.user-counter
+ = nav_link(path: 'dashboard#issues', html_options: { class: "user-counter" }) do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues', aria: { label: "Issues" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = custom_icon('issues')
+ = sprite_icon('issues', size: 16)
- issues_count = assigned_issuables_count(:issues)
%span.badge.issues-count{ class: ('hidden' if issues_count.zero?) }
= number_with_delimiter(issues_count)
- %li.user-counter
+ = nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter" }) do
= link_to assigned_mrs_dashboard_path, title: 'Merge requests', class: 'dashboard-shortcuts-merge_requests', aria: { label: "Merge requests" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = custom_icon('mr_bold')
+ = sprite_icon('git-merge', size: 16)
- merge_requests_count = assigned_issuables_count(:merge_requests)
%span.badge.merge-requests-count{ class: ('hidden' if merge_requests_count.zero?) }
= number_with_delimiter(merge_requests_count)
- %li.user-counter
+ = nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
= link_to dashboard_todos_path, title: 'Todos', aria: { label: "Todos" }, class: 'shortcuts-todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = custom_icon('todo_done')
+ = sprite_icon('todo-done', size: 16)
%span.badge.todos-count{ class: ('hidden' if todos_pending_count.zero?) }
= todos_count_format(todos_pending_count)
%li.header-user.dropdown
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do
= image_tag avatar_icon(current_user, 23), width: 23, height: 23, class: "header-user-avatar"
- = custom_icon('caret_down')
+ = sprite_icon('angle-down', css_class: 'caret-down')
.dropdown-menu-nav.dropdown-menu-align-right
%ul
%li.current-user
@@ -73,7 +73,7 @@
%button.navbar-toggle.hidden-sm.hidden-md.hidden-lg{ type: 'button' }
%span.sr-only Toggle navigation
- = icon('ellipsis-v', class: 'js-navbar-toggle-right')
- = icon('times', class: 'js-navbar-toggle-left')
+ = sprite_icon('more', size: 16, css_class: 'more-icon js-navbar-toggle-right')
+ = sprite_icon('close', size: 16, css_class: 'close-icon js-navbar-toggle-left')
= render 'shared/outdated_browser'
diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml
index 63d1c077ecd..088f2785092 100644
--- a/app/views/layouts/header/_new_dropdown.haml
+++ b/app/views/layouts/header/_new_dropdown.haml
@@ -1,7 +1,7 @@
%li.header-new.dropdown
= link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip", title: "New...", ref: 'tooltip', aria: { label: "New..." }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body' } do
- = custom_icon('plus_square')
- = custom_icon('caret_down')
+ = sprite_icon('plus-square', size: 16)
+ = sprite_icon('angle-down', css_class: 'caret-down')
.dropdown-menu-nav.dropdown-menu-align-right
%ul
- if @group&.persisted?
diff --git a/app/views/layouts/nav/_breadcrumbs.html.haml b/app/views/layouts/nav/_breadcrumbs.html.haml
index 7bd3f5306a2..002922e13f1 100644
--- a/app/views/layouts/nav/_breadcrumbs.html.haml
+++ b/app/views/layouts/nav/_breadcrumbs.html.haml
@@ -16,5 +16,5 @@
= breadcrumb_list_item link_to(extra[:text], extra[:link])
= render "layouts/nav/breadcrumbs/collapsed_dropdown", location: :after
%li
- %h2.breadcrumbs-sub-title= @breadcrumb_title
+ %h2.breadcrumbs-sub-title= link_to @breadcrumb_title, breadcrumb_title_link
= yield :header_content
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index c254ee02dd8..e0d8d9cb402 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -2,7 +2,7 @@
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects" }) do
%a{ href: "#", data: { toggle: "dropdown" } }
Projects
- = custom_icon('caret_down')
+ = sprite_icon('angle-down', css_class: 'caret-down')
.dropdown-menu.projects-dropdown-menu
= render "layouts/nav/projects_dropdown/show"
@@ -25,7 +25,7 @@
%li.header-more.dropdown.hidden-lg
%a{ href: "#", data: { toggle: "dropdown" } }
More
- = custom_icon('caret_down')
+ = sprite_icon('angle-down', css_class: 'caret-down')
.dropdown-menu
%ul
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "visible-xs" }) do
@@ -54,7 +54,7 @@
- if current_user.admin?
= nav_link(controller: 'admin/dashboard') do
= link_to admin_root_path, class: 'admin-icon', title: 'Admin area', aria: { label: "Admin area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = icon('wrench fw')
+ = sprite_icon('admin', size: 18)
- if Gitlab::Sherlock.enabled?
%li
= link_to sherlock_transactions_path, class: 'admin-icon', title: 'Sherlock Transactions',
diff --git a/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml b/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml
index 28022eebb19..610ff9001f7 100644
--- a/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml
+++ b/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml
@@ -4,7 +4,7 @@
%li.dropdown
%button.text-expander.has-tooltip.js-breadcrumbs-collapsed-expander{ type: "button", data: { toggle: "dropdown", container: "body" }, "aria-label": button_tooltip, title: button_tooltip }
= icon("ellipsis-h")
- = icon("angle-right", class: "breadcrumbs-list-angle")
+ = sprite_icon("angle-right", css_class: "breadcrumbs-list-angle")
.dropdown-menu
%ul
- @breadcrumb_dropdown_links[dropdown_location].each_with_index do |link, index|
diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml
index 9eef006b6a8..0ec07605631 100644
--- a/app/views/layouts/nav/sidebar/_admin.html.haml
+++ b/app/views/layouts/nav/sidebar/_admin.html.haml
@@ -3,7 +3,7 @@
.context-header
= link_to admin_root_path, title: 'Admin Overview' do
.avatar-container.s40.settings-avatar
- = icon('wrench')
+ = sprite_icon('admin', size: 24)
.sidebar-context-title Admin Area
%ul.sidebar-top-level-items
= nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts conversational_development_index), html_options: {class: 'home'}) do
@@ -12,7 +12,6 @@
= sprite_icon('overview')
%span.nav-item-name
Overview
-
%ul.sidebar-sub-level-items
= nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts conversational_development_index), html_options: { class: "fly-out-top-item" } ) do
= link_to admin_root_path do
diff --git a/app/views/layouts/nav/sidebar/_profile.html.haml b/app/views/layouts/nav/sidebar/_profile.html.haml
index a015c94c60e..458b5010d36 100644
--- a/app/views/layouts/nav/sidebar/_profile.html.haml
+++ b/app/views/layouts/nav/sidebar/_profile.html.haml
@@ -3,7 +3,7 @@
.context-header
= link_to profile_path, title: 'Profile Settings' do
.avatar-container.s40.settings-avatar
- = icon('user')
+ = sprite_icon('user', size: 24)
.sidebar-context-title User Settings
%ul.sidebar-top-level-items
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
diff --git a/app/views/projects/_merge_request_fast_forward_settings.html.haml b/app/views/projects/_merge_request_fast_forward_settings.html.haml
new file mode 100644
index 00000000000..9d357293a2f
--- /dev/null
+++ b/app/views/projects/_merge_request_fast_forward_settings.html.haml
@@ -0,0 +1,13 @@
+- form = local_assigns.fetch(:form)
+- project = local_assigns.fetch(:project)
+
+.radio
+ = label_tag :project_merge_method_ff do
+ = form.radio_button :merge_method, :ff, class: "js-merge-method-radio"
+ %strong Fast-forward merge
+ %br
+ %span.descr
+ No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.
+ %br
+ %span.descr
+ When fast-forward merge is not possible, the user must first rebase locally.
diff --git a/app/views/projects/_merge_request_rebase_settings.html.haml b/app/views/projects/_merge_request_rebase_settings.html.haml
new file mode 100644
index 00000000000..c52e09573a6
--- /dev/null
+++ b/app/views/projects/_merge_request_rebase_settings.html.haml
@@ -0,0 +1,13 @@
+- form = local_assigns.fetch(:form)
+
+.radio
+ = label_tag :project_merge_method_rebase_merge do
+ = form.radio_button :merge_method, :rebase_merge, class: "js-merge-method-radio"
+ %strong Merge commit with semi-linear history
+ %br
+ %span.descr
+ A merge commit is created for every merge, but merging is only allowed if fast-forward merge is possible.
+ This way you could make sure that if this merge request would build, after merging to target branch it would also build.
+ %br
+ %span.descr
+ When fast-forward merge is not possible, the user must first rebase locally.
diff --git a/app/views/projects/_merge_request_settings.html.haml b/app/views/projects/_merge_request_settings.html.haml
index cc5afa943cf..fd0c419cdac 100644
--- a/app/views/projects/_merge_request_settings.html.haml
+++ b/app/views/projects/_merge_request_settings.html.haml
@@ -1,3 +1,18 @@
- form = local_assigns.fetch(:form)
+.form-group
+ = label_tag :merge_method_merge, class: 'label-light' do
+ Merge method
+ .radio
+ = label_tag :project_merge_method_merge do
+ = form.radio_button :merge_method, :merge, class: "js-merge-method-radio"
+ %strong Merge commit
+ %br
+ %span.descr
+ A merge commit is created for every merge, and merging is allowed as long as there are no conflicts.
+
+ = render 'merge_request_rebase_settings', form: form
+
+ = render 'merge_request_fast_forward_settings', project: @project, form: form
+
= render 'projects/merge_request_merge_settings', form: form
diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml
index d1d448f0d4c..ea7a71792a3 100644
--- a/app/views/projects/blob/diff.html.haml
+++ b/app/views/projects/blob/diff.html.haml
@@ -5,25 +5,24 @@
= diff_match_line @form.since, @form.since, text: @match_line, view: diff_view
- @lines.each_with_index do |line, index|
- - line_new = index + @form.since
- - line_old = line_new - @form.offset
- - line_content = capture do
- %td.line_content.noteable_line{ class: line_class }==#{' ' * @form.indent}#{line}
- %tr.line_holder.diff-expanded{ id: line_old, class: line_class }
+ - line_number_new = index + @form.since
+ - line_number_old = line_number_new - @form.offset
+ - line[0, 0] = ' ' * @form.indent
+ %tr.line_holder.diff-expanded{ id: line_number_old, class: line_class }
- case diff_view
- when :inline
- %td.old_line.diff-line-num{ data: { linenumber: line_old } }
- %a{ href: "#", data: { linenumber: line_old }, disabled: true }
- %td.new_line.diff-line-num{ data: { linenumber: line_new } }
- %a{ href: "#", data: { linenumber: line_new }, disabled: true }
- = line_content
+ %td.old_line.diff-line-num{ data: { linenumber: line_number_old } }
+ %a{ href: "#", data: { linenumber: line_number_old }, disabled: true }
+ %td.new_line.diff-line-num{ data: { linenumber: line_number_new } }
+ %a{ href: "#", data: { linenumber: line_number_new }, disabled: true }
+ %td.line_content.noteable_line{ class: line_class }= line
- when :parallel
- %td.old_line.diff-line-num{ data: { linenumber: line_old } }
- %a{ href: "##{line_old}", data: { linenumber: line_old }, disabled: true }
- = line_content
- %td.new_line.diff-line-num{ data: { linenumber: line_new } }
- %a{ href: "##{line_new}", data: { linenumber: line_new }, disabled: true }
- = line_content
+ %td.old_line.diff-line-num{ data: { linenumber: line_number_old } }
+ %a{ href: "##{line_number_old}", data: { linenumber: line_number_old }, disabled: true }
+ %td.line_content.noteable_line.left-side{ class: line_class }= line
+ %td.new_line.diff-line-num{ data: { linenumber: line_number_new } }
+ %a{ href: "##{line_number_new}", data: { linenumber: line_number_new }, disabled: true }
+ %td.line_content.noteable_line.right-side{ class: line_class }= line
- if @form.unfold? && @form.bottom? && @form.to < @blob.lines.size
%tr.line_holder{ id: @form.to, class: line_class }
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index f45cc7f0f45..f880556a9f7 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -4,12 +4,11 @@
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'btn has-tooltip' do
= custom_icon('icon_fork')
%span= s_('GoToYourFork|Fork')
- - elsif !current_user.can_create_project?
- = link_to new_project_fork_path(@project), title: _('You have reached your project limit'), class: 'btn has-tooltip disabled' do
- = custom_icon('icon_fork')
- %span= s_('CreateNewFork|Fork')
- else
- = link_to new_project_fork_path(@project), class: 'btn' do
+ - can_create_fork = current_user.can?(:create_fork)
+ = link_to new_project_fork_path(@project),
+ class: "btn btn-default #{'has-tooltip disabled' unless can_create_fork}",
+ title: (_('You have reached your project limit') unless can_create_fork) do
= custom_icon('icon_fork')
%span= s_('CreateNewFork|Fork')
.count-with-arrow
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index 56d63250714..1f0ca211074 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -14,20 +14,20 @@
= diff_match_line left.old_pos, nil, text: left.text, view: :parallel
- when 'old-nonewline', 'new-nonewline'
%td.old_line.diff-line-num
- %td.line_content.match= left.text
+ %td.line_content.match.left-side= left.text
- else
- left_line_code = diff_file.line_code(left)
- left_position = diff_file.position(left)
- %td.old_line.diff-line-num.js-avatar-container{ id: left_line_code, class: left.type, data: { linenumber: left.old_pos } }
+ %td.old_line.diff-line-num.js-avatar-container{ class: left.type, data: { linenumber: left.old_pos } }
= add_diff_note_button(left_line_code, left_position, 'old')
%a{ href: "##{left_line_code}", data: { linenumber: left.old_pos } }
- discussion_left = discussions_left.try(:first)
- if discussion_left && discussion_left.resolvable?
%diff-note-avatars{ "discussion-id" => discussion_left.id }
- %td.line_content.parallel.noteable_line{ class: left.type }= diff_line_content(left.text)
+ %td.line_content.parallel.noteable_line.left-side{ id: left_line_code, class: left.type }= diff_line_content(left.text)
- else
%td.old_line.diff-line-num.empty-cell
- %td.line_content.parallel
+ %td.line_content.parallel.left-side
- if right
- case right.type
@@ -35,20 +35,20 @@
= diff_match_line nil, right.new_pos, text: left.text, view: :parallel
- when 'old-nonewline', 'new-nonewline'
%td.new_line.diff-line-num
- %td.line_content.match= right.text
+ %td.line_content.match.right-side= right.text
- else
- right_line_code = diff_file.line_code(right)
- right_position = diff_file.position(right)
- %td.new_line.diff-line-num.js-avatar-container{ id: right_line_code, class: right.type, data: { linenumber: right.new_pos } }
+ %td.new_line.diff-line-num.js-avatar-container{ class: right.type, data: { linenumber: right.new_pos } }
= add_diff_note_button(right_line_code, right_position, 'new')
%a{ href: "##{right_line_code}", data: { linenumber: right.new_pos } }
- discussion_right = discussions_right.try(:first)
- if discussion_right && discussion_right.resolvable?
%diff-note-avatars{ "discussion-id" => discussion_right.id }
- %td.line_content.parallel.noteable_line{ class: right.type }= diff_line_content(right.text)
+ %td.line_content.parallel.noteable_line.right-side{ id: right_line_code, class: right.type }= diff_line_content(right.text)
- else
%td.old_line.diff-line-num.empty-cell
- %td.line_content.parallel
+ %td.line_content.parallel.right-side
- if discussions_left || discussions_right
= render "discussions/parallel_diff_discussion", discussions_left: discussions_left, discussions_right: discussions_right
diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml
index 0f36e1a7353..e9613534dde 100644
--- a/app/views/projects/forks/new.html.haml
+++ b/app/views/projects/forks/new.html.haml
@@ -9,46 +9,36 @@
%br
Forking a repository allows you to make changes without affecting the original project.
.col-lg-9
- .fork-namespaces
- - if @namespaces.present?
- %label.label-light
- %span
- Click to fork the project to a user or group
- - @namespaces.in_groups_of(6, false) do |group|
- .row
- - group.each do |namespace|
- - avatar = namespace_icon(namespace, 100)
- - if fork = namespace.find_fork_of(@project)
- .fork-thumbnail.forked
- = link_to project_path(fork) do
- - if /no_((\w*)_)*avatar/.match(avatar)
- .no-avatar
- = icon 'question'
- - else
- = image_tag avatar
- .caption
- = namespace.human_name
- - else
- .fork-thumbnail
- = link_to project_forks_path(@project, namespace_key: namespace.id), method: "POST" do
- - if /no_((\w*)_)*avatar/.match(avatar)
- .no-avatar
- = icon 'question'
- - else
- = image_tag avatar
- .caption
- = namespace.human_name
- - else
- %label.label-light
- %span
- No available namespaces to fork the project.
- %br
- %small
- You must have permission to create a project in a namespace before forking.
+ - if @namespaces.present?
+ .fork-thumbnail-container.js-fork-content
+ %h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default
+ Click to fork the project
+ - @namespaces.each do |namespace|
+ - avatar = namespace_icon(namespace, 100)
+ - can_create_project = current_user.can?(:create_projects, namespace)
+ - forked_project = namespace.find_fork_of(@project)
+ - fork_path = forked_project ? project_path(forked_project) : project_forks_path(@project, namespace_key: namespace.id)
+ .bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default{ class: [("disabled" unless can_create_project), ("forked" if forked_project)] }
+ = link_to fork_path,
+ method: "POST",
+ class: [("js-fork-thumbnail" unless forked_project), ("disabled has-tooltip" unless can_create_project)],
+ title: (_('You have reached your project limit') unless can_create_project) do
+ - if /no_((\w*)_)*avatar/.match(avatar)
+ = project_identicon(namespace, class: "avatar s100 identicon")
+ - else
+ .avatar-container.s100
+ = image_tag(avatar, class: "avatar s100")
+ %h5.prepend-top-default
+ = namespace.human_name
+ - else
+ %strong
+ No available namespaces to fork the project.
+ %p.prepend-top-default
+ You must have permission to create a project in a namespace before forking.
- .save-project-loader.hide
- .center
- %h2
- %i.fa.fa-spinner.fa-spin
- Forking repository
- %p Please wait a moment, this page will automatically refresh when ready.
+ .save-project-loader.hide.js-fork-content
+ %h2.text-center
+ = icon('spinner spin')
+ Forking repository
+ %p.text-center
+ Please wait a moment, this page will automatically refresh when ready.
diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml
index 6a567487514..5f97d31f610 100644
--- a/app/views/projects/issues/_merge_requests.html.haml
+++ b/app/views/projects/issues/_merge_requests.html.haml
@@ -2,13 +2,13 @@
%h2.merge-requests-title
= pluralize(@merge_requests.count, 'Related Merge Request')
%ul.unstyled-list.related-merge-requests
- - has_any_ci = @merge_requests.any?(&:head_pipeline)
+ - has_any_head_pipeline = @merge_requests.any?(&:head_pipeline_id)
- @merge_requests.each do |merge_request|
%li
%span.merge-request-ci-status
- if merge_request.head_pipeline
= render_pipeline_status(merge_request.head_pipeline)
- - elsif has_any_ci
+ - elsif has_any_head_pipeline
= icon('blank fw')
%span.merge-request-id
= merge_request.to_reference
diff --git a/app/views/projects/issues/edit.html.haml b/app/views/projects/issues/edit.html.haml
deleted file mode 100644
index 1b7d878c38c..00000000000
--- a/app/views/projects/issues/edit.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-- page_title "Edit", "#{@issue.title} (#{@issue.to_reference})", "Issues"
-
-%h3.page-title
- Edit Issue ##{@issue.iid}
-%hr
-
-= render "form"
diff --git a/app/views/projects/merge_requests/_mr_title.html.haml b/app/views/projects/merge_requests/_mr_title.html.haml
index f3c44c94a5c..9ff85c2ee4c 100644
--- a/app/views/projects/merge_requests/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/_mr_title.html.haml
@@ -29,7 +29,7 @@
- unless current_user == @merge_request.author
%li= link_to 'Report abuse', new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request))
- if can_update_merge_request
- %li{ class: merge_request_button_visibility(@merge_request, true) }
+ %li{ class: [merge_request_button_visibility(@merge_request, true), 'js-close-item'] }
= link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, title: 'Close merge request'
%li{ class: merge_request_button_visibility(@merge_request, false) }
= link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request'
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index ab87b5e0005..4961835f12a 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -1,6 +1,6 @@
- access = note_max_access_for_user(note)
- if note.has_special_role?(Note::SpecialRole::FIRST_TIME_CONTRIBUTOR)
- %span.note-role.note-role-special.has-tooltip{ title: _("This is the author's first Merge Request to this project. Handle with care.") }
+ %span.note-role.note-role-special.has-tooltip{ title: _("This is the author's first Merge Request to this project.") }
= issuable_first_contribution_icon
- if access.nonzero?
%span.note-role.note-role-access= Gitlab::Access.human_access(access)
diff --git a/app/views/projects/registry/repositories/_image.html.haml b/app/views/projects/registry/repositories/_image.html.haml
deleted file mode 100644
index a0535edafc3..00000000000
--- a/app/views/projects/registry/repositories/_image.html.haml
+++ /dev/null
@@ -1,32 +0,0 @@
-.container-image.js-toggle-container
- .container-image-head
- = link_to "#", class: "js-toggle-button" do
- = icon('chevron-down', 'aria-hidden': 'true')
- = escape_once(image.path)
-
- = clipboard_button(clipboard_text: "docker pull #{image.location}")
-
- - if can?(current_user, :update_container_image, @project)
- .controls.hidden-xs.pull-right
- = link_to project_container_registry_path(@project, image),
- class: 'btn btn-remove has-tooltip',
- title: 'Remove repository',
- data: { confirm: 'Are you sure?' },
- method: :delete do
- = icon('trash cred', 'aria-hidden': 'true')
-
- .container-image-tags.js-toggle-content.hide
- - if image.has_tags?
- .table-holder
- %table.table.tags
- %thead
- %tr
- %th Tag
- %th Tag ID
- %th Size
- %th Created
- - if can?(current_user, :update_container_image, @project)
- %th
- = render partial: 'tag', collection: image.tags
- - else
- .nothing-here-block No tags in Container Registry for this container image.
diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml
index 5661af01302..36ea5e013e4 100644
--- a/app/views/projects/registry/repositories/index.html.haml
+++ b/app/views/projects/registry/repositories/index.html.haml
@@ -1,60 +1,49 @@
- page_title "Container Registry"
-.row.prepend-top-default.append-bottom-default
- .col-lg-3
- %h4.prepend-top-0
+%section
+ .settings-header
+ %h4
= page_title
%p
- With the Docker Container Registry integrated into GitLab, every project
- can have its own space to store its Docker images.
+ = s_('ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images.')
%p.append-bottom-0
= succeed '.' do
- Learn more about
- = link_to 'Container Registry', help_page_path('user/project/container_registry'), target: '_blank'
+ = s_('ContainerRegistry|Learn more about')
+ = link_to _('Container Registry'), help_page_path('user/project/container_registry'), target: '_blank'
+ .row.registry-placeholder.prepend-bottom-10
+ .col-lg-12
+ #js-vue-registry-images{ data: { endpoint: project_container_registry_index_path(@project, format: :json) } }
- .col-lg-9
- .panel.panel-default
- .panel-heading
- %h4.panel-title
- How to use the Container Registry
- .panel-body
- %p
- First log in to GitLab&rsquo;s Container Registry using your GitLab username
- and password. If you have
- = link_to '2FA enabled', help_page_path('user/profile/account/two_factor_authentication'), target: '_blank'
- you need to use a
- = succeed ':' do
- = link_to 'personal access token', help_page_path('user/profile/account/two_factor_authentication', anchor: 'personal-access-tokens'), target: '_blank'
- %pre
- docker login #{Gitlab.config.registry.host_port}
- %br
- %p
- Once you log in, you&rsquo;re free to create and upload a container image
- using the common
- %code build
- and
- %code push
- commands:
- %pre
- :plain
- docker build -t #{escape_once(@project.container_registry_url)} .
- docker push #{escape_once(@project.container_registry_url)}
+ = page_specific_javascript_bundle_tag('common_vue')
+ = page_specific_javascript_bundle_tag('registry_list')
- %hr
- %h5.prepend-top-default
- Use different image names
- %p.light
- GitLab supports up to 3 levels of image names. The following
- examples of images are valid for your project:
- %pre
- :plain
- #{escape_once(@project.container_registry_url)}:tag
- #{escape_once(@project.container_registry_url)}/optional-image-name:tag
- #{escape_once(@project.container_registry_url)}/optional-name/optional-image-name:tag
-
- - if @images.blank?
- %p.settings-message.text-center.append-bottom-default
- No container images stored for this project. Add one by following the
- instructions above.
- - else
- = render partial: 'image', collection: @images
+ .row.prepend-top-10
+ .col-lg-12
+ .panel.panel-default
+ .panel-heading
+ %h4.panel-title
+ = s_('ContainerRegistry|How to use the Container Registry')
+ .panel-body
+ %p
+ - link_token = link_to(_('personal access token'), help_page_path('user/profile/account/two_factor_authentication', anchor: 'personal-access-tokens'), target: '_blank')
+ - link_2fa = link_to(_('2FA enabled'), help_page_path('user/profile/account/two_factor_authentication'), target: '_blank')
+ = s_('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}:').html_safe % { link_2fa: link_2fa, link_token: link_token }
+ %pre
+ docker login #{Gitlab.config.registry.host_port}
+ %br
+ %p
+ = s_('ContainerRegistry|Once you log in, you&rsquo;re free to create and upload a container image using the common %{build} and %{push} commands').html_safe % { build: "<code>build</code>".html_safe, push: "<code>push</code>".html_safe }
+ %pre
+ :plain
+ docker build -t #{escape_once(@project.container_registry_url)} .
+ docker push #{escape_once(@project.container_registry_url)}
+ %hr
+ %h5.prepend-top-default
+ = s_('ContainerRegistry|Use different image names')
+ %p.light
+ = s_('ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:')
+ %pre
+ :plain
+ #{escape_once(@project.container_registry_url)}:tag
+ #{escape_once(@project.container_registry_url)}/optional-image-name:tag
+ #{escape_once(@project.container_registry_url)}/optional-name/optional-image-name:tag
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index b842fd57cf3..c0b1c62e8ef 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -23,7 +23,7 @@
- disabled_class = 'disabled'
- disabled_title = @service.disabled_title
- = link_to 'Cancel', project_settings_integrations_path(@project), class: 'btn btn-cancel'
+ = link_to 'Cancel', project_settings_integrations_path(@project), class: 'btn btn-cancel'
- if lookup_context.template_exists?('show', "projects/services/#{@service.to_param}", true)
%hr
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index 468ab922542..1927216e191 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -2,12 +2,11 @@
- release = @releases.find { |release| release.tag == tag.name }
%li.flex-row
.row-main-content.str-truncated
- = link_to project_tag_path(@project, tag.name), class: 'item-title ref-name' do
- = icon('tag')
- = tag.name
+ = icon('tag')
+ = link_to tag.name, project_tag_path(@project, tag.name), class: 'item-title ref-name prepend-left-4'
- if protected_tag?(@project, tag)
- %span.label.label-success
+ %span.label.label-success.prepend-left-4
protected
- if tag.message.present?
diff --git a/app/views/projects/tree/_old_tree_content.html.haml b/app/views/projects/tree/_old_tree_content.html.haml
index 820b947804e..6ea78851b8d 100644
--- a/app/views/projects/tree/_old_tree_content.html.haml
+++ b/app/views/projects/tree/_old_tree_content.html.haml
@@ -6,7 +6,7 @@
%th= s_('ProjectFileTree|Name')
%th.hidden-xs
.pull-left= _('Last commit')
- %th.text-right= _('Last Update')
+ %th.text-right= _('Last update')
- if @path.present?
%tr.tree-item
%td.tree-item-file-name
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
index 853e2a6e7ec..6cddc38d11a 100644
--- a/app/views/projects/tree/_tree_header.html.haml
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -1,10 +1,6 @@
.tree-ref-container
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'tree', path: @path
- - if show_new_repo?
- .tree-ref-target-holder.js-tree-ref-target-holder
- = icon('long-arrow-right', title: 'to target branch')
- = render 'shared/target_switcher', destination: 'tree', path: @path
- unless show_new_repo?
= render 'projects/tree/old_tree_header'
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index f819f2addaa..0cc6674842a 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -12,7 +12,7 @@
= webpack_bundle_tag 'repo'
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
- - if show_auto_devops_callout?(@project)
+ - if show_auto_devops_callout?(@project) && !show_new_repo?
= render 'shared/auto_devops_callout'
= render 'projects/last_push'
= render 'projects/files', commit: @last_commit, project: @project, ref: @ref, content_url: project_tree_path(@project, @id)
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index e5a1fccf9ba..4e265bf733a 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -1,4 +1,5 @@
-- commit_message = @page.persisted? ? "Update #{@page.title}" : "Create #{@page.title}"
+- commit_message = @page.persisted? ? s_("WikiPageEdit|Update %{page_title}") : s_("WikiPageCreate|Create %{page_title}")
+- commit_message = commit_message % { page_title: @page.title }
= form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, html: { class: 'form-horizontal wiki-form common-note-form prepend-top-default js-quick-submit' } do |f|
= form_errors(@page)
@@ -12,13 +13,13 @@
.form-group
.col-sm-12= f.label :format, class: 'control-label-full-width'
.col-sm-12
- = f.select :format, options_for_select(ProjectWiki::MARKUPS, {selected: @page.format}), {}, class: "form-control"
+ = f.select :format, options_for_select(ProjectWiki::MARKUPS, {selected: @page.format}), {}, class: 'form-control'
.form-group
.col-sm-12= f.label :content, class: 'control-label-full-width'
.col-sm-12
= render layout: 'projects/md_preview', locals: { url: project_wiki_preview_markdown_path(@project, @page.slug) } do
- = render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: 'Write your content or drag files here...'
+ = render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: s_("WikiPage|Write your content or drag files here...")
= render 'shared/notes/hints'
.clearfix
@@ -26,12 +27,11 @@
.help-block
= succeed '.' do
- To link to a (new) page, simply type
- %code [Link Title](page-slug)
+ = (s_("WikiMarkdownTip|To link to a (new) page, simply type %{link_example}") % { link_example: '<code>[Link Title](page-slug)</code>' }).html_safe
= succeed '.' do
- More examples are in the
- = link_to 'documentation', help_page_path("user/markdown", anchor: "wiki-specific-markdown")
+ - markdown_link = link_to s_("WikiMarkdownDocs|documentation"), help_page_path('user/markdown', anchor: 'wiki-specific-markdown')
+ = (s_("WikiMarkdownDocs|More examples are in the %{docs_link}") % { docs_link: markdown_link }).html_safe
.form-group
.col-sm-12= f.label :commit_message, class: 'control-label-full-width'
@@ -39,10 +39,10 @@
.form-actions
- if @page && @page.persisted?
- = f.submit 'Save changes', class: "btn-save btn"
+ = f.submit _("Save changes"), class: 'btn-save btn'
.pull-right
- = link_to "Cancel", project_wiki_path(@project, @page), class: "btn btn-cancel btn-grouped"
+ = link_to _("Cancel"), project_wiki_path(@project, @page), class: 'btn btn-cancel btn-grouped'
- else
- = f.submit 'Create page', class: "btn-create btn"
+ = f.submit s_("Wiki|Create page"), class: 'btn-create btn'
.pull-right
- = link_to "Cancel", project_wiki_path(@project, :home), class: "btn btn-cancel"
+ = link_to _("Cancel"), project_wiki_path(@project, :home), class: 'btn btn-cancel'
diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 3bbd8042c3a..cadda0a33c2 100644
--- a/app/views/projects/wikis/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -1,9 +1,9 @@
- if (@page && @page.persisted?)
- if can?(current_user, :create_wiki, @project)
= link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
- New page
+ = s_("Wiki|New page")
= link_to project_wiki_history_path(@project, @page), class: "btn" do
- Page history
+ = s_("Wiki|Page history")
- if can?(current_user, :create_wiki, @project) && @page.latest?
= link_to project_wiki_edit_path(@project, @page), class: "btn js-wiki-edit" do
- Edit
+ = _("Edit")
diff --git a/app/views/projects/wikis/_new.html.haml b/app/views/projects/wikis/_new.html.haml
index 13dd8461433..06a3cac12d5 100644
--- a/app/views/projects/wikis/_new.html.haml
+++ b/app/views/projects/wikis/_new.html.haml
@@ -3,16 +3,15 @@
.modal-content
.modal-header
%a.close{ href: "#", "data-dismiss" => "modal" } ×
- %h3.page-title New Wiki Page
+ %h3.page-title= s_("WikiNewPageTitle|New Wiki Page")
.modal-body
%form.new-wiki-page
.form-group
= label_tag :new_wiki_path do
- %span Page slug
- = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => project_wikis_path(@project), autofocus: true
+ %span= s_("WikiPage|Page slug")
+ = text_field_tag :new_wiki_path, nil, placeholder: s_("WikiNewPagePlaceholder|how-to-setup"), class: 'form-control', required: true, :'data-wikis-path' => project_wikis_path(@project), autofocus: true
%span.new-wiki-page-slug-tip
= icon('lightbulb-o')
- Tip: You can specify the full path for the new file.
- We will automatically create any missing directories.
+ = s_("WikiNewPageTip|Tip: You can specify the full path for the new file. We will automatically create any missing directories.")
.form-actions
- = button_tag 'Create page', class: 'build-new-wiki btn btn-create'
+ = button_tag s_("Wiki|Create page"), class: "build-new-wiki btn btn-create"
diff --git a/app/views/projects/wikis/_pages_wiki_page.html.haml b/app/views/projects/wikis/_pages_wiki_page.html.haml
index 7c2f562d422..0a1ccbc5f1c 100644
--- a/app/views/projects/wikis/_pages_wiki_page.html.haml
+++ b/app/views/projects/wikis/_pages_wiki_page.html.haml
@@ -2,4 +2,4 @@
= link_to wiki_page.title, project_wiki_path(@project, wiki_page)
%small (#{wiki_page.format})
.pull-right
- %small Last edited #{time_ago_with_tooltip(wiki_page.commit.authored_date)}
+ %small= (s_("Last edited %{date}") % { date: time_ago_with_tooltip(wiki_page.commit.authored_date) }).html_safe
diff --git a/app/views/projects/wikis/_sidebar.html.haml b/app/views/projects/wikis/_sidebar.html.haml
index f7283ae4739..5b781294d68 100644
--- a/app/views/projects/wikis/_sidebar.html.haml
+++ b/app/views/projects/wikis/_sidebar.html.haml
@@ -8,7 +8,7 @@
= link_to git_access_url, class: active_nav_link?(path: 'wikis#git_access') ? 'active' : '' do
= succeed '&nbsp;' do
= icon('cloud-download')
- Clone repository
+ = _("Clone repository")
.blocks-container
.block.block-first
@@ -17,6 +17,6 @@
.block
= link_to project_wikis_pages_path(@project), class: 'btn btn-block' do
- More Pages
+ = s_("Wiki|More Pages")
= render 'projects/wikis/new'
diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml
index 8fd60216536..0d77e5bd16d 100644
--- a/app/views/projects/wikis/edit.html.haml
+++ b/app/views/projects/wikis/edit.html.haml
@@ -1,11 +1,10 @@
- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout
-- page_title "Edit", @page.title.capitalize, "Wiki"
+- page_title _("Edit"), @page.title.capitalize, _("Wiki")
- if @conflict
.alert.alert-danger
- Someone edited the page the same time you did. Please check out
- = link_to "the page", project_wiki_path(@project, @page), target: "_blank"
- and make sure your changes will not unintentionally remove theirs.
+ - page_link = link_to s_("WikiPageConflictMessage|the page"), project_wiki_path(@project, @page), target: "_blank"
+ = (s_("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.") % { page_link: page_link }).html_safe
.wiki-page-header.has-sidebar-toggle
%button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
@@ -20,20 +19,20 @@
%span.light
&middot;
- if @page.persisted?
- Edit Page
+ = s_("Wiki|Edit Page")
- else
- Create Page
+ = s_("Wiki|Create Page")
.nav-controls
- if can?(current_user, :create_wiki, @project)
= link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
- New page
+ = s_("Wiki|New page")
- if @page.persisted?
= link_to project_wiki_history_path(@project, @page), class: "btn" do
- Page history
+ = s_("Wiki|Page history")
- if can?(current_user, :admin_wiki, @project)
- = link_to project_wiki_path(@project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-danger" do
- Delete
+ = link_to project_wiki_path(@project, @page), data: { confirm: s_("WikiPageConfirmDelete|Are you sure you want to delete this page?")}, method: :delete, class: "btn btn-danger" do
+ = _("Delete")
= render 'form'
diff --git a/app/views/projects/wikis/empty.html.haml b/app/views/projects/wikis/empty.html.haml
index 7dfa405d063..911e1339541 100644
--- a/app/views/projects/wikis/empty.html.haml
+++ b/app/views/projects/wikis/empty.html.haml
@@ -1,6 +1,6 @@
-- page_title "Wiki"
+- page_title _("Wiki")
-%h3.page-title Empty page
+%h3.page-title= _("Wiki|Empty page")
%hr
.error_message
- You are not allowed to create wiki pages
+ = s_("WikiEmptyPageError|You are not allowed to create wiki pages")
diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml
index e740fb93ea4..10dbbc0e42c 100644
--- a/app/views/projects/wikis/git_access.html.haml
+++ b/app/views/projects/wikis/git_access.html.haml
@@ -1,36 +1,34 @@
- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout
-- page_title "Git Access", "Wiki"
+- page_title s_("WikiClone|Git Access"), _("Wiki")
.wiki-page-header.has-sidebar-toggle
%button.btn.btn-default.visible-xs.visible-sm.pull-right.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
= icon('angle-double-left')
.git-access-header
- Clone repository
+ = _("Clone repository")
%strong= @project_wiki.full_path
= render "shared/clone_panel", project: @project_wiki
.wiki-git-access
- %h3 Install Gollum
+ %h3= s_("WikiClone|Install Gollum")
%pre.dark
:preserve
gem install gollum
%p
- It is recommended to install
- %code github-markdown
- so that GFM features render locally:
+ = (s_("WikiClone|It is recommended to install %{markdown} so that GFM features render locally:") % { markdown: "<code>github-markdown</code>" }).html_safe
%pre.dark
:preserve
gem install github-markdown
- %h3 Clone your wiki
+ %h3= s_("WikiClone|Clone your wiki")
%pre.dark
:preserve
git clone #{ content_tag(:span, h(default_url_to_repo(@project_wiki)), class: 'clone')}
cd #{h @project_wiki.path}
- %h3 Start Gollum and edit locally
+ %h3= s_("WikiClone|Start Gollum and edit locally")
%pre.dark
:preserve
gollum
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index 306feeff259..9ee09262324 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -1,4 +1,4 @@
-- page_title "History", @page.title.capitalize, "Wiki"
+- page_title _("History"), @page.title.capitalize, _("Wiki")
.wiki-page-header.has-sidebar-toggle
%button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
@@ -9,17 +9,17 @@
= link_to @page.title.capitalize, project_wiki_path(@project, @page)
%span.light
&middot;
- History
+ = _("History")
.table-holder
%table.table
%thead
%tr
- %th Page version
- %th Author
- %th Commit Message
- %th Last updated
- %th Format
+ %th= s_("Wiki|Page version")
+ %th= _("Author")
+ %th= _("Commit Message")
+ %th= _("Last updated")
+ %th= _("Format")
%tbody
- @page.versions.each_with_index do |version, index|
- commit = version
@@ -29,13 +29,13 @@
commit.id, index == 0) do
= truncate_sha(commit.id)
%td
- = commit.author.name
+ = commit.author_name
%td
= commit.message
%td
#{time_ago_with_tooltip(version.authored_date)}
%td
%strong
- = @page.page.wiki.page(@page.page.name, commit.id).try(:format)
+ = version.format
= render 'sidebar'
diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml
index d533c611a38..aeef64fd7eb 100644
--- a/app/views/projects/wikis/pages.html.haml
+++ b/app/views/projects/wikis/pages.html.haml
@@ -1,19 +1,19 @@
- @no_container = true
- add_to_breadcrumbs "Wiki", get_project_wiki_path(@project)
-- breadcrumb_title "Pages"
-- page_title "Pages", "Wiki"
+- breadcrumb_title s_("Wiki|Pages")
+- page_title s_("Wiki|Pages"), _("Wiki")
%div{ class: container_class }
.wiki-page-header
.nav-text
%h2.wiki-page-title
- Wiki Pages
+ = s_("Wiki|Wiki Pages")
.nav-controls
= link_to project_wikis_git_access_path(@project), class: 'btn' do
= icon('cloud-download')
- Clone repository
+ = _("Clone repository")
%ul.wiki-pages-list.content-list
= render @wiki_entries, context: 'pages'
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index b066a812ec8..de15fc99eda 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -1,8 +1,8 @@
- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout
- breadcrumb_title @page.title.capitalize
- wiki_breadcrumb_dropdown_links(@page.slug)
-- page_title @page.title.capitalize, "Wiki"
-- add_to_breadcrumbs "Wiki", get_project_wiki_path(@project)
+- page_title @page.title.capitalize, _("Wiki")
+- add_to_breadcrumbs _("Wiki"), get_project_wiki_path(@project)
.wiki-page-header.has-sidebar-toggle
%button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
@@ -11,9 +11,7 @@
.nav-text
%h2.wiki-page-title= @page.title.capitalize
%span.wiki-last-edit-by
- Last edited by
- %strong
- #{@page.commit.author.name}
+ = (_("Last edited by %{name}") % { name: "<strong>#{@page.commit.author_name}</strong>" }).html_safe
#{time_ago_with_tooltip(@page.commit.authored_date)}
.nav-controls
@@ -21,8 +19,10 @@
- if @page.historical?
.warning_message
- This is an old version of this page.
- You can view the #{link_to "most recent version", project_wiki_path(@project, @page)} or browse the #{link_to "history", project_wiki_history_path(@project, @page)}.
+ = s_("WikiHistoricalPage|This is an old version of this page.")
+ - most_recent_link = link_to s_("WikiHistoricalPage|most recent version"), project_wiki_path(@project, @page)
+ - history_link = link_to s_("WikiHistoricalPage|history"), project_wiki_history_path(@project, @page)
+ = (s_("WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}.") % { most_recent_link: most_recent_link, history_link: history_link }).html_safe
.wiki-holder.prepend-top-default.append-bottom-default
.wiki
diff --git a/app/views/shared/_personal_access_tokens_form.html.haml b/app/views/shared/_personal_access_tokens_form.html.haml
index e415ec64c38..b8b1f4ca42f 100644
--- a/app/views/shared/_personal_access_tokens_form.html.haml
+++ b/app/views/shared/_personal_access_tokens_form.html.haml
@@ -1,9 +1,9 @@
- type = impersonation ? "impersonation" : "personal access"
%h5.prepend-top-0
- Add a #{type} Token
+ Add a #{type} token
%p.profile-settings-content
- Pick a name for the application, and we'll give you a unique #{type} Token.
+ Pick a name for the application, and we'll give you a unique #{type} token.
= form_for token, url: path, method: :post, html: { class: 'js-requires-input' } do |f|
diff --git a/app/views/shared/_sidebar_toggle_button.html.haml b/app/views/shared/_sidebar_toggle_button.html.haml
index eb5ddb0dde4..2530db986e0 100644
--- a/app/views/shared/_sidebar_toggle_button.html.haml
+++ b/app/views/shared/_sidebar_toggle_button.html.haml
@@ -1,8 +1,8 @@
%a.toggle-sidebar-button.js-toggle-sidebar{ role: "button", type: "button", title: "Toggle sidebar" }
- = icon('angle-double-left')
- = icon('angle-double-right')
+ = sprite_icon('angle-double-left', css_class: 'icon-angle-double-left')
+ = sprite_icon('angle-double-right', css_class: 'icon-angle-double-right')
%span.collapse-text Collapse sidebar
= button_tag class: 'close-nav-button', type: 'button' do
- = icon ('times')
+ = sprite_icon('close', size: 16)
%span.collapse-text Close sidebar
diff --git a/app/views/shared/_target_switcher.html.haml b/app/views/shared/_target_switcher.html.haml
deleted file mode 100644
index bbe9692a7da..00000000000
--- a/app/views/shared/_target_switcher.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-- dropdown_toggle_text = @ref || @project.default_branch
-= form_tag nil, method: :get, class: "project-refs-form project-refs-target-form" do
- = hidden_field_tag :destination, destination
- - if defined?(path)
- = hidden_field_tag :path, path
- - @options && @options.each do |key, value|
- = hidden_field_tag key, value, id: nil
- .dropdown
- = dropdown_toggle dropdown_toggle_text, { toggle: "dropdown", selected: dropdown_toggle_text, ref: @ref, refs_url: refs_project_path(@project, find: ['branches']), field_name: 'ref', input_field_name: 'new-branch', submit_form_on_click: true, visit: false }, { toggle_class: "js-project-refs-dropdown" }
- .dropdown-menu.dropdown-menu-selectable.git-revision-dropdown{ class: ("dropdown-menu-align-right" if local_assigns[:align_right]) }
- = dropdown_title _("Create a new branch")
- = dropdown_input _("Create a new branch")
- = dropdown_title _("Select existing branch"), options: {close: false}
- = dropdown_filter _("Search branches and tags")
- = dropdown_content
- = dropdown_loading
diff --git a/app/views/shared/issuable/_participants.html.haml b/app/views/shared/issuable/_participants.html.haml
index 8a71819aa8e..d2b62557e03 100644
--- a/app/views/shared/issuable/_participants.html.haml
+++ b/app/views/shared/issuable/_participants.html.haml
@@ -11,7 +11,7 @@
.hide-collapsed.participants-list
- participants.each do |participant|
.participants-author.js-participants-author
- = link_to_member(@project, participant, name: false, size: 24)
+ = link_to_member(@project, participant, name: false, size: 24, lazy_load: true)
- if participants_extra > 0
.hide-collapsed.participants-more
%a.js-participants-more{ href: "#", data: { original_text: "+ #{participants_size - 7} more", less_text: "- show less" } }
diff --git a/app/views/shared/notes/_comment_button.html.haml b/app/views/shared/notes/_comment_button.html.haml
index 1dfe380db16..4b9af78bc1a 100644
--- a/app/views/shared/notes/_comment_button.html.haml
+++ b/app/views/shared/notes/_comment_button.html.haml
@@ -7,7 +7,7 @@
= button_tag type: 'button', class: 'btn btn-nr dropdown-toggle comment-btn js-note-new-discussion js-disable-on-submit', data: { 'dropdown-trigger' => '#resolvable-comment-menu' }, 'aria-label' => 'Open comment type dropdown' do
= icon('caret-down', class: 'toggle-icon')
- %ul#resolvable-comment-menu.dropdown-menu{ data: { dropdown: true } }
+ %ul#resolvable-comment-menu.dropdown-menu.dropdown-open-top{ data: { dropdown: true } }
%li#comment.droplab-item-selected{ data: { value: '', 'submit-text' => 'Comment', 'close-text' => "Comment & close #{noteable_name}", 'reopen-text' => "Comment & reopen #{noteable_name}" } }
%button.btn.btn-transparent
= icon('check', class: 'icon')
diff --git a/changelogs/unreleased/12673-fix_v3_project_hooks_build_events b/changelogs/unreleased/12673-fix_v3_project_hooks_build_events
deleted file mode 100644
index 59bc646406f..00000000000
--- a/changelogs/unreleased/12673-fix_v3_project_hooks_build_events
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: "Fix v3 api project_hooks POST and PUT operations for build_events"
-merge_request: 12673
-author: Richard Clamp
diff --git a/changelogs/unreleased/12892-reset-css-text-align-to-initial-for-rtl.md b/changelogs/unreleased/12892-reset-css-text-align-to-initial-for-rtl.md
deleted file mode 100644
index 87e95240bba..00000000000
--- a/changelogs/unreleased/12892-reset-css-text-align-to-initial-for-rtl.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: "reset text-align to initial to let elements with dir="auto" align texts to right in RTL languages ( default is left )"
-merge_request: 12892
-author: goshhob
diff --git a/changelogs/unreleased/13711-allow-same-period-housekeeping.yml b/changelogs/unreleased/13711-allow-same-period-housekeeping.yml
index 6749e22cf6a..607a8683aff 100644
--- a/changelogs/unreleased/13711-allow-same-period-housekeeping.yml
+++ b/changelogs/unreleased/13711-allow-same-period-housekeeping.yml
@@ -2,5 +2,5 @@
title: Allow to use same periods for different housekeeping tasks (effectively
skipping the lesser task)
merge_request: 13711
-author: @cernvcs
+author: cernvcs
type: added
diff --git a/changelogs/unreleased/14553-missing-space-in-log-msg.yml b/changelogs/unreleased/14553-missing-space-in-log-msg.yml
new file mode 100644
index 00000000000..a0420d49770
--- /dev/null
+++ b/changelogs/unreleased/14553-missing-space-in-log-msg.yml
@@ -0,0 +1,5 @@
+---
+title: "Add missing space in Sidekiq memory killer log message"
+merge_request: 14553
+author: Benjamin Drung
+type: fixed
diff --git a/changelogs/unreleased/22619-add-an-email-address-to-unsubscribe-list-header-in-email b/changelogs/unreleased/22619-add-an-email-address-to-unsubscribe-list-header-in-email
deleted file mode 100644
index f4011b756a5..00000000000
--- a/changelogs/unreleased/22619-add-an-email-address-to-unsubscribe-list-header-in-email
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Handle unsubscribe from email notifications via replying to reply+%{key}+unsubscribe@ address
-merge_request: 6597
-author:
diff --git a/changelogs/unreleased/26890-fix-default-branches-sorting.yml b/changelogs/unreleased/26890-fix-default-branches-sorting.yml
new file mode 100644
index 00000000000..cf7060190b3
--- /dev/null
+++ b/changelogs/unreleased/26890-fix-default-branches-sorting.yml
@@ -0,0 +1,5 @@
+---
+title: Fix the default branches sorting to actually be 'Last updated'
+merge_request: 14295
+author:
+type: fixed
diff --git a/changelogs/unreleased/26908-make-timelogs-use-foreign-keys b/changelogs/unreleased/26908-make-timelogs-use-foreign-keys
deleted file mode 100644
index 0e8f7093b34..00000000000
--- a/changelogs/unreleased/26908-make-timelogs-use-foreign-keys
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Refactor Timelogs structure to use foreign keys.
-merge_request: 8769
-author:
diff --git a/changelogs/unreleased/32340-correct-jobs-api-documentation b/changelogs/unreleased/32340-correct-jobs-api-documentation
deleted file mode 100644
index 4ada62356eb..00000000000
--- a/changelogs/unreleased/32340-correct-jobs-api-documentation
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: "Correction to documention for manual steps on the Jobs API"
-merge_request: 11411
-author: Zac Sturgess \ No newline at end of file
diff --git a/changelogs/unreleased/33493-attempt-to-link-saml-users-to-ldap-by-email.yml b/changelogs/unreleased/33493-attempt-to-link-saml-users-to-ldap-by-email.yml
new file mode 100644
index 00000000000..727f3cecd52
--- /dev/null
+++ b/changelogs/unreleased/33493-attempt-to-link-saml-users-to-ldap-by-email.yml
@@ -0,0 +1,5 @@
+---
+title: Link SAML users to LDAP by email.
+merge_request: 14216
+author:
+type: changed
diff --git a/changelogs/unreleased/34366-issue-sidebar-don-t-render-participants-in-collapsed-state.yml b/changelogs/unreleased/34366-issue-sidebar-don-t-render-participants-in-collapsed-state.yml
new file mode 100644
index 00000000000..d34e685b5f5
--- /dev/null
+++ b/changelogs/unreleased/34366-issue-sidebar-don-t-render-participants-in-collapsed-state.yml
@@ -0,0 +1,5 @@
+---
+title: Load sidebar participants avatars only when visible
+merge_request: 14270
+author:
+type: other
diff --git a/changelogs/unreleased/35942-api-binary-encoding.yaml b/changelogs/unreleased/35942-api-binary-encoding.yaml
deleted file mode 100644
index 4f7960d860e..00000000000
--- a/changelogs/unreleased/35942-api-binary-encoding.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-title: "Fix API to serve binary diffs that are treated as text."
-merge_request: 14038
diff --git a/changelogs/unreleased/3612-update-script-template-order-in-vue-files.yml b/changelogs/unreleased/3612-update-script-template-order-in-vue-files.yml
new file mode 100644
index 00000000000..cea6cb2e48b
--- /dev/null
+++ b/changelogs/unreleased/3612-update-script-template-order-in-vue-files.yml
@@ -0,0 +1,5 @@
+---
+title: Re-arrange <script> tags before <template> tags in .vue files
+merge_request: 14671
+author:
+type: changed
diff --git a/changelogs/unreleased/36631-activerecord-statementinvalid-pg-querycanceled-error-canceling-statement-due-to-statement-timeout.yml b/changelogs/unreleased/36631-activerecord-statementinvalid-pg-querycanceled-error-canceling-statement-due-to-statement-timeout.yml
new file mode 100644
index 00000000000..a2e1d07158b
--- /dev/null
+++ b/changelogs/unreleased/36631-activerecord-statementinvalid-pg-querycanceled-error-canceling-statement-due-to-statement-timeout.yml
@@ -0,0 +1,6 @@
+---
+title: Reschedule merge request diff background migrations to catch failures from
+ 9.5 run
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/36670-remove-edit-form.yml b/changelogs/unreleased/36670-remove-edit-form.yml
new file mode 100644
index 00000000000..4e80b685f67
--- /dev/null
+++ b/changelogs/unreleased/36670-remove-edit-form.yml
@@ -0,0 +1,5 @@
+---
+title: Remove the ability to visit the issue edit form directly
+merge_request: 14523
+author:
+type: removed
diff --git a/changelogs/unreleased/36742-hide-close-mr-button-on-merge.yml b/changelogs/unreleased/36742-hide-close-mr-button-on-merge.yml
new file mode 100644
index 00000000000..3d3efcdbcc6
--- /dev/null
+++ b/changelogs/unreleased/36742-hide-close-mr-button-on-merge.yml
@@ -0,0 +1,5 @@
+---
+title: Hide close MR button after merge without reloading page
+merge_request: 14122
+author: Jacopo Beschi @jacopo-beschi
+type: added
diff --git a/changelogs/unreleased/36953-add-gitLab-pages-version-to-admin-dashboard.yml b/changelogs/unreleased/36953-add-gitLab-pages-version-to-admin-dashboard.yml
index 680ef0cef92..9ac4a0ae7f3 100644
--- a/changelogs/unreleased/36953-add-gitLab-pages-version-to-admin-dashboard.yml
+++ b/changelogs/unreleased/36953-add-gitLab-pages-version-to-admin-dashboard.yml
@@ -1,5 +1,5 @@
---
title: Add GitLab-Pages version to Admin Dashboard
merge_request: 14040
-author: @travismiller
+author: travismiller
type: added
diff --git a/changelogs/unreleased/37229-mr-widget-status-icon.yml b/changelogs/unreleased/37229-mr-widget-status-icon.yml
new file mode 100644
index 00000000000..6d84d1964ca
--- /dev/null
+++ b/changelogs/unreleased/37229-mr-widget-status-icon.yml
@@ -0,0 +1,5 @@
+---
+title: fix merge request widget status icon for failed CI
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/37335-counter-active-state.yml b/changelogs/unreleased/37335-counter-active-state.yml
new file mode 100644
index 00000000000..a9632201a89
--- /dev/null
+++ b/changelogs/unreleased/37335-counter-active-state.yml
@@ -0,0 +1,5 @@
+---
+title: Add active states to nav bar counters
+merge_request:
+author:
+type: changed
diff --git a/changelogs/unreleased/37467-helper-method-from-users-endpoint-overrides-api-helper-method.yml b/changelogs/unreleased/37467-helper-method-from-users-endpoint-overrides-api-helper-method.yml
deleted file mode 100644
index 1984ec6e81c..00000000000
--- a/changelogs/unreleased/37467-helper-method-from-users-endpoint-overrides-api-helper-method.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: find_user Users helper method no longer overrides find_user API helper method.
-merge_request: 14418
-author:
-type: fixed
diff --git a/changelogs/unreleased/37970-timestamped-ci.yml b/changelogs/unreleased/37970-timestamped-ci.yml
new file mode 100644
index 00000000000..2a4797f069a
--- /dev/null
+++ b/changelogs/unreleased/37970-timestamped-ci.yml
@@ -0,0 +1,5 @@
+---
+title: Strip gitlab-runner section markers in build trace HTML view
+merge_request: 14393
+author:
+type: added
diff --git a/changelogs/unreleased/38036-hover-and-legend-data-should-be-linked.yml b/changelogs/unreleased/38036-hover-and-legend-data-should-be-linked.yml
new file mode 100644
index 00000000000..591e542cd17
--- /dev/null
+++ b/changelogs/unreleased/38036-hover-and-legend-data-should-be-linked.yml
@@ -0,0 +1,5 @@
+---
+title: Sync up hover and legend data across all graphs for the prometheus dashboard
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/38052-use-simple-api-for-projects.yml b/changelogs/unreleased/38052-use-simple-api-for-projects.yml
new file mode 100644
index 00000000000..49c7485861e
--- /dev/null
+++ b/changelogs/unreleased/38052-use-simple-api-for-projects.yml
@@ -0,0 +1,5 @@
+---
+title: Use `simple=true` for projects API in Projects dropdown for better search performance
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/38187-38315-fix-dropdown-open-top-bottom-spacing.yml b/changelogs/unreleased/38187-38315-fix-dropdown-open-top-bottom-spacing.yml
new file mode 100644
index 00000000000..579c247c4c2
--- /dev/null
+++ b/changelogs/unreleased/38187-38315-fix-dropdown-open-top-bottom-spacing.yml
@@ -0,0 +1,5 @@
+---
+title: Fix bottom spacing for dropdowns that open upwards
+merge_request: 14535
+author:
+type: fixed
diff --git a/changelogs/unreleased/38202-cannot-rename-a-hashed-project.yml b/changelogs/unreleased/38202-cannot-rename-a-hashed-project.yml
new file mode 100644
index 00000000000..768e296fcd7
--- /dev/null
+++ b/changelogs/unreleased/38202-cannot-rename-a-hashed-project.yml
@@ -0,0 +1,6 @@
+---
+title: Does not check if an invariant hashed storage path exists on disk when renaming
+ projects.
+merge_request: 14428
+author:
+type: fixed
diff --git a/changelogs/unreleased/38319-nomethoderror-undefined-method-sha-for-nil-nilclass.yml b/changelogs/unreleased/38319-nomethoderror-undefined-method-sha-for-nil-nilclass.yml
deleted file mode 100644
index f3c39827590..00000000000
--- a/changelogs/unreleased/38319-nomethoderror-undefined-method-sha-for-nil-nilclass.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix 500 error on merged merge requests when GitLab is restored from a backup
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/38417-use-explicit-boolean-vue-attribute.yml b/changelogs/unreleased/38417-use-explicit-boolean-vue-attribute.yml
new file mode 100644
index 00000000000..419e9295d32
--- /dev/null
+++ b/changelogs/unreleased/38417-use-explicit-boolean-vue-attribute.yml
@@ -0,0 +1,5 @@
+---
+title: Use explicit boolean true attribute for show-disabled-button in Vue files
+merge_request: 14672
+author:
+type: fixed
diff --git a/changelogs/unreleased/38432-fix-notes-type-for-import.yml b/changelogs/unreleased/38432-fix-notes-type-for-import.yml
new file mode 100644
index 00000000000..db8371f4420
--- /dev/null
+++ b/changelogs/unreleased/38432-fix-notes-type-for-import.yml
@@ -0,0 +1,6 @@
+---
+title: Fix notes type created from import. This should fix some missing notes issues
+ from imported projects
+merge_request: 14524
+author:
+type: fixed
diff --git a/changelogs/unreleased/38476-improve-merge-jid-cleanup-on-merge-process.yml b/changelogs/unreleased/38476-improve-merge-jid-cleanup-on-merge-process.yml
deleted file mode 100644
index 43dec51029b..00000000000
--- a/changelogs/unreleased/38476-improve-merge-jid-cleanup-on-merge-process.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adjust MRs being stuck on "process of being merged" for more than 2 hours
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/38502-fix-nav-dropdown-close-animation.yml b/changelogs/unreleased/38502-fix-nav-dropdown-close-animation.yml
new file mode 100644
index 00000000000..974adb9ed28
--- /dev/null
+++ b/changelogs/unreleased/38502-fix-nav-dropdown-close-animation.yml
@@ -0,0 +1,5 @@
+---
+title: Fix navigation dropdown close animation on mobile screens
+merge_request: 14649
+author:
+type: fixed
diff --git a/changelogs/unreleased/38571-fix-exception-in-raven-report.yml b/changelogs/unreleased/38571-fix-exception-in-raven-report.yml
new file mode 100644
index 00000000000..62e3b8d304c
--- /dev/null
+++ b/changelogs/unreleased/38571-fix-exception-in-raven-report.yml
@@ -0,0 +1,6 @@
+---
+title: Ensure no exception is raised when Raven tries to get the current user in API
+ context
+merge_request: 14580
+author:
+type: fixed
diff --git a/changelogs/unreleased/38619-fix-comment-delete-confirm-text.yml b/changelogs/unreleased/38619-fix-comment-delete-confirm-text.yml
new file mode 100644
index 00000000000..a203bff8410
--- /dev/null
+++ b/changelogs/unreleased/38619-fix-comment-delete-confirm-text.yml
@@ -0,0 +1,5 @@
+---
+title: Fix comment deletion confirmation dialog typo
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/38635-fix-gitlab-check-git-ssh-config.yml b/changelogs/unreleased/38635-fix-gitlab-check-git-ssh-config.yml
new file mode 100644
index 00000000000..49d0671233a
--- /dev/null
+++ b/changelogs/unreleased/38635-fix-gitlab-check-git-ssh-config.yml
@@ -0,0 +1,5 @@
+---
+title: Whitelist authorized_keys.lock in the gitlab:check rake task
+merge_request: 14624
+author:
+type: fixed
diff --git a/changelogs/unreleased/38789-prometheus-graphs-occasionally-have-incorrect-y-scale.yml b/changelogs/unreleased/38789-prometheus-graphs-occasionally-have-incorrect-y-scale.yml
new file mode 100644
index 00000000000..bbfe5d49a3e
--- /dev/null
+++ b/changelogs/unreleased/38789-prometheus-graphs-occasionally-have-incorrect-y-scale.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken Y-axis scaling in some Prometheus graphs
+merge_request: 14693
+author:
+type: fixed
diff --git a/changelogs/unreleased/add-ci-builds-index-for-jobscontroller.yml b/changelogs/unreleased/add-ci-builds-index-for-jobscontroller.yml
new file mode 100644
index 00000000000..7f098c8f60c
--- /dev/null
+++ b/changelogs/unreleased/add-ci-builds-index-for-jobscontroller.yml
@@ -0,0 +1,5 @@
+---
+title: Change index on ci_builds to optimize Jobs Controller
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/add-composite-index-on-merge-requests-merge-commit-sha.yml b/changelogs/unreleased/add-composite-index-on-merge-requests-merge-commit-sha.yml
new file mode 100644
index 00000000000..9a600282716
--- /dev/null
+++ b/changelogs/unreleased/add-composite-index-on-merge-requests-merge-commit-sha.yml
@@ -0,0 +1,5 @@
+---
+title: Add index for merge_requests.merge_commit_sha
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/add-labels-template-index.yml b/changelogs/unreleased/add-labels-template-index.yml
new file mode 100644
index 00000000000..5f66c4ce181
--- /dev/null
+++ b/changelogs/unreleased/add-labels-template-index.yml
@@ -0,0 +1,5 @@
+---
+title: Add (partial) index on Labels.template
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/add-mock-deployment-and-monitoring-service-for-development.yaml b/changelogs/unreleased/add-mock-deployment-and-monitoring-service-for-development.yaml
deleted file mode 100644
index 4c81d21a94b..00000000000
--- a/changelogs/unreleased/add-mock-deployment-and-monitoring-service-for-development.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Added mock deployment and monitoring service with environments fixtures
-merge_request:
-author:
diff --git a/changelogs/unreleased/breadcrumb-item-links.yml b/changelogs/unreleased/breadcrumb-item-links.yml
new file mode 100644
index 00000000000..9b66456efca
--- /dev/null
+++ b/changelogs/unreleased/breadcrumb-item-links.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed issue/merge request breadcrumb titles not having links
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/bvl-fix-close-issuable-link.yml b/changelogs/unreleased/bvl-fix-close-issuable-link.yml
deleted file mode 100644
index 140a9d35cc1..00000000000
--- a/changelogs/unreleased/bvl-fix-close-issuable-link.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix CSRF validation issue when closing/opening merge requests from the UI
-merge_request: 14555
-author:
-type: fixed
diff --git a/changelogs/unreleased/close-issue-by-implements.yml b/changelogs/unreleased/close-issue-by-implements.yml
new file mode 100644
index 00000000000..fe36ce3f7aa
--- /dev/null
+++ b/changelogs/unreleased/close-issue-by-implements.yml
@@ -0,0 +1,5 @@
+---
+title: "Add \"implements\" to the default issue closing message regex"
+merge_request: 14612
+author: Guilherme Vieira
+type: added
diff --git a/changelogs/unreleased/commit-row-avatar-align-top.yml b/changelogs/unreleased/commit-row-avatar-align-top.yml
new file mode 100644
index 00000000000..aa5ab770bd8
--- /dev/null
+++ b/changelogs/unreleased/commit-row-avatar-align-top.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed commit avatars being centered vertically
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/commit-side-by-side-comment.yml b/changelogs/unreleased/commit-side-by-side-comment.yml
deleted file mode 100644
index f9bea285a77..00000000000
--- a/changelogs/unreleased/commit-side-by-side-comment.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed commenting on side-by-side commit diff
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/dm-api-unauthorized.yml b/changelogs/unreleased/dm-api-unauthorized.yml
deleted file mode 100644
index 26b45bd4c40..00000000000
--- a/changelogs/unreleased/dm-api-unauthorized.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make sure API responds with 401 when invalid authentication info is provided
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/dm-copy-parallel-diff.yml b/changelogs/unreleased/dm-copy-parallel-diff.yml
new file mode 100644
index 00000000000..96a65007661
--- /dev/null
+++ b/changelogs/unreleased/dm-copy-parallel-diff.yml
@@ -0,0 +1,5 @@
+---
+title: Only copy old/new code when selecting left/right side of parallel diff
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/dm-pat-revoke.yml b/changelogs/unreleased/dm-pat-revoke.yml
new file mode 100644
index 00000000000..32ac66056d5
--- /dev/null
+++ b/changelogs/unreleased/dm-pat-revoke.yml
@@ -0,0 +1,5 @@
+---
+title: Set default scope on PATs that don't have one set to allow them to be revoked
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/docs-add-summary-about-project-archiving.yml b/changelogs/unreleased/docs-add-summary-about-project-archiving.yml
new file mode 100644
index 00000000000..cc1b48a682d
--- /dev/null
+++ b/changelogs/unreleased/docs-add-summary-about-project-archiving.yml
@@ -0,0 +1,5 @@
+---
+title: Add documentation to summarise project archiving
+merge_request: 14650
+author:
+type: other
diff --git a/changelogs/unreleased/docs-openid-connect.yml b/changelogs/unreleased/docs-openid-connect.yml
new file mode 100644
index 00000000000..3989ec53cfa
--- /dev/null
+++ b/changelogs/unreleased/docs-openid-connect.yml
@@ -0,0 +1,5 @@
+---
+title: Add link to OpenID Connect documentation
+merge_request: 14368
+author: Markus Koller
+type: other
diff --git a/changelogs/unreleased/ff_port_from_ee.yml b/changelogs/unreleased/ff_port_from_ee.yml
new file mode 100644
index 00000000000..e1cb7804a47
--- /dev/null
+++ b/changelogs/unreleased/ff_port_from_ee.yml
@@ -0,0 +1,5 @@
+---
+title: Move Custom merge methods from EE
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/fix-edit-project-service-cancel-button-position.yml b/changelogs/unreleased/fix-edit-project-service-cancel-button-position.yml
new file mode 100644
index 00000000000..efb993eff71
--- /dev/null
+++ b/changelogs/unreleased/fix-edit-project-service-cancel-button-position.yml
@@ -0,0 +1,5 @@
+---
+title: Fix edit project service cancel button position
+merge_request: 14596
+author: Matt Coleman
+type: fixed
diff --git a/changelogs/unreleased/fix-gpg-case-insensitive.yml b/changelogs/unreleased/fix-gpg-case-insensitive.yml
new file mode 100644
index 00000000000..744ec00a4a8
--- /dev/null
+++ b/changelogs/unreleased/fix-gpg-case-insensitive.yml
@@ -0,0 +1,5 @@
+---
+title: Compare email addresses case insensitively when verifying GPG signatures
+merge_request: 14376
+author: Tim Bishop
+type: fixed
diff --git a/changelogs/unreleased/fix-mr-sidebar-counter-after-merge.yml b/changelogs/unreleased/fix-mr-sidebar-counter-after-merge.yml
deleted file mode 100644
index 22a3efb8b1e..00000000000
--- a/changelogs/unreleased/fix-mr-sidebar-counter-after-merge.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix merge request counter updates after merge
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/gem-sm-bump-google-api-client-gem-from-0-8-6-to-0-13-6.yml b/changelogs/unreleased/gem-sm-bump-google-api-client-gem-from-0-8-6-to-0-13-6.yml
new file mode 100644
index 00000000000..13ec113167f
--- /dev/null
+++ b/changelogs/unreleased/gem-sm-bump-google-api-client-gem-from-0-8-6-to-0-13-6.yml
@@ -0,0 +1,5 @@
+---
+title: Bump google-api-client Gem from 0.8.6 to 0.13.6
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/hash-mr-scroll-load.yml b/changelogs/unreleased/hash-mr-scroll-load.yml
new file mode 100644
index 00000000000..7e3965add03
--- /dev/null
+++ b/changelogs/unreleased/hash-mr-scroll-load.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed notes not being scrolled to in merge requests
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/lint-changelog-yaml.yml b/changelogs/unreleased/lint-changelog-yaml.yml
new file mode 100644
index 00000000000..dcc8bf54827
--- /dev/null
+++ b/changelogs/unreleased/lint-changelog-yaml.yml
@@ -0,0 +1,5 @@
+---
+title: Detect when changelog entries are invalid
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/mentions-in-comments.yml b/changelogs/unreleased/mentions-in-comments.yml
new file mode 100644
index 00000000000..907f455007b
--- /dev/null
+++ b/changelogs/unreleased/mentions-in-comments.yml
@@ -0,0 +1,5 @@
+---
+title: Makes @mentions links have a different styling for better separation
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/merge-request-notes-performance.yml b/changelogs/unreleased/merge-request-notes-performance.yml
new file mode 100644
index 00000000000..6cf7a5047df
--- /dev/null
+++ b/changelogs/unreleased/merge-request-notes-performance.yml
@@ -0,0 +1,5 @@
+---
+title: Use a UNION ALL for getting merge request notes
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/mr-widget-merged-date-tooltip.yml b/changelogs/unreleased/mr-widget-merged-date-tooltip.yml
new file mode 100644
index 00000000000..ea22993ff52
--- /dev/null
+++ b/changelogs/unreleased/mr-widget-merged-date-tooltip.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed merge request widget merged & closed date tooltip text
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/rd-fix-case-sensative-email-conf-signup.yml b/changelogs/unreleased/rd-fix-case-sensative-email-conf-signup.yml
new file mode 100644
index 00000000000..69695e403a9
--- /dev/null
+++ b/changelogs/unreleased/rd-fix-case-sensative-email-conf-signup.yml
@@ -0,0 +1,5 @@
+---
+title: Fix case sensitive email confirmation on signup
+merge_request: 14606
+author: robdel12
+type: fixed
diff --git a/changelogs/unreleased/remote_user.yml b/changelogs/unreleased/remote_user.yml
new file mode 100644
index 00000000000..75a941fa95f
--- /dev/null
+++ b/changelogs/unreleased/remote_user.yml
@@ -0,0 +1,4 @@
+---
+title: Add username as GL_USERNAME in hooks
+merge_request:
+author:
diff --git a/changelogs/unreleased/remove_repo_prefix_from_api.yml b/changelogs/unreleased/remove_repo_prefix_from_api.yml
new file mode 100644
index 00000000000..bf2075e529c
--- /dev/null
+++ b/changelogs/unreleased/remove_repo_prefix_from_api.yml
@@ -0,0 +1,5 @@
+---
+title: Remove 'Repo' prefix from API entites
+merge_request: 14694
+author: Vitaliy @blackst0ne Klachkov
+type: other
diff --git a/changelogs/unreleased/repository-name-emojis b/changelogs/unreleased/repository-name-emojis
deleted file mode 100644
index fe52df8eedc..00000000000
--- a/changelogs/unreleased/repository-name-emojis
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Added ability to put emojis into repository name
-merge_request: 7420
-author: Vincent Composieux
diff --git a/changelogs/unreleased/sh-fix-username-logging.yml b/changelogs/unreleased/sh-fix-username-logging.yml
new file mode 100644
index 00000000000..dadf3fb6729
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-username-logging.yml
@@ -0,0 +1,5 @@
+---
+title: Fix username and ID not logging in production_json.log for Git activity
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-thread-safe-markdown.yml b/changelogs/unreleased/sh-thread-safe-markdown.yml
new file mode 100644
index 00000000000..af7d9d58a9f
--- /dev/null
+++ b/changelogs/unreleased/sh-thread-safe-markdown.yml
@@ -0,0 +1,5 @@
+---
+title: Make Redcarpet Markdown renderer thread-safe
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/tag-link-size.yml b/changelogs/unreleased/tag-link-size.yml
new file mode 100644
index 00000000000..d94e415ba1f
--- /dev/null
+++ b/changelogs/unreleased/tag-link-size.yml
@@ -0,0 +1,5 @@
+---
+title: Adjusts tag link to avoid underlining spaces
+merge_request: 14544
+author: Guilherme Vieira
+type: fixed
diff --git a/changelogs/unreleased/update-pages-0-6.yml b/changelogs/unreleased/update-pages-0-6.yml
new file mode 100644
index 00000000000..507bb4d78e9
--- /dev/null
+++ b/changelogs/unreleased/update-pages-0-6.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Pages to v0.6.0
+merge_request: 14630
+author:
+type: other
diff --git a/changelogs/unreleased/winh-sprintf.yml b/changelogs/unreleased/winh-sprintf.yml
new file mode 100644
index 00000000000..f8ae5932ae4
--- /dev/null
+++ b/changelogs/unreleased/winh-sprintf.yml
@@ -0,0 +1,5 @@
+---
+title: Add basic sprintf implementation to JavaScript
+merge_request: 14506
+author:
+type: other
diff --git a/changelogs/unreleased/zj-repo-gitaly.yml b/changelogs/unreleased/zj-repo-gitaly.yml
deleted file mode 100644
index 634f6ba1b8b..00000000000
--- a/changelogs/unreleased/zj-repo-gitaly.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Gitaly RepositoryExists remains opt-in for all method calls
-merge_request:
-author:
-type: fixed
diff --git a/config/application.rb b/config/application.rb
index 30117b6a98e..ca2ab83becc 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -105,6 +105,7 @@ module Gitlab
config.assets.precompile << "lib/ace.js"
config.assets.precompile << "vendor/assets/fonts/*"
config.assets.precompile << "test.css"
+ config.assets.precompile << "locale/**/app.js"
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 278144b8943..1edb6fd39b8 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -16,7 +16,7 @@ Rails.application.configure do
config.cache_classes = ENV['CACHE_CLASSES'] == 'true'
# Configure static asset server for tests with Cache-Control for performance
- config.assets.digest = false
+ config.assets.compile = false if ENV['CI']
config.serve_static_files = true
config.static_cache_control = "public, max-age=3600"
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 9b496822e93..88771c5f5bb 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -89,7 +89,7 @@ production: &base
# This happens when the commit is pushed or merged into the default branch of a project.
# When not specified the default issue_closing_pattern as specified below will be used.
# Tip: you can test your closing pattern at http://rubular.com.
- # issue_closing_pattern: '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing))(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)'
+ # issue_closing_pattern: '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)'
## Default project features settings
default_projects_features:
@@ -499,6 +499,8 @@ production: &base
# Gitaly settings
gitaly:
+ # Path to the directory containing Gitaly client executables.
+ client_path: /home/git/gitaly
# Default Gitaly authentication token. Can be overriden per storage. Can
# be left blank when Gitaly is running locally on a Unix socket, which
# is the normal way to deploy Gitaly.
@@ -664,7 +666,7 @@ test:
gitaly_address: unix:tmp/tests/gitaly/gitaly.socket
gitaly:
- enabled: true
+ client_path: tmp/tests/gitaly
token: secret
backup:
path: tmp/tests/backups
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 27c1ecc7b23..a23b3208dab 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -257,7 +257,7 @@ Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].
Settings.gitlab['password_authentication_enabled'] ||= true if Settings.gitlab['password_authentication_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.__send__(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
-Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing))(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil?
+Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil?
Settings.gitlab['default_projects_features'] ||= {}
Settings.gitlab['webhook_timeout'] ||= 10
Settings.gitlab['max_attachment_size'] ||= 10
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 3aed2136f1b..0ba0d791054 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -36,7 +36,7 @@ Devise.setup do |config|
# Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
- config.case_insensitive_keys = [:email]
+ config.case_insensitive_keys = [:email, :email_confirmation]
# Configure which authentication keys should have whitespace stripped.
# These keys will have whitespace before and after removed upon creating or
diff --git a/config/initializers/gettext_rails_i18n_patch.rb b/config/initializers/gettext_rails_i18n_patch.rb
index 377e5104f9d..49551319435 100644
--- a/config/initializers/gettext_rails_i18n_patch.rb
+++ b/config/initializers/gettext_rails_i18n_patch.rb
@@ -39,3 +39,17 @@ module GettextI18nRailsJs
end
end
end
+
+class PoToJson
+ # This is required to modify the JS locale file output to our import needs
+ # Overwrites: https://github.com/webhippie/po_to_json/blob/master/lib/po_to_json.rb#L46
+ def generate_for_jed(language, overwrite = {})
+ @options = parse_options(overwrite.merge(language: language))
+ @parsed ||= inject_meta(parse_document)
+
+ generated = build_json_for(build_jed_for(@parsed))
+ [
+ "window.translations = #{generated};"
+ ].join(" ")
+ end
+end
diff --git a/config/initializers/grpc.rb b/config/initializers/grpc.rb
new file mode 100644
index 00000000000..b96962fe7db
--- /dev/null
+++ b/config/initializers/grpc.rb
@@ -0,0 +1,11 @@
+require 'logger'
+
+GRPC_LOGGER = Logger.new(Rails.root.join('log/grpc.log'))
+GRPC_LOGGER.level = ENV['GRPC_LOG_LEVEL'].presence || 'WARN'
+GRPC_LOGGER.progname = 'GRPC'
+
+module GRPC
+ def self.logger
+ GRPC_LOGGER
+ end
+end
diff --git a/config/routes/project.rb b/config/routes/project.rb
index b36d13888cd..70d7673250c 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -271,7 +271,7 @@ constraints(ProjectUrlConstrainer.new) do
namespace :registry do
resources :repository, only: [] do
- resources :tags, only: [:destroy],
+ resources :tags, only: [:index, :destroy],
constraints: { id: Gitlab::Regex.container_registry_tag_regex }
end
end
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 3404715fe30..c515a170d2d 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -68,6 +68,7 @@ var config = {
prometheus_metrics: './prometheus_metrics',
protected_branches: './protected_branches',
protected_tags: './protected_tags',
+ registry_list: './registry/index.js',
repo: './repo/index.js',
sidebar: './sidebar/sidebar_bundle.js',
schedule_form: './pipeline_schedules/pipeline_schedule_form_bundle.js',
@@ -122,10 +123,6 @@ var config = {
}
},
{
- test: /locale\/\w+\/(.*)\.js$/,
- loader: 'exports-loader?locales',
- },
- {
test: /monaco-editor\/\w+\/vs\/loader\.js$/,
use: [
{ loader: 'exports-loader', options: 'l.global' },
@@ -200,6 +197,7 @@ var config = {
'pdf_viewer',
'pipelines',
'pipelines_details',
+ 'registry_list',
'repo',
'schedule_form',
'schedules_index',
@@ -222,7 +220,7 @@ var config = {
// create cacheable common library bundles
new webpack.optimize.CommonsChunkPlugin({
- names: ['main', 'locale', 'common', 'webpack_runtime'],
+ names: ['main', 'common', 'webpack_runtime'],
}),
// enable scope hoisting
diff --git a/db/migrate/20141126120926_add_merge_request_rebase_enabled_to_projects.rb b/db/migrate/20141126120926_add_merge_request_rebase_enabled_to_projects.rb
new file mode 100644
index 00000000000..3dafdf0fde4
--- /dev/null
+++ b/db/migrate/20141126120926_add_merge_request_rebase_enabled_to_projects.rb
@@ -0,0 +1,17 @@
+# rubocop:disable all
+class AddMergeRequestRebaseEnabledToProjects < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default(:projects, :merge_requests_rebase_enabled, :boolean, default: false)
+ end
+
+ def down
+ remove_column(:projects, :merge_requests_rebase_enabled)
+ end
+end
diff --git a/db/migrate/20150827121444_add_fast_forward_option_to_project.rb b/db/migrate/20150827121444_add_fast_forward_option_to_project.rb
new file mode 100644
index 00000000000..6f22641077d
--- /dev/null
+++ b/db/migrate/20150827121444_add_fast_forward_option_to_project.rb
@@ -0,0 +1,19 @@
+# rubocop:disable all
+class AddFastForwardOptionToProject < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false)
+ end
+
+ def down
+ if column_exists?(:projects, :merge_requests_ff_only_enabled)
+ remove_column(:projects, :merge_requests_ff_only_enabled)
+ end
+ end
+end
diff --git a/db/migrate/20170927095921_add_ci_builds_index_for_jobscontroller.rb b/db/migrate/20170927095921_add_ci_builds_index_for_jobscontroller.rb
new file mode 100644
index 00000000000..c2cb1df2586
--- /dev/null
+++ b/db/migrate/20170927095921_add_ci_builds_index_for_jobscontroller.rb
@@ -0,0 +1,39 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddCiBuildsIndexForJobscontroller < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ # When a migration requires downtime you **must** uncomment the following
+ # constant and define a short and easy to understand explanation as to why the
+ # migration requires downtime.
+ # DOWNTIME_REASON = ''
+
+ # When using the methods "add_concurrent_index", "remove_concurrent_index" or
+ # "add_column_with_default" you must disable the use of transactions
+ # as these methods can not run in an existing transaction.
+ # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
+ # that either of them is the _only_ method called in the migration,
+ # any other changes should go in a separate migration.
+ # This ensures that upon failure _only_ the index creation or removing fails
+ # and can be retried or reverted easily.
+ #
+ # To disable transactions uncomment the following line and remove these
+ # comments:
+ # disable_ddl_transaction!
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_builds, [:project_id, :id] unless index_exists? :ci_builds, [:project_id, :id]
+ remove_concurrent_index :ci_builds, :project_id if index_exists? :ci_builds, :project_id
+ end
+
+ def down
+ add_concurrent_index :ci_builds, :project_id unless index_exists? :ci_builds, :project_id
+ remove_concurrent_index :ci_builds, [:project_id, :id] if index_exists? :ci_builds, [:project_id, :id]
+ end
+end
diff --git a/db/migrate/20170927122209_add_partial_index_for_labels_template.rb b/db/migrate/20170927122209_add_partial_index_for_labels_template.rb
new file mode 100644
index 00000000000..c3e5077ba20
--- /dev/null
+++ b/db/migrate/20170927122209_add_partial_index_for_labels_template.rb
@@ -0,0 +1,45 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddPartialIndexForLabelsTemplate < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ # When a migration requires downtime you **must** uncomment the following
+ # constant and define a short and easy to understand explanation as to why the
+ # migration requires downtime.
+ # DOWNTIME_REASON = ''
+
+ # When using the methods "add_concurrent_index", "remove_concurrent_index" or
+ # "add_column_with_default" you must disable the use of transactions
+ # as these methods can not run in an existing transaction.
+ # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
+ # that either of them is the _only_ method called in the migration,
+ # any other changes should go in a separate migration.
+ # This ensures that upon failure _only_ the index creation or removing fails
+ # and can be retried or reverted easily.
+ #
+ # To disable transactions uncomment the following line and remove these
+ # comments:
+
+ disable_ddl_transaction!
+
+ # Note this is a partial index in Postgres but MySQL will ignore the
+ # partial index clause. By making it an index on "template" this
+ # means the index will still accomplish the same goal of optimizing
+ # a query with "where template = true" on MySQL -- it'll just take
+ # more space. In this case the number of records with template=true
+ # is expected to be very small (small enough to display on a single
+ # web page) so it's ok to filter or sort them without the index
+ # anyways.
+
+ def up
+ add_concurrent_index "labels", ["template"], where: "template"
+ end
+
+ def down
+ remove_concurrent_index "labels", ["template"], where: "template"
+ end
+end
diff --git a/db/migrate/20170928100231_add_composite_index_on_merge_requests_merge_commit_sha.rb b/db/migrate/20170928100231_add_composite_index_on_merge_requests_merge_commit_sha.rb
new file mode 100644
index 00000000000..9f02daf04c1
--- /dev/null
+++ b/db/migrate/20170928100231_add_composite_index_on_merge_requests_merge_commit_sha.rb
@@ -0,0 +1,33 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddCompositeIndexOnMergeRequestsMergeCommitSha < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ # The default index name is too long for PostgreSQL and would thus be
+ # truncated.
+ INDEX_NAME = 'index_merge_requests_on_tp_id_and_merge_commit_sha_and_id'
+
+ COLUMNS = [:target_project_id, :merge_commit_sha, :id]
+
+ disable_ddl_transaction!
+
+ def up
+ return if index_is_present?
+
+ add_concurrent_index(:merge_requests, COLUMNS, name: INDEX_NAME)
+ end
+
+ def down
+ return unless index_is_present?
+
+ remove_concurrent_index(:merge_requests, COLUMNS, name: INDEX_NAME)
+ end
+
+ def index_is_present?
+ index_exists?(:merge_requests, COLUMNS, name: INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb b/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb
new file mode 100644
index 00000000000..ac266c3e22e
--- /dev/null
+++ b/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb
@@ -0,0 +1,25 @@
+# rubocop:disable all
+class MakeSureFastForwardOptionExists < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ # We had to fix the migration db/migrate/20150827121444_add_fast_forward_option_to_project.rb
+ # And this is why it's possible that someone has ran the migrations but does
+ # not have the merge_requests_ff_only_enabled column. This migration makes sure it will
+ # be added
+ unless column_exists?(:projects, :merge_requests_ff_only_enabled)
+ add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false)
+ end
+ end
+
+ def down
+ if column_exists?(:projects, :merge_requests_ff_only_enabled)
+ remove_column(:projects, :merge_requests_ff_only_enabled)
+ end
+ end
+end
diff --git a/db/post_migrate/20170926150348_schedule_merge_request_diff_migrations_take_two.rb b/db/post_migrate/20170926150348_schedule_merge_request_diff_migrations_take_two.rb
new file mode 100644
index 00000000000..5732cb85ea5
--- /dev/null
+++ b/db/post_migrate/20170926150348_schedule_merge_request_diff_migrations_take_two.rb
@@ -0,0 +1,32 @@
+class ScheduleMergeRequestDiffMigrationsTakeTwo < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ BATCH_SIZE = 500
+ MIGRATION = 'DeserializeMergeRequestDiffsAndCommits'
+ DELAY_INTERVAL = 10.minutes
+
+ disable_ddl_transaction!
+
+ class MergeRequestDiff < ActiveRecord::Base
+ self.table_name = 'merge_request_diffs'
+
+ include ::EachBatch
+
+ default_scope { where('st_commits IS NOT NULL OR st_diffs IS NOT NULL') }
+ end
+
+ # By this point, we assume ScheduleMergeRequestDiffMigrations - the first
+ # version of this - has already run. On GitLab.com, we have ~220k un-migrated
+ # rows, but these rows will, in general, take a long time.
+ #
+ # With a gap of 10 minutes per batch, and 500 rows per batch, these migrations
+ # are scheduled over 220_000 / 500 / 6 ~= 74 hours, which is a little over
+ # three days.
+ def up
+ queue_background_migration_jobs_by_range_at_intervals(MergeRequestDiff, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
+ end
+
+ def down
+ end
+end
diff --git a/db/post_migrate/20170927112318_update_legacy_diff_notes_type_for_import.rb b/db/post_migrate/20170927112318_update_legacy_diff_notes_type_for_import.rb
new file mode 100644
index 00000000000..a238216253b
--- /dev/null
+++ b/db/post_migrate/20170927112318_update_legacy_diff_notes_type_for_import.rb
@@ -0,0 +1,16 @@
+class UpdateLegacyDiffNotesTypeForImport < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ update_column_in_batches(:notes, :type, 'LegacyDiffNote') do |table, query|
+ query.where(table[:type].eq('Github::Import::LegacyDiffNote'))
+ end
+ end
+
+ def down
+ end
+end
diff --git a/db/post_migrate/20170927112319_update_notes_type_for_import.rb b/db/post_migrate/20170927112319_update_notes_type_for_import.rb
new file mode 100644
index 00000000000..1e70acd9868
--- /dev/null
+++ b/db/post_migrate/20170927112319_update_notes_type_for_import.rb
@@ -0,0 +1,16 @@
+class UpdateNotesTypeForImport < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ update_column_in_batches(:notes, :type, 'Note') do |table, query|
+ query.where(table[:type].eq('Github::Import::Note'))
+ end
+ end
+
+ def down
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index d14d4d8b94d..fa1aad257db 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: 20170921115009) do
+ActiveRecord::Schema.define(version: 20171004121444) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -256,7 +256,7 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_index "ci_builds", ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree
add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree
add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree
- add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree
+ add_index "ci_builds", ["project_id", "id"], name: "index_ci_builds_on_project_id_and_id", using: :btree
add_index "ci_builds", ["protected"], name: "index_ci_builds_on_protected", using: :btree
add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree
add_index "ci_builds", ["stage_id"], name: "index_ci_builds_on_stage_id", using: :btree
@@ -730,6 +730,7 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_index "labels", ["group_id", "project_id", "title"], name: "index_labels_on_group_id_and_project_id_and_title", unique: true, using: :btree
add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree
+ add_index "labels", ["template"], name: "index_labels_on_template", where: "template", using: :btree
add_index "labels", ["title"], name: "index_labels_on_title", using: :btree
add_index "labels", ["type", "project_id"], name: "index_labels_on_type_and_project_id", using: :btree
@@ -895,6 +896,7 @@ ActiveRecord::Schema.define(version: 20170921115009) do
add_index "merge_requests", ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_id_and_source_branch", using: :btree
add_index "merge_requests", ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree
add_index "merge_requests", ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid", unique: true, using: :btree
+ add_index "merge_requests", ["target_project_id", "merge_commit_sha", "id"], name: "index_merge_requests_on_tp_id_and_merge_commit_sha_and_id", using: :btree
add_index "merge_requests", ["title"], name: "index_merge_requests_on_title", using: :btree
add_index "merge_requests", ["title"], name: "index_merge_requests_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"}
@@ -1216,6 +1218,8 @@ ActiveRecord::Schema.define(version: 20170921115009) do
t.integer "storage_version", limit: 2
t.boolean "resolve_outdated_diff_discussions"
t.boolean "repository_read_only"
+ t.boolean "merge_requests_ff_only_enabled", default: false
+ t.boolean "merge_requests_rebase_enabled", default: false, null: false
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index 40099dcc967..e3b10119090 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -32,6 +32,14 @@ prometheus_listen_addr = "localhost:9236"
Changes to `/home/git/gitaly/config.toml` are applied when you run `service
gitlab restart`.
+## Client-side GRPC logs
+
+Gitaly uses the [gRPC](https://grpc.io/) RPC framework. The Ruby gRPC
+client has its own log file which may contain useful information when
+you are seeing Gitaly errors. You can control the log level of the
+gRPC client with the `GRPC_LOG_LEVEL` environment variable. The
+default level is `WARN`.
+
## Running Gitaly on its own server
> This is an optional way to deploy Gitaly which can benefit GitLab
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index 3587696225c..86b436d89dd 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -142,9 +142,9 @@ and [projects APIs](../api/projects.md).
## Implementation details
When GitLab receives an artifacts archive, an archive metadata file is also
-generated. This metadata file describes all the entries that are located in the
-artifacts archive itself. The metadata file is in a binary format, with
-additional GZIP compression.
+generated by [GitLab Workhorse]. This metadata file describes all the entries
+that are located in the artifacts archive itself.
+The metadata file is in a binary format, with additional GZIP compression.
GitLab does not extract the artifacts archive in order to save space, memory
and disk I/O. It instead inspects the metadata file which contains all the
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index bff8a2d3e4d..63a5dd1445c 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -121,6 +121,15 @@ GET /projects/:id/merge_requests?labels=bug,reproduced
GET /projects/:id/merge_requests?my_reaction_emoji=star
```
+`project_id` represents the ID of the project where the MR resides.
+`project_id` will always equal `target_project_id`.
+
+In the case of a merge request from the same project,
+`source_project_id`, `target_project_id` and `project_id`
+will be the same. In the case of a merge request from a fork,
+`target_project_id` and `project_id` will be the same and
+`source_project_id` will be the fork project's ID.
+
Parameters:
| Attribute | Type | Required | Description |
diff --git a/doc/ci/enable_or_disable_ci.md b/doc/ci/enable_or_disable_ci.md
index 796a025b951..b8f9988e3ef 100644
--- a/doc/ci/enable_or_disable_ci.md
+++ b/doc/ci/enable_or_disable_ci.md
@@ -1,51 +1,46 @@
-## Enable or disable GitLab CI
+## Enable or disable GitLab CI/CD
-_To effectively use GitLab CI, you need a valid [`.gitlab-ci.yml`](yaml/README.md)
+To effectively use GitLab CI/CD, you need a valid [`.gitlab-ci.yml`](yaml/README.md)
file present at the root directory of your project and a
[runner](runners/README.md) properly set up. You can read our
-[quick start guide](quick_start/README.md) to get you started._
+[quick start guide](quick_start/README.md) to get you started.
-If you are using an external CI server like Jenkins or Drone CI, it is advised
-to disable GitLab CI in order to not have any conflicts with the commits status
+If you are using an external CI/CD server like Jenkins or Drone CI, it is advised
+to disable GitLab CI/CD in order to not have any conflicts with the commits status
API.
---
-GitLab CI is exposed via the `/pipelines` and `/builds` pages of a project.
-Disabling GitLab CI in a project does not delete any previous jobs.
-In fact, the `/pipelines` and `/builds` pages can still be accessed, although
+GitLab CI/CD is exposed via the `/pipelines` and `/jobs` pages of a project.
+Disabling GitLab CI/CD in a project does not delete any previous jobs.
+In fact, the `/pipelines` and `/jobs` pages can still be accessed, although
it's hidden from the left sidebar menu.
-GitLab CI is enabled by default on new installations and can be disabled either
+GitLab CI/CD is enabled by default on new installations and can be disabled either
individually under each project's settings, or site-wide by modifying the
settings in `gitlab.yml` and `gitlab.rb` for source and Omnibus installations
respectively.
### Per-project user setting
-The setting to enable or disable GitLab CI can be found with the name **Pipelines**
-under the **Sharing & Permissions** area of a project's settings along with
-**Merge Requests**. Choose one of **Disabled**, **Only team members** and
-**Everyone with access** and hit **Save changes** for the settings to take effect.
+The setting to enable or disable GitLab CI/CD can be found under your project's
+**Settings > General > Permissions**. Choose one of "Disabled", "Only team members"
+or "Everyone with access" and hit **Save changes** for the settings to take effect.
-![Sharing & Permissions settings](img/permissions_settings.png)
+![Sharing & Permissions settings](../user/project/settings/img/sharing_and_permissions_settings.png)
----
-
-### Site-wide administrator setting
+### Site-wide admin setting
-You can disable GitLab CI site-wide, by modifying the settings in `gitlab.yml`
+You can disable GitLab CI/CD site-wide, by modifying the settings in `gitlab.yml`
and `gitlab.rb` for source and Omnibus installations respectively.
Two things to note:
-1. Disabling GitLab CI, will affect only newly-created projects. Projects that
+1. Disabling GitLab CI/CD, will affect only newly-created projects. Projects that
had it enabled prior to this modification, will work as before.
-1. Even if you disable GitLab CI, users will still be able to enable it in the
+1. Even if you disable GitLab CI/CD, users will still be able to enable it in the
project's settings.
----
-
For installations from source, open `gitlab.yml` with your editor and set
`builds` to `false`:
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index acd5682841a..c03e16b1b38 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -26,7 +26,7 @@ so every environment can have one or more deployments. GitLab keeps track of
your deployments, so you always know what is currently being deployed on your
servers. If you have a deployment service such as [Kubernetes][kubernetes-service]
enabled for your project, you can use it to assist with your deployments, and
-can even access a web terminal for your environment from within GitLab!
+can even access a [web terminal](#web-terminals) for your environment from within GitLab!
To better understand how environments and deployments work, let's consider an
example. We assume that you have already created a project in GitLab and set up
@@ -119,7 +119,7 @@ where you can find information of the last deployment status of an environment.
Here's how the Environments page looks so far.
-![Staging environment view](img/environments_available_staging.png)
+![Environment view](img/environments_available.png)
There's a bunch of information there, specifically you can see:
@@ -229,7 +229,7 @@ You can find it in the pipeline, job, environment, and deployment views.
| Pipelines | Single pipeline | Environments | Deployments | jobs |
| --------- | ----------------| ------------ | ----------- | -------|
-| ![Pipelines manual action](img/environments_manual_action_pipelines.png) | ![Pipelines manual action](img/environments_manual_action_single_pipeline.png) | ![Environments manual action](img/environments_manual_action_environments.png) | ![Deployments manual action](img/environments_manual_action_deployments.png) | ![Builds manual action](img/environments_manual_action_builds.png) |
+| ![Pipelines manual action](img/environments_manual_action_pipelines.png) | ![Pipelines manual action](img/environments_manual_action_single_pipeline.png) | ![Environments manual action](img/environments_manual_action_environments.png) | ![Deployments manual action](img/environments_manual_action_deployments.png) | ![Builds manual action](img/environments_manual_action_jobs.png) |
Clicking on the play button in either of these places will trigger the
`deploy_prod` job, and the deployment will be recorded under a new
@@ -402,7 +402,7 @@ places within GitLab.
| In a merge request widget as a link | In the Environments view as a button | In the Deployments view as a button |
| -------------------- | ------------ | ----------- |
-| ![Environment URL in merge request](img/environments_mr_review_app.png) | ![Environment URL in environments](img/environments_link_url.png) | ![Environment URL in deployments](img/environments_link_url_deployments.png) |
+| ![Environment URL in merge request](img/environments_mr_review_app.png) | ![Environment URL in environments](img/environments_available.png) | ![Environment URL in deployments](img/deployments_view.png) |
If a merge request is eventually merged to the default branch (in our case
`master`) and that branch also deploys to an environment (in our case `staging`
@@ -574,7 +574,7 @@ Once configured, GitLab will attempt to retrieve [supported performance metrics]
environment which has had a successful deployment. If monitoring data was
successfully retrieved, a Monitoring button will appear for each environment.
-![Environment Detail with Metrics](img/prometheus_environment_detail_with_metrics.png)
+![Environment Detail with Metrics](img/deployments_view.png)
Clicking on the Monitoring button will display a new page, showing up to the last
8 hours of performance data. It may take a minute or two for data to appear
@@ -593,10 +593,11 @@ Web terminals were added in GitLab 8.15 and are only available to project
masters and owners.
If you deploy to your environments with the help of a deployment service (e.g.,
-the [Kubernetes service][kubernetes-service], GitLab can open
+the [Kubernetes service][kubernetes-service]), GitLab can open
a terminal session to your environment! This is a very powerful feature that
allows you to debug issues without leaving the comfort of your web browser. To
-enable it, just follow the instructions given in the service documentation.
+enable it, just follow the instructions given in the service integration
+documentation.
Once enabled, your environments will gain a "terminal" button:
diff --git a/doc/ci/img/builds_tab.png b/doc/ci/img/builds_tab.png
deleted file mode 100644
index 2d7eec8a949..00000000000
--- a/doc/ci/img/builds_tab.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/img/deployments_view.png b/doc/ci/img/deployments_view.png
index 7ded0c97b72..436fed5f465 100644
--- a/doc/ci/img/deployments_view.png
+++ b/doc/ci/img/deployments_view.png
Binary files differ
diff --git a/doc/ci/img/environments_available.png b/doc/ci/img/environments_available.png
new file mode 100644
index 00000000000..2991a309655
--- /dev/null
+++ b/doc/ci/img/environments_available.png
Binary files differ
diff --git a/doc/ci/img/environments_available_staging.png b/doc/ci/img/environments_available_staging.png
deleted file mode 100644
index 5c031ad0d9d..00000000000
--- a/doc/ci/img/environments_available_staging.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/img/environments_dynamic_groups.png b/doc/ci/img/environments_dynamic_groups.png
index 0f42b368c5b..45124b3d8d8 100644
--- a/doc/ci/img/environments_dynamic_groups.png
+++ b/doc/ci/img/environments_dynamic_groups.png
Binary files differ
diff --git a/doc/ci/img/environments_link_url.png b/doc/ci/img/environments_link_url.png
deleted file mode 100644
index 44010f6aa6f..00000000000
--- a/doc/ci/img/environments_link_url.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/img/environments_link_url_deployments.png b/doc/ci/img/environments_link_url_deployments.png
deleted file mode 100644
index 4f90143527a..00000000000
--- a/doc/ci/img/environments_link_url_deployments.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/img/environments_link_url_mr.png b/doc/ci/img/environments_link_url_mr.png
index 64f134e0b0d..7ce46063062 100644
--- a/doc/ci/img/environments_link_url_mr.png
+++ b/doc/ci/img/environments_link_url_mr.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_builds.png b/doc/ci/img/environments_manual_action_builds.png
deleted file mode 100644
index e7cf63a1031..00000000000
--- a/doc/ci/img/environments_manual_action_builds.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_deployments.png b/doc/ci/img/environments_manual_action_deployments.png
index 2b3f6f3edad..93beaa0de54 100644
--- a/doc/ci/img/environments_manual_action_deployments.png
+++ b/doc/ci/img/environments_manual_action_deployments.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_environments.png b/doc/ci/img/environments_manual_action_environments.png
index e0c07604e7f..9490be63f14 100644
--- a/doc/ci/img/environments_manual_action_environments.png
+++ b/doc/ci/img/environments_manual_action_environments.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_jobs.png b/doc/ci/img/environments_manual_action_jobs.png
new file mode 100644
index 00000000000..9ae223cf77f
--- /dev/null
+++ b/doc/ci/img/environments_manual_action_jobs.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_pipelines.png b/doc/ci/img/environments_manual_action_pipelines.png
index 82bbae88027..129e44f6fb0 100644
--- a/doc/ci/img/environments_manual_action_pipelines.png
+++ b/doc/ci/img/environments_manual_action_pipelines.png
Binary files differ
diff --git a/doc/ci/img/environments_manual_action_single_pipeline.png b/doc/ci/img/environments_manual_action_single_pipeline.png
index 36337cb1870..1eeb4379eb7 100644
--- a/doc/ci/img/environments_manual_action_single_pipeline.png
+++ b/doc/ci/img/environments_manual_action_single_pipeline.png
Binary files differ
diff --git a/doc/ci/img/environments_mr_review_app.png b/doc/ci/img/environments_mr_review_app.png
index 7bff84362a3..4bb643d708f 100644
--- a/doc/ci/img/environments_mr_review_app.png
+++ b/doc/ci/img/environments_mr_review_app.png
Binary files differ
diff --git a/doc/ci/img/environments_terminal_button_on_index.png b/doc/ci/img/environments_terminal_button_on_index.png
index 6f05b2aa343..061bb7c3c87 100644
--- a/doc/ci/img/environments_terminal_button_on_index.png
+++ b/doc/ci/img/environments_terminal_button_on_index.png
Binary files differ
diff --git a/doc/ci/img/environments_terminal_button_on_show.png b/doc/ci/img/environments_terminal_button_on_show.png
index 9469fab99ab..4d24304bc93 100644
--- a/doc/ci/img/environments_terminal_button_on_show.png
+++ b/doc/ci/img/environments_terminal_button_on_show.png
Binary files differ
diff --git a/doc/ci/img/environments_view.png b/doc/ci/img/environments_view.png
deleted file mode 100644
index 821352188ef..00000000000
--- a/doc/ci/img/environments_view.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/img/permissions_settings.png b/doc/ci/img/permissions_settings.png
deleted file mode 100644
index 1454c75fd24..00000000000
--- a/doc/ci/img/permissions_settings.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/img/prometheus_environment_detail_with_metrics.png b/doc/ci/img/prometheus_environment_detail_with_metrics.png
deleted file mode 100644
index 214b10624a9..00000000000
--- a/doc/ci/img/prometheus_environment_detail_with_metrics.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index ebcb92b5db1..17839cbaef1 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -149,14 +149,15 @@ script:
## Secret variables
->**Notes:**
-- This feature requires GitLab Runner 0.4.0 or higher.
-- Group-level secret variables added in GitLab 9.4.
-- Be aware that secret variables are not masked, and their values can be shown
- in the job logs if explicitly asked to do so. If your project is public or
- internal, you can set the pipelines private from your project's Pipelines
- settings. Follow the discussion in issue [#13784][ce-13784] for masking the
- secret variables.
+NOTE: **Note:**
+Group-level secret variables were added in GitLab 9.4.
+
+CAUTION: **Important:**
+Be aware that secret variables are not masked, and their values can be shown
+in the job logs if explicitly asked to do so. If your project is public or
+internal, you can set the pipelines private from your [project's Pipelines
+settings](../../user/project/pipelines/settings.md#visibility-of-pipelines).
+Follow the discussion in issue [#13784][ce-13784] for masking the secret variables.
GitLab CI allows you to define per-project or per-group secret variables
that are set in the pipeline environment. The secret variables are stored out of
@@ -171,6 +172,8 @@ Likewise, group-level secret variables can be added by going to your group's
**Settings > CI/CD**, then finding the section called **Secret variables**.
Any variables of [subgroups] will be inherited recursively.
+![Secret variables](img/secret_variables.png)
+
Once you set them, they will be available for all subsequent pipelines. You can also
[protect your variables](#protected-secret-variables).
@@ -202,7 +205,7 @@ are set in the build environment. These variables are only defined for
the project services that you are using to learn which variables they define.
An example project service that defines deployment variables is
-[Kubernetes Service](../../user/project/integrations/kubernetes.md).
+[Kubernetes Service](../../user/project/integrations/kubernetes.md#deployment-variables).
## Debug tracing
@@ -439,7 +442,7 @@ export CI_REGISTRY_USER="gitlab-ci-token"
export CI_REGISTRY_PASSWORD="longalfanumstring"
```
-[ce-13784]: https://gitlab.com/gitlab-org/gitlab-ce/issues/13784
+[ce-13784]: https://gitlab.com/gitlab-org/gitlab-ce/issues/13784 "Simple protection of CI secret variables"
[eep]: https://about.gitlab.com/gitlab-ee/ "Available only in GitLab Enterprise Edition Premium"
[envs]: ../environments.md
[protected branches]: ../../user/project/protected_branches.md
diff --git a/doc/ci/variables/img/secret_variables.png b/doc/ci/variables/img/secret_variables.png
new file mode 100644
index 00000000000..f70935069d9
--- /dev/null
+++ b/doc/ci/variables/img/secret_variables.png
Binary files differ
diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md
index c8d23609280..77ae6d2a0ea 100644
--- a/doc/development/fe_guide/style_guide_js.md
+++ b/doc/development/fe_guide/style_guide_js.md
@@ -470,7 +470,25 @@ On those a default key should not be provided.
```
#### Ordering
-1. Order for a Vue Component:
+
+1. Tag order in `.vue` file
+
+ ```
+ <script>
+ // ...
+ </script>
+
+ <template>
+ // ...
+ </template>
+
+ // We don't use scoped styles but there are few instances of this
+ <style>
+ // ...
+ </style>
+ ```
+
+1. Properties in a Vue Component:
1. `name`
1. `props`
1. `mixins`
@@ -490,6 +508,7 @@ On those a default key should not be provided.
1. `beforeDestroy`
1. `destroyed`
+
#### Vue and Bootstrap
1. Tooltips: Do not rely on `has-tooltip` class name for Vue components
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index 2607353782a..277e0cd5f00 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -428,7 +428,7 @@ is a good example of this pattern.
## Style guide
-Please refer to the Vue section of our [style guide](style_guide_js.md#vuejs)
+Please refer to the Vue section of our [style guide](style_guide_js.md#vue-js)
for best practices while writing your Vue components and templates.
## Testing Vue Components
diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md
index f0be3a6b141..e41d258bec6 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -12,6 +12,7 @@ status of the migration.
Gitaly makes heavy use of [feature flags](feature_flags.md).
Each Rugged-to-Gitaly migration goes through a [series of phases](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/MIGRATION_PROCESS.md):
+
* **Opt-In**: by default the Rugged implementation is used.
* Production instances can choose to enable the Gitaly endpoint by enabling the feature flag.
* For testing purposes, you may wish to enable all feature flags by default. This can be done by exporting the following
@@ -19,7 +20,7 @@ Each Rugged-to-Gitaly migration goes through a [series of phases](https://gitlab
* On developer instances (ie, when `Rails.env.development?` is true), the Gitaly endpoint
is enabled by default, but can be _disabled_ using feature flags.
* **Opt-Out**: by default, the Gitaly endpoint is used, but the feature can be explicitly disabled using the feature flag.
-* **Madatory**: The migration is complete and cannot be disabled. The old codepath is removed.
+* **Mandatory**: The migration is complete and cannot be disabled. The old codepath is removed.
### Enabling and Disabling Feature
@@ -49,6 +50,35 @@ If your test-suite is failing with Gitaly issues, as a first step, try running:
rm -rf tmp/tests/gitaly
```
+## `TooManyInvocationsError` errors
+
+During development and testing, you may experience `Gitlab::GitalyClient::TooManyInvocationsError` failures.
+The `GitalyClient` will attempt to block against potential n+1 issues by raising this error
+when Gitaly is called more than 30 times in a single Rails request or Sidekiq execution.
+
+As a temporary measure, export `GITALY_DISABLE_REQUEST_LIMITS=1` to suppress the error. This will disable the n+1 detection
+in your development environment.
+
+Please raise an issue in the GitLab CE or EE repositories to report the issue. Include the labels ~Gitaly
+~performance ~"technical debt". Please ensure that the issue contains the full stack trace and error message of the
+`TooManyInvocationsError`. Also include any known failing tests if possible.
+
+Isolate the source of the n+1 problem. This will normally be a loop that results in Gitaly being called for each
+element in an array. If you are unable to isolate the problem, please contact a member
+of the [Gitaly Team](https://gitlab.com/groups/gl-gitaly/group_members) for assistance.
+
+Once the source has been found, wrap it in an `allow_n_plus_1_calls` block, as follows:
+
+```ruby
+# n+1: link to n+1 issue
+Gitlab::GitalyClient.allow_n_plus_1_calls do
+ # original code
+ commits.each { |commit| ... }
+end
+```
+
+Once the code is wrapped in this block, this code-path will be excluded from n+1 detection.
+
---
[Return to Development documentation](README.md)
diff --git a/doc/development/i18n_guide.md b/doc/development/i18n_guide.md
index bd0ef39ca62..29c8941a8f7 100644
--- a/doc/development/i18n_guide.md
+++ b/doc/development/i18n_guide.md
@@ -183,13 +183,20 @@ aren't in the message with id `1 pipeline`.
### Interpolation
-- In Ruby/HAML:
+- In Ruby/HAML (see [sprintf]):
```ruby
_("Hello %{name}") % { name: 'Joe' }
```
-- In JavaScript: Not supported at this moment.
+- In JavaScript: Only named parameters are supported (see also [#37992]):
+
+ ```javascript
+ __("Hello %{name}") % { name: 'Joe' }
+ ```
+
+[sprintf]: http://ruby-doc.org/core/Kernel.html#method-i-sprintf
+[#37992]: https://gitlab.com/gitlab-org/gitlab-ce/issues/37992
### Plurals
diff --git a/doc/development/testing.md b/doc/development/testing.md
index d856b003353..4d5b90de6fc 100644
--- a/doc/development/testing.md
+++ b/doc/development/testing.md
@@ -302,7 +302,7 @@ range of inputs, might look like this:
```ruby
describe "#==" do
- using Rspec::Parameterized::TableSyntax
+ using RSpec::Parameterized::TableSyntax
let(:project1) { create(:project) }
let(:project2) { create(:project) }
diff --git a/doc/development/ux_guide/animation.md b/doc/development/ux_guide/animation.md
index 5dae4bcc905..d190ee1b0ff 100644
--- a/doc/development/ux_guide/animation.md
+++ b/doc/development/ux_guide/animation.md
@@ -39,6 +39,12 @@ When information is updating in place, a quick, subtle animation is needed. The
![Quick update animation](img/animation-quickupdate.gif)
+### Skeleton loading
+
+Skeleton loading is explained in the [component section](components.html#skeleton-loading) of the UX guide. It includes a horizontally pulsating animation that shows motion as if it's growing. It's timing is a slower `linear 1s`.
+
+![Skeleton loading animation](img/skeleton-loading.gif)
+
### Moving transitions
When elements move on screen, there should be a quick animation so it is clear to users what moved where. The timing of this animation differs based on the amount of movement and change. Consider animations between `200ms` and `400ms`.
@@ -51,7 +57,9 @@ View the [interactive example](http://codepen.io/awhildy/full/ALyKPE/) here.
![Reorder animation](img/animation-reorder.gif)
#### Autoscroll the page
+
Another example of a moving transition is when you have to autoscroll the page to keep an active element visible.
View the [interactive example](http://codepen.io/awhildy/full/PbxgVo/) here.
-![Autoscroll animation](img/animation-autoscroll.gif) \ No newline at end of file
+
+![Autoscroll animation](img/animation-autoscroll.gif)
diff --git a/doc/development/ux_guide/components.md b/doc/development/ux_guide/components.md
index ac7c1b6207d..986b796437b 100644
--- a/doc/development/ux_guide/components.md
+++ b/doc/development/ux_guide/components.md
@@ -204,6 +204,25 @@ Cover blocks are generally used to create a heading element for a page, such as
---
+## Skeleton loading
+
+Skeleton loading is a way to convey to the user what kind of content is currently being loaded. It's a paradigm with which content can independently and asynchronously be loaded, while still adhering to the structure and look of the completely loaded view.
+
+### Requirements
+
+* A skeleton should represent an organism in a recognisable way
+* Atom elements within organisms (for reference see this article on [atomic design methodology](http://atomicdesign.bradfrost.com/chapter-2/)) may be represented in a maximum of 3 repetitions, if applicable.
+* Skeletons should only be presented in grayscale using the HEX colors: `#fafafa` or `#ffffff` (except for shadows)
+* Animate the grey atoms in a pulsating way to show motion, as if "loading". The pulse animation transitions colors horizontally from left to right, starting with `#f2f2f2` to `#fafafa`.
+
+![Skeleton loading animation](img/skeleton-loading.gif)
+
+### Usage
+
+Skeleton loading can replace any existing UI elements for the period in which they are loaded and should aim for maintaining a similar structure visually.
+
+---
+
## Panels
> TODO: Catalog how we are currently using panels and rationalize how they relate to alerts
diff --git a/doc/development/ux_guide/illustrations.md b/doc/development/ux_guide/illustrations.md
new file mode 100644
index 00000000000..7e16c300921
--- /dev/null
+++ b/doc/development/ux_guide/illustrations.md
@@ -0,0 +1,86 @@
+# Illustrations
+
+The illustrations should always align with topics and goals in specific context.
+
+## Principles
+
+#### Be simple.
+- For clarity, we use simple and specific elements to create our illustrations.
+
+#### Be optimistic.
+- We are an open-minded, optimistic, and friendly team. We should reflect those values in our illustrations to connect with our brand experience.
+
+#### Be gentle.
+- Our illustrations assist users in understanding context and guide users in the right direction. Illustrations are supportive, so they should be obvious but not aggressive.
+
+
+## Style
+
+#### Shapes
+- All illustrations are geometric rather than organic.
+- The illustrations are made by circles, rectangles, squares, and triangles.
+
+<img src="img/illustrations-geometric.png" width=224px alt="Example for geometric" />
+
+#### Stroke
+- Standard border thickness: **4px**
+- Depending on the situation, border thickness can be changed to **3px**. For example, when the illustration size is small, an illustration with 4px border thickness would look tight. In this case, the border thickness can be changed to 3px.
+- We use **rounded caps** and **rounded corner**.
+
+| Do | Don't |
+| -------- | -------- |
+| <img src="img/illustrations-caps-do.png" width= 133px alt="Do: caps and corner" /> | <img src="img/illustrations-caps-don't.png" width= 133px alt="Don't: caps and corner"/> |
+
+#### Radius
+- Standard corner radius: **10px**
+- Depending on the situation, corner radius can be changed to **5px**. For example, when the illustration size is small, an illustration with 10px corner radius would be over-rounded. In this case, the corner radius can be changed to 5px.
+
+<img src="img/illustrations-border-radius.png" width= 464px alt="Example for border radius"/>
+
+#### Size
+Depends on the situation, the illustration size can be the 3 types below:
+
+**Large**
+* Use case: Empty states, error pages(e.g. 404, 403)
+* For vertical layout, the illustration should not larger than **430*300 px**.
+* For horizontal layout, the illustration should not larger than **430*380 px**.
+
+| Vertical layout | Horizontal layout |
+| --------------- | ----------------- |
+| <img src="img/illustration-size-large-vertical.png" /> | <img src="img/illustration-size-large-horizontal.png" />
+
+**Medium**
+* Use case: Banner
+* The illustration should not larger than **240*160 px**
+* The illustration should keep simple and clear. We recommend not including too many elements in the medium size illustration.
+
+<img src="img/illustration-size-medium.png" width=983px />
+
+**Small**
+* Use case: Graphics for explanatory text, graphics for status.
+* The illustration should not larger than **160*90 px**.
+* The illustration should keep simple and clear. We recommend not including too many elements in the small size illustration.
+
+<img src="img/illustration-size-small.png" width=983px />
+
+**Illustration on mobile**
+- Keep the proportions in original ratio.
+
+#### Colors palette
+
+For consistency, we recommend choosing colors from our color palette.
+
+| Orange | Purple | Grey |
+| -------- | -------- | -------- |
+| <img src="img/illustrations-color-orange.png" width= 160px alt="Orange" /> | <img src="img/illustrations-color-purple.png" width= 160px alt="Purple" /> | <img src="img/illustrations-color-grey.png" width= 160px alt="Grey" /> |
+| #FC6D26 | #6B4FBB | #EEEEEE |
+
+#### Don't
+- Don't include the typography in the illustration.
+- Don't include tanuki in the illustration. If necessary, we recommend having tanuki monochromatic.
+
+---
+
+| Orange | Purple |
+| -------- | -------- |
+| <img src="img/illustrations-palette-oragne.png" width= 160px alt="Palette - Orange" /> | <img src="img/illustrations-palette-purple.png" width= 160px alt="Palette - Purple" /> |
diff --git a/doc/development/ux_guide/img/illustration-size-large-horizontal.png b/doc/development/ux_guide/img/illustration-size-large-horizontal.png
new file mode 100755
index 00000000000..8aa835adccc
--- /dev/null
+++ b/doc/development/ux_guide/img/illustration-size-large-horizontal.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustration-size-large-vertical.png b/doc/development/ux_guide/img/illustration-size-large-vertical.png
new file mode 100644
index 00000000000..813b6a065e5
--- /dev/null
+++ b/doc/development/ux_guide/img/illustration-size-large-vertical.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustration-size-medium.png b/doc/development/ux_guide/img/illustration-size-medium.png
new file mode 100755
index 00000000000..55cfe1dcb91
--- /dev/null
+++ b/doc/development/ux_guide/img/illustration-size-medium.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustration-size-small.png b/doc/development/ux_guide/img/illustration-size-small.png
new file mode 100644
index 00000000000..0124f58f48e
--- /dev/null
+++ b/doc/development/ux_guide/img/illustration-size-small.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-border-radius.png b/doc/development/ux_guide/img/illustrations-border-radius.png
new file mode 100755
index 00000000000..4e2fef5c7f5
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-border-radius.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-caps-do.png b/doc/development/ux_guide/img/illustrations-caps-do.png
new file mode 100755
index 00000000000..7a2c74382f6
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-caps-do.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-caps-don't.png b/doc/development/ux_guide/img/illustrations-caps-don't.png
new file mode 100755
index 00000000000..848f72dbe30
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-caps-don't.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-color-grey.png b/doc/development/ux_guide/img/illustrations-color-grey.png
new file mode 100755
index 00000000000..63855026c2b
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-color-grey.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-color-orange.png b/doc/development/ux_guide/img/illustrations-color-orange.png
new file mode 100755
index 00000000000..96765c8c28c
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-color-orange.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-color-purple.png b/doc/development/ux_guide/img/illustrations-color-purple.png
new file mode 100755
index 00000000000..745d2c853ba
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-color-purple.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-geometric.png b/doc/development/ux_guide/img/illustrations-geometric.png
new file mode 100755
index 00000000000..33f05547bac
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-geometric.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-palette-oragne.png b/doc/development/ux_guide/img/illustrations-palette-oragne.png
new file mode 100755
index 00000000000..15f35912646
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-palette-oragne.png
Binary files differ
diff --git a/doc/development/ux_guide/img/illustrations-palette-purple.png b/doc/development/ux_guide/img/illustrations-palette-purple.png
new file mode 100755
index 00000000000..e0f5839705e
--- /dev/null
+++ b/doc/development/ux_guide/img/illustrations-palette-purple.png
Binary files differ
diff --git a/doc/development/ux_guide/img/skeleton-loading.gif b/doc/development/ux_guide/img/skeleton-loading.gif
new file mode 100644
index 00000000000..5877139171d
--- /dev/null
+++ b/doc/development/ux_guide/img/skeleton-loading.gif
Binary files differ
diff --git a/doc/development/ux_guide/index.md b/doc/development/ux_guide/index.md
index 8a849f239dc..42bcf234e12 100644
--- a/doc/development/ux_guide/index.md
+++ b/doc/development/ux_guide/index.md
@@ -21,6 +21,11 @@ Guidance on the timing, curving and motion for GitLab.
---
+### [Illustrations](illustrations.md)
+Guidelines for principals and styles related to illustrations for GitLab.
+
+---
+
### [Copy](copy.md)
Conventions on text and messaging within labels, buttons, and other components.
diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md
index 177124c8291..ddfd47df099 100644
--- a/doc/install/kubernetes/gitlab_chart.md
+++ b/doc/install/kubernetes/gitlab_chart.md
@@ -1,8 +1,13 @@
# GitLab Helm Chart
> **Note**:
-* This chart will be replaced by the [gitlab-omnibus](gitlab_omnibus.md) chart, once it supports [additional configuration options](https://gitlab.com/charts/charts.gitlab.io/issues/68).
+* This chart will be replaced by the [gitlab-omnibus](gitlab_omnibus.md) chart, once it supports [additional configuration options](https://gitlab.com/charts/charts.gitlab.io/issues/68). For more information on available charts, please see our [overview](index.md#chart-overview).
* These charts have been tested on Google Container Engine and Azure Container Service. Other Kubernetes installations may work as well, if not please [open an issue](https://gitlab.com/charts/charts.gitlab.io/issues).
+
+For more information on available GitLab Helm Charts, please see our [overview](index.md#chart-overview).
+
+## Introduction
+
The `gitlab` Helm chart deploys just GitLab into your Kubernetes cluster, and offers extensive configuration options. This chart requires advanced knowledge of Kubernetes to successfully use. For most deployments we **strongly recommended** the [gitlab-omnibus](gitlab_omnibus.md) chart, which will replace this chart once it supports [additional configuration options](https://gitlab.com/charts/charts.gitlab.io/issues/68). Due to the difficulty in supporting upgrades to the `omnibus-gitlab` chart, migrating will require exporting data out of this instance and importing it into the new deployment.
This chart includes the following:
@@ -15,8 +20,6 @@ This chart includes the following:
- Optional PostgreSQL deployment using the [PostgreSQL Chart](https://github.com/kubernetes/charts/tree/master/stable/postgresql) (defaults to enabled)
- Optional Ingress (defaults to disabled)
-For more information on available GitLab Helm Charts, please see our [overview](index.md#chart-overview).
-
## Prerequisites
- _At least_ 3 GB of RAM available on your cluster. 41GB of storage and 2 CPU are also required.
diff --git a/doc/install/kubernetes/index.md b/doc/install/kubernetes/index.md
index 467d5b92e0c..aed00ae9e2c 100644
--- a/doc/install/kubernetes/index.md
+++ b/doc/install/kubernetes/index.md
@@ -9,12 +9,12 @@ should be deployed, upgraded, and configured.
## Chart Overview
-* **[GitLab-Omnibus](#gitlab-omnibus-chart-recommended)**: The best way to run GitLab on Kubernetes today. It is suited for small to medium deployments, and is in beta while support for backups and other features are added.
-* **[Upcoming Cloud Native Charts](#upcoming-cloud-native-helm-charts)**: The next generation of charts, currently in development. Will support large deployments, with horizontal scaling of individual GitLab components.
+* **[GitLab-Omnibus](gitlab_omnibus.md)**: The best way to run GitLab on Kubernetes today. It is suited for small to medium deployments, and is in beta while support for backups and other features are added.
+* **[Cloud Native GitLab Chart](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md)**: The next generation GitLab chart, currently in development. Will support large deployments with horizontal scaling of individual GitLab components.
* Other Charts
- * [GitLab Runner Chart](#gitlab-runner-chart): For deploying just the GitLab Runner.
- * [Advanced GitLab Installation](#advanced-gitlab-installation): Provides additional deployment options, but provides less functionality out-of-the-box. It's beta, no longer actively developed, and will be deprecated by [gitlab-omnibus](#gitlab-omnibus-chart-recommended) once it supports these options.
- * [Community Contributed Charts](#community-contributed-charts): Community contributed charts, deprecated by the official GitLab charts.
+ * [GitLab Runner Chart](gitlab_runner_chart.md): For deploying just the GitLab Runner.
+ * [Advanced GitLab Installation](gitlab_chart.md): Provides additional deployment options, but provides less functionality out-of-the-box. It's beta, no longer actively developed, and will be deprecated by [gitlab-omnibus](#gitlab-omnibus-chart-recommended) once it supports these options.
+ * [Community Contributed Charts](#community-contributed-charts): Community contributed charts, deprecated by the official GitLab chart.
## GitLab-Omnibus Chart (Recommended)
> **Note**: This chart is in beta while [additional features](https://gitlab.com/charts/charts.gitlab.io/issues/68) are being added.
@@ -25,9 +25,9 @@ Once the [cloud native charts](#upcoming-cloud-native-helm-charts) are ready for
Learn more about the [gitlab-omnibus chart.](gitlab_omnibus.md)
-## Upcoming Cloud Native Charts
+## Cloud Native GitLab Chart
-GitLab is working towards building a [cloud native deployment method](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md). A key part of this effort is to isolate each service into its [own Docker container and Helm chart](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2420), rather than utilizing the all-in-one container image of the [current charts](#official-gitlab-helm-charts-recommended).
+GitLab is working towards building a [cloud native GitLab chart](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md). A key part of this effort is to isolate each service into its [own Docker container and Helm chart](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2420), rather than utilizing the all-in-one container image of the [current charts](#official-gitlab-helm-charts-recommended).
By offering individual containers and charts, we will be able to provide a number of benefits:
* Easier horizontal scaling of each service,
@@ -37,6 +37,8 @@ By offering individual containers and charts, we will be able to provide a numbe
This is a large project and will be worked on over the span of multiple releases. For the most up-to-date status and release information, please see our [tracking issue](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2420). We do not expect these to be production ready before the second half of 2018.
+Learn more about the [cloud native GitLab chart.](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md)
+
## Other Charts
### GitLab Runner Chart
@@ -55,7 +57,7 @@ Learn more about the [gitlab chart.](gitlab_chart.md)
### Community Contributed Charts
-The community has also [contributed GitLab charts](https://github.com/kubernetes/charts/tree/master/stable/gitlab-ce) to the [Helm Stable Repository](https://github.com/kubernetes/charts#repository-structure). These charts should be considered [deprecated](https://github.com/kubernetes/charts/issues/1138) in favor of the [official Charts](#official-gitlab-helm-charts-recommended).
+The community has also contributed GitLab [CE](https://github.com/kubernetes/charts/tree/master/stable/gitlab-ce) and [EE](https://github.com/kubernetes/charts/tree/master/stable/gitlab-ee) charts to the [Helm Stable Repository](https://github.com/kubernetes/charts#repository-structure). These charts should be considered [deprecated](https://github.com/kubernetes/charts/issues/1138) in favor of the [official Charts](gitlab_omnibus.md).
[chart]: https://github.com/kubernetes/charts
[helm]: https://github.com/kubernetes/helm/blob/master/README.md
diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md
index fac91935a45..597c98fbf6b 100644
--- a/doc/topics/authentication/index.md
+++ b/doc/topics/authentication/index.md
@@ -11,6 +11,7 @@ This page gathers all the resources for the topic **Authentication** within GitL
- [Security Webcast with Yubico](https://about.gitlab.com/2016/08/31/gitlab-and-yubico-security-webcast/)
- **Integrations:**
- [GitLab as OAuth2 authentication service provider](../../integration/oauth_provider.md#introduction-to-oauth)
+ - [GitLab as OpenID Connect identity provider](../../integration/openid_connect_provider.md)
## GitLab administrators
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 0b7c11ea700..5561784ed0b 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -511,7 +511,7 @@ sudo gitlab-rails console
Then run:
```ruby
-Feature.get(:auto_devops_banner_disabled).disable
+Feature.get(:auto_devops_banner_disabled).enable
```
Or through the HTTP API with an admin access token:
diff --git a/doc/user/admin_area/monitoring/health_check.md b/doc/user/admin_area/monitoring/health_check.md
index 70934f9960a..843fb4ce26b 100644
--- a/doc/user/admin_area/monitoring/health_check.md
+++ b/doc/user/admin_area/monitoring/health_check.md
@@ -18,7 +18,7 @@ traffic until the system is ready or restart the container as needed.
To access monitoring resources, the client IP needs to be included in a whitelist.
-[Read how to add IPs to a whitelist for the monitoring endpoints.][admin].
+[Read how to add IPs to a whitelist for the monitoring endpoints][admin].
## Using the endpoint
diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md
index 5c615daf464..2c4dfcff4a6 100644
--- a/doc/user/project/container_registry.md
+++ b/doc/user/project/container_registry.md
@@ -17,25 +17,25 @@ have its own space to store its Docker images.
You can read more about Docker Registry at https://docs.docker.com/registry/introduction/.
----
-
## Enable the Container Registry for your project
+NOTE: **Note:**
+If you cannot find the Container Registry entry under your project's settings,
+that means that it is not enabled in your GitLab instance. Ask your administrator
+to enable it.
+
1. First, ask your system administrator to enable GitLab Container Registry
following the [administration documentation](../../administration/container_registry.md).
If you are using GitLab.com, this is enabled by default so you can start using
the Registry immediately.
-
-1. Go to your project's settings and enable the **Container Registry** feature
- on your project. For new projects this might be enabled by default. For
- existing projects (prior GitLab 8.8), you will have to explicitly enable it.
-
- ![Enable Container Registry](img/container_registry_enable.png)
-
+1. Go to your [project's General settings](settings/index.md#sharing-and-permissions)
+ and enable the **Container Registry** feature on your project. For new
+ projects this might be enabled by default. For existing projects
+ (prior GitLab 8.8), you will have to explicitly enable it.
1. Hit **Save changes** for the changes to take effect. You should now be able
- to see the **Registry** link in the project menu.
+ to see the **Registry** link in the sidebar.
- ![Container Registry tab](img/container_registry_tab.png)
+![Container Registry](img/container_registry.png)
## Build and push images
diff --git a/doc/user/project/img/container_registry.png b/doc/user/project/img/container_registry.png
new file mode 100644
index 00000000000..abbaf838538
--- /dev/null
+++ b/doc/user/project/img/container_registry.png
Binary files differ
diff --git a/doc/user/project/img/container_registry_enable.png b/doc/user/project/img/container_registry_enable.png
deleted file mode 100644
index d067a8be1ca..00000000000
--- a/doc/user/project/img/container_registry_enable.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/container_registry_tab.png b/doc/user/project/img/container_registry_tab.png
deleted file mode 100644
index a85237271d9..00000000000
--- a/doc/user/project/img/container_registry_tab.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/issue_board.png b/doc/user/project/img/issue_board.png
index cf7f519f783..5f6dc9e4e8b 100644
--- a/doc/user/project/img/issue_board.png
+++ b/doc/user/project/img/issue_board.png
Binary files differ
diff --git a/doc/user/project/img/issue_board_move_issue_card_list.png b/doc/user/project/img/issue_board_move_issue_card_list.png
index c6b17ada40e..3666dbb87ab 100644
--- a/doc/user/project/img/issue_board_move_issue_card_list.png
+++ b/doc/user/project/img/issue_board_move_issue_card_list.png
Binary files differ
diff --git a/doc/user/project/img/labels_assign_label_in_new_issue.png b/doc/user/project/img/labels_assign_label_in_new_issue.png
deleted file mode 100644
index badfbed0bbe..00000000000
--- a/doc/user/project/img/labels_assign_label_in_new_issue.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_default.png b/doc/user/project/img/labels_default.png
index 474953d565b..7934e3bfb5e 100644
--- a/doc/user/project/img/labels_default.png
+++ b/doc/user/project/img/labels_default.png
Binary files differ
diff --git a/doc/user/project/img/labels_filter.png b/doc/user/project/img/labels_filter.png
index 3aca77f0070..6a1ebfc2ecb 100644
--- a/doc/user/project/img/labels_filter.png
+++ b/doc/user/project/img/labels_filter.png
Binary files differ
diff --git a/doc/user/project/img/labels_filter_by_priority.png b/doc/user/project/img/labels_filter_by_priority.png
index 5609a1f6d7f..419e555e709 100644
--- a/doc/user/project/img/labels_filter_by_priority.png
+++ b/doc/user/project/img/labels_filter_by_priority.png
Binary files differ
diff --git a/doc/user/project/img/labels_new_label.png b/doc/user/project/img/labels_new_label.png
index b44b4bd296d..e26425d0188 100644
--- a/doc/user/project/img/labels_new_label.png
+++ b/doc/user/project/img/labels_new_label.png
Binary files differ
diff --git a/doc/user/project/img/labels_prioritize.png b/doc/user/project/img/labels_prioritize.png
index 3e888f36364..d602a3c90ec 100644
--- a/doc/user/project/img/labels_prioritize.png
+++ b/doc/user/project/img/labels_prioritize.png
Binary files differ
diff --git a/doc/user/project/img/project_repository_settings.png b/doc/user/project/img/project_repository_settings.png
index 1aa7efc36f1..aa4d4452c87 100644
--- a/doc/user/project/img/project_repository_settings.png
+++ b/doc/user/project/img/project_repository_settings.png
Binary files differ
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index e2cc67726e0..96a5a23ee13 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -12,6 +12,8 @@ Other interesting links:
- [GitLab Issue Board landing page on about.gitlab.com][landing]
- [YouTube video introduction to Issue Boards][youtube]
+![GitLab Issue Board](img/issue_board.png)
+
## Overview
The Issue Board builds on GitLab's existing
@@ -89,10 +91,6 @@ two defaults:
- **Backlog** (default): shows all open issues that does not belong to one of lists. Always appears on the very left.
- **Closed** (default): shows all closed issues. Always appears on the very right.
-![GitLab Issue Board](img/issue_board.png)
-
----
-
In short, here's a list of actions you can take in an Issue Board:
- [Create a new list](#creating-a-new-list).
diff --git a/doc/user/project/issues/img/button_close_issue.png b/doc/user/project/issues/img/button_close_issue.png
index 8fb2e23f58a..05d257ce9bf 100644
--- a/doc/user/project/issues/img/button_close_issue.png
+++ b/doc/user/project/issues/img/button_close_issue.png
Binary files differ
diff --git a/doc/user/project/issues/img/group_issues_list_view.png b/doc/user/project/issues/img/group_issues_list_view.png
index 5d20e8cbc89..bba964076d0 100644
--- a/doc/user/project/issues/img/group_issues_list_view.png
+++ b/doc/user/project/issues/img/group_issues_list_view.png
Binary files differ
diff --git a/doc/user/project/issues/img/issue_board.png b/doc/user/project/issues/img/issue_board.png
index 1759b28a9ef..87b1016cc76 100644
--- a/doc/user/project/issues/img/issue_board.png
+++ b/doc/user/project/issues/img/issue_board.png
Binary files differ
diff --git a/doc/user/project/issues/img/issue_template.png b/doc/user/project/issues/img/issue_template.png
index c63229a4af2..0e4c8df897b 100644
--- a/doc/user/project/issues/img/issue_template.png
+++ b/doc/user/project/issues/img/issue_template.png
Binary files differ
diff --git a/doc/user/project/issues/img/issues_main_view.png b/doc/user/project/issues/img/issues_main_view.png
index 4faa42e40ee..a929916c682 100644
--- a/doc/user/project/issues/img/issues_main_view.png
+++ b/doc/user/project/issues/img/issues_main_view.png
Binary files differ
diff --git a/doc/user/project/issues/img/issues_main_view_numbered.jpg b/doc/user/project/issues/img/issues_main_view_numbered.jpg
index 4b5d7fba459..b4b68476d24 100644
--- a/doc/user/project/issues/img/issues_main_view_numbered.jpg
+++ b/doc/user/project/issues/img/issues_main_view_numbered.jpg
Binary files differ
diff --git a/doc/user/project/issues/img/new_issue.png b/doc/user/project/issues/img/new_issue.png
index e72ac49d6b9..07d65a93070 100644
--- a/doc/user/project/issues/img/new_issue.png
+++ b/doc/user/project/issues/img/new_issue.png
Binary files differ
diff --git a/doc/user/project/issues/img/new_issue_from_issue_board.png b/doc/user/project/issues/img/new_issue_from_issue_board.png
index 9c2b3ff50fa..da892eff0a6 100644
--- a/doc/user/project/issues/img/new_issue_from_issue_board.png
+++ b/doc/user/project/issues/img/new_issue_from_issue_board.png
Binary files differ
diff --git a/doc/user/project/issues/img/new_issue_from_open_issue.png b/doc/user/project/issues/img/new_issue_from_open_issue.png
index 2aed5372830..c6f3f0617ab 100644
--- a/doc/user/project/issues/img/new_issue_from_open_issue.png
+++ b/doc/user/project/issues/img/new_issue_from_open_issue.png
Binary files differ
diff --git a/doc/user/project/issues/img/new_issue_from_projects_dashboard.png b/doc/user/project/issues/img/new_issue_from_projects_dashboard.png
index cddf36b7457..4b9535f6b15 100644
--- a/doc/user/project/issues/img/new_issue_from_projects_dashboard.png
+++ b/doc/user/project/issues/img/new_issue_from_projects_dashboard.png
Binary files differ
diff --git a/doc/user/project/issues/img/new_issue_from_tracker_list.png b/doc/user/project/issues/img/new_issue_from_tracker_list.png
index 7e5413f0b7d..66793cb44fa 100644
--- a/doc/user/project/issues/img/new_issue_from_tracker_list.png
+++ b/doc/user/project/issues/img/new_issue_from_tracker_list.png
Binary files differ
diff --git a/doc/user/project/issues/img/project_issues_list_view.png b/doc/user/project/issues/img/project_issues_list_view.png
index 2fcc9e8d9da..584a81aab8a 100644
--- a/doc/user/project/issues/img/project_issues_list_view.png
+++ b/doc/user/project/issues/img/project_issues_list_view.png
Binary files differ
diff --git a/doc/user/project/issues/img/sidebar_move_issue.png b/doc/user/project/issues/img/sidebar_move_issue.png
index 111f7861364..1e688cec894 100644
--- a/doc/user/project/issues/img/sidebar_move_issue.png
+++ b/doc/user/project/issues/img/sidebar_move_issue.png
Binary files differ
diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md
index 8ec7adad172..21a2e1213ec 100644
--- a/doc/user/project/labels.md
+++ b/doc/user/project/labels.md
@@ -20,8 +20,6 @@ Head over a single project and navigate to **Issues > Labels**.
The first time you visit this page, you'll notice that there are no labels
created yet.
-![Generate new labels](img/labels_generate.png)
-
Creating a new label from scratch is as easy as pressing the **New label**
button. From there on you can choose the name, give it an optional description,
a color and you are set.
@@ -32,21 +30,23 @@ When you are ready press the **Create label** button to create the new label.
---
-## Default Labels
-
-It's possible to populate the labels for your project from a set of predefined labels.
-
-### Generate GitLab's predefined label set
+## Default labels
-![Generate new labels](img/labels_generate.png)
+The very first time you visit the labels area, it's gonna be empty. In that
+case, it's possible to populate the labels for your project from a set of
+predefined labels.
Click the link to 'Generate a default set of labels' and GitLab will
-generate a set of predefined labels for you. There are 8 default generated labels
-in total and you can see them in the screenshot below.
-
-![Default generated labels](img/labels_default.png)
+generate them for you. There are 8 default generated labels in total:
----
+- bug
+- confirmed
+- critical
+- discussion
+- documentation
+- enhancement
+- suggestion
+- support
## Labels Overview
@@ -102,30 +102,25 @@ If you work on a large or popular project, try subscribing only to the labels
that are relevant to you. You’ll notice it’ll be much easier to focus on what’s
important.
-## Create a new label right from the issue tracker
-
-> Introduced in GitLab 8.6.
+## Create a new label when inside an issue
-There are times when you are already in the issue tracker searching for a
+There are times when you are already inside an issue searching to assign a
label, only to realize it doesn't exist. Instead of going to the **Labels**
page and being distracted from your original purpose, you can create new
labels on the fly.
-Select **Create new** from the labels dropdown list, provide a name, pick a
-color and hit **Create**.
+Expand the issue sidebar and select **Create new label** from the labels dropdown
+list. Provide a name, pick a color and hit **Create**. The new label will be
+ready to used right away!
-![Create new label on the fly](img/labels_new_label_on_the_fly_create.png)
![New label on the fly](img/labels_new_label_on_the_fly.png)
## Assigning labels to issues and merge requests
There are generally two ways to assign a label to an issue or merge request.
-You can assign a label when you first create or edit an issue or merge request.
-
-![Assign label in new issue](img/labels_assign_label_in_new_issue.png)
-
----
+The first one is to assign a label when you first create or edit an issue or
+merge request.
The second way is by using the right sidebar when inside an issue or merge
request. Expand it and hit **Edit** in the labels area. Start typing the name
diff --git a/doc/user/project/merge_requests/cherry_pick_changes.md b/doc/user/project/merge_requests/cherry_pick_changes.md
index 64b94d81024..22ef11e4049 100644
--- a/doc/user/project/merge_requests/cherry_pick_changes.md
+++ b/doc/user/project/merge_requests/cherry_pick_changes.md
@@ -2,24 +2,19 @@
> [Introduced][ce-3514] in GitLab 8.7.
----
-
GitLab implements Git's powerful feature to [cherry-pick any commit][git-cherry-pick]
-with introducing a **Cherry-pick** button in Merge Requests and commit details.
+with introducing a **Cherry-pick** button in merge requests and commit details.
-## Cherry-picking a Merge Request
+## Cherry-picking a merge request
-After the Merge Request has been merged, a **Cherry-pick** button will be available
-to cherry-pick the changes introduced by that Merge Request:
+After the merge request has been merged, a **Cherry-pick** button will be available
+to cherry-pick the changes introduced by that merge request.
![Cherry-pick Merge Request](img/cherry_pick_changes_mr.png)
----
-
-You can cherry-pick the changes directly into the selected branch or you can opt to
-create a new Merge Request with the cherry-pick changes:
-
-![Cherry-pick Merge Request modal](img/cherry_pick_changes_mr_modal.png)
+After you click that button, a modal will appear where you can choose to
+cherry-pick the changes directly into the selected branch or you can opt to
+create a new merge request with the cherry-pick changes
## Cherry-picking a Commit
@@ -27,15 +22,9 @@ You can cherry-pick a Commit from the Commit details page:
![Cherry-pick commit](img/cherry_pick_changes_commit.png)
----
-
-Similar to cherry-picking a Merge Request, you can opt to cherry-pick the changes
-directly into the target branch or create a new Merge Request to cherry-pick the
-changes:
-
-![Cherry-pick commit modal](img/cherry_pick_changes_commit_modal.png)
-
----
+Similar to cherry-picking a merge request, you can opt to cherry-pick the changes
+directly into the target branch or create a new merge request to cherry-pick the
+changes.
Please note that when cherry-picking merge commits, the mainline will always be the
first parent. If you want to use a different mainline then you need to do that
diff --git a/doc/user/project/merge_requests/fast_forward_merge.md b/doc/user/project/merge_requests/fast_forward_merge.md
new file mode 100644
index 00000000000..085170d9f03
--- /dev/null
+++ b/doc/user/project/merge_requests/fast_forward_merge.md
@@ -0,0 +1,35 @@
+# Fast-forward merge requests
+
+Retain a linear Git history and a way to accept merge requests without
+creating merge commits.
+
+## Overview
+
+When the fast-forward merge ([`--ff-only`][ffonly]) setting is enabled, no merge
+commits will be created and all merges are fast-forwarded, which means that
+merging is only allowed if the branch could be fast-forwarded.
+
+When a fast-forward merge is not possible, the user must rebase the branch manually.
+
+## Use cases
+
+Sometimes, a workflow policy might mandate a clean commit history without
+merge commits. In such cases, the fast-forward merge is the perfect candidate.
+
+## Enabling fast-forward merges
+
+1. Navigate to your project's **Settings** and search for the 'Merge method'
+1. Select the **Fast-forward merge** option
+1. Hit **Save changes** for the changes to take effect
+
+Now, when you visit the merge request page, you will be able to accept it
+**only if a fast-forward merge is possible**.
+
+![Fast forward merge request](img/ff_merge_mr.png)
+
+If the target branch is ahead of the source branch, you need to rebase the
+source branch locally before you will be able to do a fast-forward merge.
+
+![Fast forward merge rebase locally](img/ff_merge_rebase_locally.png)
+
+[ffonly]: https://git-scm.com/docs/git-merge#git-merge---ff-only
diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png b/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png
index 5ab094ab367..7dc344f8cf6 100644
--- a/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png
+++ b/doc/user/project/merge_requests/img/cherry_pick_changes_commit.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_commit_modal.png b/doc/user/project/merge_requests/img/cherry_pick_changes_commit_modal.png
deleted file mode 100644
index 42dcb9203ec..00000000000
--- a/doc/user/project/merge_requests/img/cherry_pick_changes_commit_modal.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png b/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png
index 71227747182..811b0998f85 100644
--- a/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png
+++ b/doc/user/project/merge_requests/img/cherry_pick_changes_mr.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/cherry_pick_changes_mr_modal.png b/doc/user/project/merge_requests/img/cherry_pick_changes_mr_modal.png
deleted file mode 100644
index 604eb22f51c..00000000000
--- a/doc/user/project/merge_requests/img/cherry_pick_changes_mr_modal.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/commit_compare.png b/doc/user/project/merge_requests/img/commit_compare.png
deleted file mode 100644
index e612a39716e..00000000000
--- a/doc/user/project/merge_requests/img/commit_compare.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/ff_merge_mr.png b/doc/user/project/merge_requests/img/ff_merge_mr.png
new file mode 100644
index 00000000000..241cc990343
--- /dev/null
+++ b/doc/user/project/merge_requests/img/ff_merge_mr.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/ff_merge_rebase_locally.png b/doc/user/project/merge_requests/img/ff_merge_rebase_locally.png
new file mode 100644
index 00000000000..fb412296efc
--- /dev/null
+++ b/doc/user/project/merge_requests/img/ff_merge_rebase_locally.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_request.png b/doc/user/project/merge_requests/img/merge_request.png
new file mode 100644
index 00000000000..f9ca6348953
--- /dev/null
+++ b/doc/user/project/merge_requests/img/merge_request.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png
index 33f5a4a7a02..d7f0535d3c5 100644
--- a/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png
+++ b/doc/user/project/merge_requests/img/merge_when_pipeline_succeeds_enable.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/revert_changes_commit_modal.png b/doc/user/project/merge_requests/img/revert_changes_commit_modal.png
deleted file mode 100644
index ef7b6dae553..00000000000
--- a/doc/user/project/merge_requests/img/revert_changes_commit_modal.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/revert_changes_mr_modal.png b/doc/user/project/merge_requests/img/revert_changes_mr_modal.png
deleted file mode 100644
index f6540c9dd33..00000000000
--- a/doc/user/project/merge_requests/img/revert_changes_mr_modal.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/versions.png b/doc/user/project/merge_requests/img/versions.png
index 33c58d2abff..3883fb4bc1c 100644
--- a/doc/user/project/merge_requests/img/versions.png
+++ b/doc/user/project/merge_requests/img/versions.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/versions_compare.png b/doc/user/project/merge_requests/img/versions_compare.png
index db978ea7b1d..f5bd85dc7c1 100644
--- a/doc/user/project/merge_requests/img/versions_compare.png
+++ b/doc/user/project/merge_requests/img/versions_compare.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/versions_dropdown.png b/doc/user/project/merge_requests/img/versions_dropdown.png
index 889a2d93e6c..cc70a5bf14b 100644
--- a/doc/user/project/merge_requests/img/versions_dropdown.png
+++ b/doc/user/project/merge_requests/img/versions_dropdown.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/wip_blocked_accept_button.png b/doc/user/project/merge_requests/img/wip_blocked_accept_button.png
index 047b0b4620f..0c492aca363 100644
--- a/doc/user/project/merge_requests/img/wip_blocked_accept_button.png
+++ b/doc/user/project/merge_requests/img/wip_blocked_accept_button.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/wip_mark_as_wip.png b/doc/user/project/merge_requests/img/wip_mark_as_wip.png
index 8bd206bc24a..e405879b28a 100644
--- a/doc/user/project/merge_requests/img/wip_mark_as_wip.png
+++ b/doc/user/project/merge_requests/img/wip_mark_as_wip.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/wip_unmark_as_wip.png b/doc/user/project/merge_requests/img/wip_unmark_as_wip.png
index c0bfa6a35a2..d7f8c419945 100644
--- a/doc/user/project/merge_requests/img/wip_unmark_as_wip.png
+++ b/doc/user/project/merge_requests/img/wip_unmark_as_wip.png
Binary files differ
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index 26c6277d33a..6289fcf3c2b 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -3,6 +3,8 @@
Merge requests allow you to exchange changes you made to source code and
collaborate with other people on the same project.
+![Merge request view](img/merge_request.png)
+
## Overview
A Merge Request (**MR**) is the basis of GitLab as a code collaboration
@@ -23,12 +25,14 @@ With GitLab merge requests, you can:
- Organize your issues and merge requests consistently throughout the project with [labels](../../project/labels.md)
- Add a time estimation and the time spent with that merge request with [Time Tracking](../../../workflow/time_tracking.html#time-tracking)
- [Resolve merge conflicts from the UI](#resolve-conflicts)
+- 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
+
With **[GitLab Enterprise Edition][ee]**, you can also:
- View the deployment process across projects with [Multi-Project Pipeline Graphs](https://docs.gitlab.com/ee/ci/multi_project_pipeline_graphs.html#multi-project-pipeline-graphs) (available only in GitLab Enterprise Edition Premium)
- Request [approvals](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html) from your managers (available in GitLab Enterprise Edition Starter)
-- Enable [fast-forward merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/fast_forward_merge.html) (available in GitLab Enterprise Edition Starter)
- [Squash and merge](https://docs.gitlab.com/ee/user/project/merge_requests/squash_and_merge.html) for a cleaner commit history (available in GitLab Enterprise Edition Starter)
- Enable [semi-linear history merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/index.html#semi-linear-history-merge-requests) as another security layer to guarantee the pipeline is passing in the target branch (available in GitLab Enterprise Edition Starter)
- Analise the impact of your changes with [Code Quality reports](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality_diff.html) (available in GitLab Enterprise Edition Starter)
@@ -89,6 +93,22 @@ in a merged merge requests or a commit.
[Learn more about cherry-picking changes.](cherry_pick_changes.md)
+## Semi-linear history merge requests
+
+A merge commit is created for every merge, but the branch is only merged if
+a fast-forward merge is possible. This ensures that if the merge request build
+succeeded, the target branch build will also succeed after merging.
+
+Navigate to a project's settings, select the **Merge commit with semi-linear
+history** option under **Merge Requests: Merge method** and save your changes.
+
+## Fast-forward merge requests
+
+If you prefer a linear Git history and a way to accept merge requests without
+creating merge commits, you can configure this on a per-project basis.
+
+[Read more about fast-forward merge requests.](fast_forward_merge.md)
+
## Merge when pipeline succeeds
When reviewing a merge request that looks ready to merge but still has one or
@@ -254,4 +274,4 @@ git checkout origin/merge-requests/1
```
[protected branches]: ../protected_branches.md
-[ee]: https://about.gitlab.com/gitlab-ee/ "GitLab Enterprise Edition" \ No newline at end of file
+[ee]: https://about.gitlab.com/gitlab-ee/ "GitLab Enterprise Edition"
diff --git a/doc/user/project/merge_requests/revert_changes.md b/doc/user/project/merge_requests/revert_changes.md
index 5ead9f4177f..8cf8a59dbfe 100644
--- a/doc/user/project/merge_requests/revert_changes.md
+++ b/doc/user/project/merge_requests/revert_changes.md
@@ -2,51 +2,39 @@
> [Introduced][ce-1990] in GitLab 8.5.
----
-
GitLab implements Git's powerful feature to [revert any commit][git-revert]
-with introducing a **Revert** button in Merge Requests and commit details.
+with introducing a **Revert** button in merge requests and commit details.
## Reverting a Merge Request
-_**Note:** The **Revert** button will only be available for Merge Requests
-created since GitLab 8.5. However, you can still revert a Merge Request
-by reverting the merge commit from the list of Commits page._
+NOTE: **Note:**
+The **Revert** button will only be available for merge requests
+created since GitLab 8.5. However, you can still revert a merge request
+by reverting the merge commit from the list of Commits page.
After the Merge Request has been merged, a **Revert** button will be available
-to revert the changes introduced by that Merge Request:
-
-![Revert Merge Request](img/revert_changes_mr.png)
-
----
-
-You can revert the changes directly into the selected branch or you can opt to
-create a new Merge Request with the revert changes:
+to revert the changes introduced by that merge request.
-![Revert Merge Request modal](img/revert_changes_mr_modal.png)
+![Revert Merge Request](img/cherry_pick_changes_mr.png)
----
+After you click that button, a modal will appear where you can choose to
+revert the changes directly into the selected branch or you can opt to
+create a new merge request with the revert changes.
-After the Merge Request has been reverted, the **Revert** button will not be
+After the merge request has been reverted, the **Revert** button will not be
available anymore.
## Reverting a Commit
You can revert a Commit from the Commit details page:
-![Revert commit](img/revert_changes_commit.png)
-
----
-
-Similar to reverting a Merge Request, you can opt to revert the changes
-directly into the target branch or create a new Merge Request to revert the
-changes:
-
-![Revert commit modal](img/revert_changes_commit_modal.png)
+![Revert commit](img/cherry_pick_changes_commit.png)
----
+Similar to reverting a merge request, you can opt to revert the changes
+directly into the target branch or create a new merge request to revert the
+changes.
-After the Commit has been reverted, the **Revert** button will not be available
+After the commit has been reverted, the **Revert** button will not be available
anymore.
Please note that when reverting merge commits, the mainline will always be the
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 22c343dc027..a234a647b77 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -23,7 +23,7 @@ Add an [issue description template](../description_templates.md#description-temp
Set up your project's merge request settings:
-- Set up the merge request method (merge commit, [fast-forward merge](https://docs.gitlab.com/ee/user/project/merge_requests/fast_forward_merge.html#fast-forward-merge-requests)). _Fast-forward is available in [GitLab Enterprise Edition Starter](https://about.gitlab.com/gitlab-ee/)._
+- Set up the merge request method (merge commit, [fast-forward merge](../merge_requests/fast_forward_merge.html)).
- Merge request [description templates](../description_templates.md#description-templates).
- Enable [merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html#merge-request-approvals), _available in [GitLab Enterprise Edition Starter](https://about.gitlab.com/gitlab-ee/)_.
- Enable [merge only of pipeline succeeds](../merge_requests/merge_when_pipeline_succeeds.md).
@@ -42,3 +42,11 @@ Learn how to [export a project](import_export.md#importing-the-project) in GitLa
### Advanced settings
Here you can run housekeeping, archive, rename, transfer, or remove a project.
+
+#### Archiving a project
+
+>**Note:** Only Project Owners and Admin users have the permission to archive a project
+
+It's possible to mark a project as archived via the Project Settings. An archived project will be hidden by default in the project listings.
+
+An archived project can be fully restored and will therefore retain it's repository and all associated resources whilst in an archived state.
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 673e08287a3..6b2aba47f54 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -36,6 +36,7 @@
- [Revert changes in the UI](../user/project/merge_requests/revert_changes.md)
- [Merge requests versions](../user/project/merge_requests/versions.md)
- ["Work In Progress" merge requests](../user/project/merge_requests/work_in_progress_merge_requests.md)
+ - [Fast-forward merge requests](../user/project/merge_requests/fast_forward_merge.md)
- [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md)
- [Importing from SVN, GitHub, Bitbucket, etc](importing/README.md)
- [Todos](todos.md)
diff --git a/features/project/ff_merge_requests.feature b/features/project/ff_merge_requests.feature
new file mode 100644
index 00000000000..995e52f9332
--- /dev/null
+++ b/features/project/ff_merge_requests.feature
@@ -0,0 +1,24 @@
+Feature: Project Ff Merge Requests
+ Background:
+ Given I sign in as a user
+ And I own project "Shop"
+ And project "Shop" have "Bug NS-05" open merge request with diffs inside
+ And merge request "Bug NS-05" is mergeable
+
+ @javascript
+ Scenario: I do ff-only merge for rebased branch
+ Given ff merge enabled
+ And merge request "Bug NS-05" is rebased
+ When I visit merge request page "Bug NS-05"
+ Then I should see ff-only merge button
+ When I accept this merge request
+ Then I should see merged request
+
+ @javascript
+ Scenario: I do ff-only merge for merged branch
+ Given ff merge enabled
+ And merge request "Bug NS-05" merged target
+ When I visit merge request page "Bug NS-05"
+ Then I should see ff-only merge button
+ When I accept this merge request
+ Then I should see merged request
diff --git a/features/steps/project/ff_merge_requests.rb b/features/steps/project/ff_merge_requests.rb
new file mode 100644
index 00000000000..d68fe71e16e
--- /dev/null
+++ b/features/steps/project/ff_merge_requests.rb
@@ -0,0 +1,65 @@
+class Spinach::Features::ProjectFfMergeRequests < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedIssuable
+ include SharedProject
+ include SharedNote
+ include SharedPaths
+ include SharedMarkdown
+ include SharedDiffNote
+ include SharedUser
+ include WaitForRequests
+
+ step 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do
+ create(:merge_request_with_diffs,
+ title: "Bug NS-05",
+ source_project: project,
+ target_project: project,
+ author: project.users.first)
+ end
+
+ step 'I should see ff-only merge button' do
+ expect(page).to have_content "Fast-forward merge without a merge commit"
+ expect(page).to have_button 'Merge'
+ end
+
+ step 'merge request "Bug NS-05" is mergeable' do
+ merge_request.mark_as_mergeable
+ end
+
+ step 'I accept this merge request' do
+ page.within '.mr-state-widget' do
+ click_button "Merge"
+ end
+ end
+
+ step 'I should see merged request' do
+ page.within '.status-box' do
+ expect(page).to have_content "Merged"
+ wait_for_requests
+ end
+ end
+
+ step 'ff merge enabled' do
+ project = merge_request.target_project
+ project.merge_requests_ff_only_enabled = true
+ project.save!
+ end
+
+ step 'merge request "Bug NS-05" is rebased' do
+ merge_request.source_branch = 'flatten-dir'
+ merge_request.target_branch = 'improve/awesome'
+ merge_request.reload_diff
+ merge_request.save!
+ end
+
+ step 'merge request "Bug NS-05" merged target' do
+ merge_request.source_branch = 'merged-target'
+ merge_request.target_branch = 'improve/awesome'
+ merge_request.reload_diff
+ merge_request.save!
+ end
+
+ def merge_request
+ @merge_request ||= MergeRequest.find_by!(title: "Bug NS-05")
+ end
+end
diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb
index f88738b4c61..3490bbd968c 100644
--- a/features/steps/project/fork.rb
+++ b/features/steps/project/fork.rb
@@ -26,7 +26,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps
end
step 'I fork to my namespace' do
- page.within '.fork-namespaces' do
+ page.within '.fork-thumbnail-container' do
click_link current_user.name
end
end
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index 2c59ec5bb06..c872bd6f861 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -232,7 +232,7 @@ module SharedDiffNote
end
def click_parallel_diff_line(code, line_type)
- find(".line_holder.parallel .diff-line-num[id='#{code}']").trigger 'mouseover'
+ find(".line_holder.parallel td[id='#{code}']").find(:xpath, 'preceding-sibling::*[1][self::td]').trigger 'mouseover'
find(".line_holder.parallel button[data-line-code='#{code}']").trigger 'click'
end
end
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 643c8e6fb8e..61a2d688282 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -13,7 +13,7 @@ module API
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a project repository branches' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
use :pagination
@@ -23,13 +23,13 @@ module API
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37442
Gitlab::GitalyClient.allow_n_plus_1_calls do
- present paginate(branches), with: Entities::RepoBranch, project: user_project
+ present paginate(branches), with: Entities::Branch, project: user_project
end
end
resource ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
desc 'Get a single branch' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
requires :branch, type: String, desc: 'The name of the branch'
@@ -41,7 +41,7 @@ module API
branch = user_project.repository.find_branch(params[:branch])
not_found!('Branch') unless branch
- present branch, with: Entities::RepoBranch, project: user_project
+ present branch, with: Entities::Branch, project: user_project
end
end
@@ -50,7 +50,7 @@ module API
# in `gitlab-org/gitlab-ce!5081`. The API interface has not been changed (to maintain compatibility),
# but it works with the changed data model to infer `developers_can_merge` and `developers_can_push`.
desc 'Protect a single branch' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
requires :branch, type: String, desc: 'The name of the branch'
@@ -80,7 +80,7 @@ module API
end
if protected_branch.valid?
- present branch, with: Entities::RepoBranch, project: user_project
+ present branch, with: Entities::Branch, project: user_project
else
render_api_error!(protected_branch.errors.full_messages, 422)
end
@@ -88,7 +88,7 @@ module API
# Note: This API will be deprecated in favor of the protected branches API.
desc 'Unprotect a single branch' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
requires :branch, type: String, desc: 'The name of the branch'
@@ -101,11 +101,11 @@ module API
protected_branch = user_project.protected_branches.find_by(name: branch.name)
protected_branch&.destroy
- present branch, with: Entities::RepoBranch, project: user_project
+ present branch, with: Entities::Branch, project: user_project
end
desc 'Create branch' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
requires :branch, type: String, desc: 'The name of the branch'
@@ -119,7 +119,7 @@ module API
if result[:status] == :success
present result[:branch],
- with: Entities::RepoBranch,
+ with: Entities::Branch,
project: user_project
else
render_api_error!(result[:message], 400)
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 4b8d248f5f7..4af37a2ad1d 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -13,7 +13,7 @@ module API
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a project repository commits' do
- success Entities::RepoCommit
+ success Entities::Commit
end
params do
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
@@ -46,11 +46,11 @@ module API
paginated_commits = Kaminari.paginate_array(commits, total_count: commit_count)
- present paginate(paginated_commits), with: Entities::RepoCommit
+ present paginate(paginated_commits), with: Entities::Commit
end
desc 'Commit multiple file changes as one commit' do
- success Entities::RepoCommitDetail
+ success Entities::CommitDetail
detail 'This feature was introduced in GitLab 8.13'
end
params do
@@ -72,14 +72,14 @@ module API
if result[:status] == :success
commit_detail = user_project.repository.commit(result[:result])
- present commit_detail, with: Entities::RepoCommitDetail
+ present commit_detail, with: Entities::CommitDetail
else
render_api_error!(result[:message], 400)
end
end
desc 'Get a specific commit of a project' do
- success Entities::RepoCommitDetail
+ success Entities::CommitDetail
failure [[404, 'Commit Not Found']]
end
params do
@@ -90,7 +90,7 @@ module API
not_found! 'Commit' unless commit
- present commit, with: Entities::RepoCommitDetail
+ present commit, with: Entities::CommitDetail
end
desc 'Get the diff for a specific commit of a project' do
@@ -104,7 +104,7 @@ module API
not_found! 'Commit' unless commit
- present commit.raw_diffs.to_a, with: Entities::RepoDiff
+ present commit.raw_diffs.to_a, with: Entities::Diff
end
desc "Get a commit's comments" do
@@ -126,7 +126,7 @@ module API
desc 'Cherry pick commit into a branch' do
detail 'This feature was introduced in GitLab 8.15'
- success Entities::RepoCommit
+ success Entities::Commit
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag to be cherry picked'
@@ -151,7 +151,7 @@ module API
if result[:status] == :success
branch = user_project.repository.find_branch(params[:branch])
- present user_project.repository.commit(branch.dereferenced_target), with: Entities::RepoCommit
+ present user_project.repository.commit(branch.dereferenced_target), with: Entities::Commit
else
render_api_error!(result[:message], 400)
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 5d45b14f592..86dec3ca9f1 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -220,7 +220,7 @@ module API
expose :shared_projects, using: Entities::Project
end
- class RepoCommit < Grape::Entity
+ class Commit < Grape::Entity
expose :id, :short_id, :title, :created_at
expose :parent_ids
expose :safe_message, as: :message
@@ -228,20 +228,20 @@ module API
expose :committer_name, :committer_email, :committed_date
end
- class RepoCommitStats < Grape::Entity
+ class CommitStats < Grape::Entity
expose :additions, :deletions, :total
end
- class RepoCommitDetail < RepoCommit
- expose :stats, using: Entities::RepoCommitStats
+ class CommitDetail < Commit
+ expose :stats, using: Entities::CommitStats
expose :status
expose :last_pipeline, using: 'API::Entities::PipelineBasic'
end
- class RepoBranch < Grape::Entity
+ class Branch < Grape::Entity
expose :name
- expose :commit, using: Entities::RepoCommit do |repo_branch, options|
+ expose :commit, using: Entities::Commit do |repo_branch, options|
options[:project].repository.commit(repo_branch.dereferenced_target)
end
@@ -265,7 +265,7 @@ module API
end
end
- class RepoTreeObject < Grape::Entity
+ class TreeObject < Grape::Entity
expose :id, :name, :type, :path
expose :mode do |obj, options|
@@ -305,7 +305,7 @@ module API
expose :state, :created_at, :updated_at
end
- class RepoDiff < Grape::Entity
+ class Diff < Grape::Entity
expose :old_path, :new_path, :a_mode, :b_mode
expose :new_file?, as: :new_file
expose :renamed_file?, as: :renamed_file
@@ -483,7 +483,7 @@ module API
end
class MergeRequestChanges < MergeRequest
- expose :diffs, as: :changes, using: Entities::RepoDiff do |compare, _|
+ expose :diffs, as: :changes, using: Entities::Diff do |compare, _|
compare.raw_diffs(limits: false).to_a
end
end
@@ -494,9 +494,9 @@ module API
end
class MergeRequestDiffFull < MergeRequestDiff
- expose :commits, using: Entities::RepoCommit
+ expose :commits, using: Entities::Commit
- expose :diffs, using: Entities::RepoDiff do |compare, _|
+ expose :diffs, using: Entities::Diff do |compare, _|
compare.raw_diffs(limits: false).to_a
end
end
@@ -592,8 +592,7 @@ module API
expose :target_type
expose :target do |todo, options|
- target = todo.target_type == 'Commit' ? 'RepoCommit' : todo.target_type
- Entities.const_get(target).represent(todo.target, options)
+ Entities.const_get(todo.target_type).represent(todo.target, options)
end
expose :target_url do |todo, options|
@@ -729,15 +728,15 @@ module API
end
class Compare < Grape::Entity
- expose :commit, using: Entities::RepoCommit do |compare, options|
- Commit.decorate(compare.commits, nil).last
+ expose :commit, using: Entities::Commit do |compare, options|
+ ::Commit.decorate(compare.commits, nil).last
end
- expose :commits, using: Entities::RepoCommit do |compare, options|
- Commit.decorate(compare.commits, nil)
+ expose :commits, using: Entities::Commit do |compare, options|
+ ::Commit.decorate(compare.commits, nil)
end
- expose :diffs, using: Entities::RepoDiff do |compare, options|
+ expose :diffs, using: Entities::Diff do |compare, options|
compare.diffs(limits: false).to_a
end
@@ -773,10 +772,10 @@ module API
expose :description
end
- class RepoTag < Grape::Entity
+ class Tag < Grape::Entity
expose :name, :message
- expose :commit, using: Entities::RepoCommit do |repo_tag, options|
+ expose :commit, using: Entities::Commit do |repo_tag, options|
options[:project].repository.commit(repo_tag.dereferenced_target)
end
@@ -827,7 +826,7 @@ module API
expose :created_at, :started_at, :finished_at
expose :user, with: User
expose :artifacts_file, using: JobArtifactFile, if: -> (job, opts) { job.artifacts? }
- expose :commit, with: RepoCommit
+ expose :commit, with: Commit
expose :runner, with: Runner
expose :pipeline, with: PipelineBasic
end
@@ -880,7 +879,7 @@ module API
expose :deployable, using: Entities::Job
end
- class RepoLicense < Grape::Entity
+ class License < Grape::Entity
expose :key, :name, :nickname
expose :featured, as: :popular
expose :url, as: :html_url
@@ -1022,6 +1021,7 @@ module API
expose :cache, using: Cache
expose :credentials, using: Credentials
expose :dependencies, using: Dependency
+ expose :features
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 1e8475ba3ec..4964a76bef6 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -464,10 +464,12 @@ module API
header(*Gitlab::Workhorse.send_artifacts_entry(build, entry))
end
- # The Grape Error Middleware only has access to env but no params. We workaround this by
- # defining a method that returns the right value.
+ # The Grape Error Middleware only has access to `env` but not `params` nor
+ # `request`. We workaround this by defining methods that returns the right
+ # values.
def define_params_for_grape_middleware
- self.define_singleton_method(:params) { Rack::Request.new(env).params.symbolize_keys }
+ self.define_singleton_method(:request) { Rack::Request.new(env) }
+ self.define_singleton_method(:params) { request.params.symbolize_keys }
end
# We could get a Grape or a standard Ruby exception. We should only report anything that
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index a0557a609ca..6e78ac2c903 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -31,6 +31,12 @@ module API
protocol = params[:protocol]
actor.update_last_used_at if actor.is_a?(Key)
+ user =
+ if actor.is_a?(Key)
+ actor.user
+ else
+ actor
+ end
access_checker_klass = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
access_checker = access_checker_klass
@@ -47,6 +53,7 @@ module API
{
status: true,
gl_repository: gl_repository,
+ gl_username: user&.username,
repository_path: repository_path,
gitaly: gitaly_payload(params[:action])
}
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 8aa1e0216ee..828bc48383e 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -183,13 +183,13 @@ module API
end
desc 'Get the commits of a merge request' do
- success Entities::RepoCommit
+ success Entities::Commit
end
get ':id/merge_requests/:merge_request_iid/commits' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
commits = ::Kaminari.paginate_array(merge_request.commits)
- present paginate(commits), with: Entities::RepoCommit
+ present paginate(commits), with: Entities::Commit
end
desc 'Show the merge request changes' do
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 2255fb1b70d..ceee3226732 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -35,7 +35,7 @@ module API
end
desc 'Get a project repository tree' do
- success Entities::RepoTreeObject
+ success Entities::TreeObject
end
params do
optional :ref, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
@@ -52,7 +52,7 @@ module API
tree = user_project.repository.tree(commit.id, path, recursive: params[:recursive])
entries = ::Kaminari.paginate_array(tree.sorted_entries)
- present paginate(entries), with: Entities::RepoTreeObject
+ present paginate(entries), with: Entities::TreeObject
end
desc 'Get raw blob contents from the repository'
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index 912415e3a7f..0d394a7b441 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -11,18 +11,18 @@ module API
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a project repository tags' do
- success Entities::RepoTag
+ success Entities::Tag
end
params do
use :pagination
end
get ':id/repository/tags' do
tags = ::Kaminari.paginate_array(user_project.repository.tags.sort_by(&:name).reverse)
- present paginate(tags), with: Entities::RepoTag, project: user_project
+ present paginate(tags), with: Entities::Tag, project: user_project
end
desc 'Get a single repository tag' do
- success Entities::RepoTag
+ success Entities::Tag
end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
@@ -31,11 +31,11 @@ module API
tag = user_project.repository.find_tag(params[:tag_name])
not_found!('Tag') unless tag
- present tag, with: Entities::RepoTag, project: user_project
+ present tag, with: Entities::Tag, project: user_project
end
desc 'Create a new repository tag' do
- success Entities::RepoTag
+ success Entities::Tag
end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
@@ -51,7 +51,7 @@ module API
if result[:status] == :success
present result[:tag],
- with: Entities::RepoTag,
+ with: Entities::Tag,
project: user_project
else
render_api_error!(result[:message], 400)
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index f70bc0622b7..6550b331fb8 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -49,7 +49,7 @@ module API
desc 'Get the list of the available license template' do
detail 'This feature was introduced in GitLab 8.7.'
- success ::API::Entities::RepoLicense
+ success ::API::Entities::License
end
params do
optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
@@ -60,12 +60,12 @@ module API
featured: declared(params)[:popular].present? ? true : nil
}
licences = ::Kaminari.paginate_array(Licensee::License.all(options))
- present paginate(licences), with: Entities::RepoLicense
+ present paginate(licences), with: Entities::License
end
desc 'Get the text for a specific license' do
detail 'This feature was introduced in GitLab 8.7.'
- success ::API::Entities::RepoLicense
+ success ::API::Entities::License
end
params do
requires :name, type: String, desc: 'The name of the template'
@@ -75,7 +75,7 @@ module API
template = parsed_license_template
- present template, with: ::API::Entities::RepoLicense
+ present template, with: ::API::Entities::License
end
GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
diff --git a/lib/api/v3/branches.rb b/lib/api/v3/branches.rb
index 81b13249892..69cd12de72c 100644
--- a/lib/api/v3/branches.rb
+++ b/lib/api/v3/branches.rb
@@ -11,12 +11,12 @@ module API
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get a project repository branches' do
- success ::API::Entities::RepoBranch
+ success ::API::Entities::Branch
end
get ":id/repository/branches" do
branches = user_project.repository.branches.sort_by(&:name)
- present branches, with: ::API::Entities::RepoBranch, project: user_project
+ present branches, with: ::API::Entities::Branch, project: user_project
end
desc 'Delete a branch'
@@ -47,7 +47,7 @@ module API
end
desc 'Create branch' do
- success ::API::Entities::RepoBranch
+ success ::API::Entities::Branch
end
params do
requires :branch_name, type: String, desc: 'The name of the branch'
@@ -60,7 +60,7 @@ module API
if result[:status] == :success
present result[:branch],
- with: ::API::Entities::RepoBranch,
+ with: ::API::Entities::Branch,
project: user_project
else
render_api_error!(result[:message], 400)
diff --git a/lib/api/v3/commits.rb b/lib/api/v3/commits.rb
index 5936f4700aa..345cb7e7c11 100644
--- a/lib/api/v3/commits.rb
+++ b/lib/api/v3/commits.rb
@@ -13,7 +13,7 @@ module API
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get a project repository commits' do
- success ::API::Entities::RepoCommit
+ success ::API::Entities::Commit
end
params do
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
@@ -34,11 +34,11 @@ module API
after: params[:since],
before: params[:until])
- present commits, with: ::API::Entities::RepoCommit
+ present commits, with: ::API::Entities::Commit
end
desc 'Commit multiple file changes as one commit' do
- success ::API::Entities::RepoCommitDetail
+ success ::API::Entities::CommitDetail
detail 'This feature was introduced in GitLab 8.13'
end
params do
@@ -59,14 +59,14 @@ module API
if result[:status] == :success
commit_detail = user_project.repository.commits(result[:result], limit: 1).first
- present commit_detail, with: ::API::Entities::RepoCommitDetail
+ present commit_detail, with: ::API::Entities::CommitDetail
else
render_api_error!(result[:message], 400)
end
end
desc 'Get a specific commit of a project' do
- success ::API::Entities::RepoCommitDetail
+ success ::API::Entities::CommitDetail
failure [[404, 'Not Found']]
end
params do
@@ -77,7 +77,7 @@ module API
not_found! "Commit" unless commit
- present commit, with: ::API::Entities::RepoCommitDetail
+ present commit, with: ::API::Entities::CommitDetail
end
desc 'Get the diff for a specific commit of a project' do
@@ -113,7 +113,7 @@ module API
desc 'Cherry pick commit into a branch' do
detail 'This feature was introduced in GitLab 8.15'
- success ::API::Entities::RepoCommit
+ success ::API::Entities::Commit
end
params do
requires :sha, type: String, desc: 'A commit sha to be cherry picked'
@@ -138,7 +138,7 @@ module API
if result[:status] == :success
branch = user_project.repository.find_branch(params[:branch])
- present user_project.repository.commit(branch.dereferenced_target), with: ::API::Entities::RepoCommit
+ present user_project.repository.commit(branch.dereferenced_target), with: ::API::Entities::Commit
else
render_api_error!(result[:message], 400)
end
diff --git a/lib/api/v3/entities.rb b/lib/api/v3/entities.rb
index c928ce5265b..afdd7b83998 100644
--- a/lib/api/v3/entities.rb
+++ b/lib/api/v3/entities.rb
@@ -220,7 +220,7 @@ module API
expose :created_at, :started_at, :finished_at
expose :user, with: ::API::Entities::User
expose :artifacts_file, using: ::API::Entities::JobArtifactFile, if: -> (build, opts) { build.artifacts? }
- expose :commit, with: ::API::Entities::RepoCommit
+ expose :commit, with: ::API::Entities::Commit
expose :runner, with: ::API::Entities::Runner
expose :pipeline, with: ::API::Entities::PipelineBasic
end
@@ -237,7 +237,7 @@ module API
end
class MergeRequestChanges < MergeRequest
- expose :diffs, as: :changes, using: ::API::Entities::RepoDiff do |compare, _|
+ expose :diffs, as: :changes, using: ::API::Entities::Diff do |compare, _|
compare.raw_diffs(limits: false).to_a
end
end
diff --git a/lib/api/v3/merge_requests.rb b/lib/api/v3/merge_requests.rb
index b6b7254ae29..1d6d823f32b 100644
--- a/lib/api/v3/merge_requests.rb
+++ b/lib/api/v3/merge_requests.rb
@@ -135,12 +135,12 @@ module API
end
desc 'Get the commits of a merge request' do
- success ::API::Entities::RepoCommit
+ success ::API::Entities::Commit
end
get "#{path}/commits" do
merge_request = find_merge_request_with_access(params[:merge_request_id])
- present merge_request.commits, with: ::API::Entities::RepoCommit
+ present merge_request.commits, with: ::API::Entities::Commit
end
desc 'Show the merge request changes' do
diff --git a/lib/api/v3/repositories.rb b/lib/api/v3/repositories.rb
index 0eaa0de2eef..41a7c6b83ae 100644
--- a/lib/api/v3/repositories.rb
+++ b/lib/api/v3/repositories.rb
@@ -19,7 +19,7 @@ module API
end
desc 'Get a project repository tree' do
- success ::API::Entities::RepoTreeObject
+ success ::API::Entities::TreeObject
end
params do
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
@@ -35,7 +35,7 @@ module API
tree = user_project.repository.tree(commit.id, path, recursive: params[:recursive])
- present tree.sorted_entries, with: ::API::Entities::RepoTreeObject
+ present tree.sorted_entries, with: ::API::Entities::TreeObject
end
desc 'Get a raw file contents'
diff --git a/lib/api/v3/tags.rb b/lib/api/v3/tags.rb
index 7e5875cd030..6e37d31d153 100644
--- a/lib/api/v3/tags.rb
+++ b/lib/api/v3/tags.rb
@@ -8,11 +8,11 @@ module API
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get a project repository tags' do
- success ::API::Entities::RepoTag
+ success ::API::Entities::Tag
end
get ":id/repository/tags" do
tags = user_project.repository.tags.sort_by(&:name).reverse
- present tags, with: ::API::Entities::RepoTag, project: user_project
+ present tags, with: ::API::Entities::Tag, project: user_project
end
desc 'Delete a repository tag'
diff --git a/lib/api/v3/templates.rb b/lib/api/v3/templates.rb
index 2a2fb59045c..7298203df10 100644
--- a/lib/api/v3/templates.rb
+++ b/lib/api/v3/templates.rb
@@ -52,7 +52,7 @@ module API
detailed_desc = 'This feature was introduced in GitLab 8.7.'
detailed_desc << DEPRECATION_MESSAGE unless status == :ok
detail detailed_desc
- success ::API::Entities::RepoLicense
+ success ::API::Entities::License
end
params do
optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
@@ -61,7 +61,7 @@ module API
options = {
featured: declared(params)[:popular].present? ? true : nil
}
- present Licensee::License.all(options), with: ::API::Entities::RepoLicense
+ present Licensee::License.all(options), with: ::API::Entities::License
end
end
@@ -70,7 +70,7 @@ module API
detailed_desc = 'This feature was introduced in GitLab 8.7.'
detailed_desc << DEPRECATION_MESSAGE unless status == :ok
detail detailed_desc
- success ::API::Entities::RepoLicense
+ success ::API::Entities::License
end
params do
requires :name, type: String, desc: 'The name of the template'
@@ -80,7 +80,7 @@ module API
template = parsed_license_template
- present template, with: ::API::Entities::RepoLicense
+ present template, with: ::API::Entities::License
end
end
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index 4e92be85110..3ad09a1b421 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -78,7 +78,7 @@ module Backup
project.ensure_storage_path_exists
cmd = if File.exist?(path_to_project_bundle)
- %W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_project_bundle} #{path_to_project_repo})
+ %W(#{Gitlab.config.git.bin_path} clone --bare --mirror #{path_to_project_bundle} #{path_to_project_repo})
else
%W(#{Gitlab.config.git.bin_path} init --bare #{path_to_project_repo})
end
diff --git a/lib/banzai/filter/markdown_filter.rb b/lib/banzai/filter/markdown_filter.rb
index ee73fa91589..9cac303e645 100644
--- a/lib/banzai/filter/markdown_filter.rb
+++ b/lib/banzai/filter/markdown_filter.rb
@@ -1,6 +1,18 @@
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"
@@ -13,27 +25,11 @@ module Banzai
end
def self.renderer
- @renderer ||= begin
+ Thread.current[:banzai_markdown_renderer] ||= begin
renderer = Banzai::Renderer::HTML.new
- Redcarpet::Markdown.new(renderer, redcarpet_options)
+ Redcarpet::Markdown.new(renderer, REDCARPET_OPTIONS)
end
end
-
- def self.redcarpet_options
- # 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
- end
-
- private_class_method :redcarpet_options
end
end
end
diff --git a/lib/banzai/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb
index 88b17e12576..d8c8deea628 100644
--- a/lib/banzai/filter/sanitization_filter.rb
+++ b/lib/banzai/filter/sanitization_filter.rb
@@ -73,8 +73,9 @@ module Banzai
return unless node.has_attribute?('href')
begin
+ node['href'] = node['href'].strip
uri = Addressable::URI.parse(node['href'])
- uri.scheme = uri.scheme.strip.downcase if uri.scheme
+ uri.scheme = uri.scheme.downcase if uri.scheme
node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(uri.scheme)
rescue Addressable::URI::InvalidURIError
diff --git a/lib/github/import.rb b/lib/github/import.rb
index f5f62dc8b6f..c0cd8382875 100644
--- a/lib/github/import.rb
+++ b/lib/github/import.rb
@@ -1,46 +1,13 @@
require_relative 'error'
+require_relative 'import/issue'
+require_relative 'import/legacy_diff_note'
+require_relative 'import/merge_request'
+require_relative 'import/note'
module Github
class Import
include Gitlab::ShellAdapter
- class MergeRequest < ::MergeRequest
- self.table_name = 'merge_requests'
-
- self.reset_callbacks :create
- self.reset_callbacks :save
- self.reset_callbacks :commit
- self.reset_callbacks :update
- self.reset_callbacks :validate
- end
-
- class Issue < ::Issue
- self.table_name = 'issues'
-
- self.reset_callbacks :save
- self.reset_callbacks :create
- self.reset_callbacks :commit
- self.reset_callbacks :update
- self.reset_callbacks :validate
- end
-
- class Note < ::Note
- self.table_name = 'notes'
-
- self.reset_callbacks :save
- self.reset_callbacks :commit
- self.reset_callbacks :update
- self.reset_callbacks :validate
- end
-
- class LegacyDiffNote < ::LegacyDiffNote
- self.table_name = 'notes'
-
- self.reset_callbacks :commit
- self.reset_callbacks :update
- self.reset_callbacks :validate
- end
-
attr_reader :project, :repository, :repo, :repo_url, :wiki_url,
:options, :errors, :cached, :verbose
diff --git a/lib/github/import/issue.rb b/lib/github/import/issue.rb
new file mode 100644
index 00000000000..171f0872666
--- /dev/null
+++ b/lib/github/import/issue.rb
@@ -0,0 +1,13 @@
+module Github
+ class Import
+ class Issue < ::Issue
+ self.table_name = 'issues'
+
+ self.reset_callbacks :save
+ self.reset_callbacks :create
+ self.reset_callbacks :commit
+ self.reset_callbacks :update
+ self.reset_callbacks :validate
+ end
+ end
+end
diff --git a/lib/github/import/legacy_diff_note.rb b/lib/github/import/legacy_diff_note.rb
new file mode 100644
index 00000000000..18adff560b6
--- /dev/null
+++ b/lib/github/import/legacy_diff_note.rb
@@ -0,0 +1,12 @@
+module Github
+ class Import
+ class LegacyDiffNote < ::LegacyDiffNote
+ self.table_name = 'notes'
+ self.store_full_sti_class = false
+
+ self.reset_callbacks :commit
+ self.reset_callbacks :update
+ self.reset_callbacks :validate
+ end
+ end
+end
diff --git a/lib/github/import/merge_request.rb b/lib/github/import/merge_request.rb
new file mode 100644
index 00000000000..c258e5d5e0e
--- /dev/null
+++ b/lib/github/import/merge_request.rb
@@ -0,0 +1,13 @@
+module Github
+ class Import
+ class MergeRequest < ::MergeRequest
+ self.table_name = 'merge_requests'
+
+ self.reset_callbacks :create
+ self.reset_callbacks :save
+ self.reset_callbacks :commit
+ self.reset_callbacks :update
+ self.reset_callbacks :validate
+ end
+ end
+end
diff --git a/lib/github/import/note.rb b/lib/github/import/note.rb
new file mode 100644
index 00000000000..8cf4f30e6b7
--- /dev/null
+++ b/lib/github/import/note.rb
@@ -0,0 +1,13 @@
+module Github
+ class Import
+ class Note < ::Note
+ self.table_name = 'notes'
+ self.store_full_sti_class = false
+
+ self.reset_callbacks :save
+ self.reset_callbacks :commit
+ self.reset_callbacks :update
+ self.reset_callbacks :validate
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb b/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb
index 3fde1b09efb..8e5c95f2287 100644
--- a/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb
+++ b/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb
@@ -3,11 +3,18 @@ module Gitlab
class DeserializeMergeRequestDiffsAndCommits
attr_reader :diff_ids, :commit_rows, :file_rows
+ class Error < StandardError
+ def backtrace
+ cause.backtrace
+ end
+ end
+
class MergeRequestDiff < ActiveRecord::Base
self.table_name = 'merge_request_diffs'
end
BUFFER_ROWS = 1000
+ DIFF_FILE_BUFFER_ROWS = 100
def perform(start_id, stop_id)
merge_request_diffs = MergeRequestDiff
@@ -26,13 +33,17 @@ module Gitlab
if diff_ids.length > BUFFER_ROWS ||
commit_rows.length > BUFFER_ROWS ||
- file_rows.length > BUFFER_ROWS
+ file_rows.length > DIFF_FILE_BUFFER_ROWS
flush_buffers!
end
end
flush_buffers!
+ rescue => e
+ Rails.logger.info("#{self.class.name}: failed for IDs #{merge_request_diffs.map(&:id)} with #{e.class.name}")
+
+ raise Error.new(e.inspect)
end
private
@@ -45,17 +56,28 @@ module Gitlab
def flush_buffers!
if diff_ids.any?
- MergeRequestDiff.transaction do
- Gitlab::Database.bulk_insert('merge_request_diff_commits', commit_rows)
- Gitlab::Database.bulk_insert('merge_request_diff_files', file_rows)
+ commit_rows.each_slice(BUFFER_ROWS).each do |commit_rows_slice|
+ bulk_insert('merge_request_diff_commits', commit_rows_slice)
+ end
- MergeRequestDiff.where(id: diff_ids).update_all(st_commits: nil, st_diffs: nil)
+ file_rows.each_slice(DIFF_FILE_BUFFER_ROWS).each do |file_rows_slice|
+ bulk_insert('merge_request_diff_files', file_rows_slice)
end
+
+ MergeRequestDiff.where(id: diff_ids).update_all(st_commits: nil, st_diffs: nil)
end
reset_buffers!
end
+ def bulk_insert(table, rows)
+ Gitlab::Database.bulk_insert(table, rows)
+ rescue ActiveRecord::RecordNotUnique
+ ids = rows.map { |row| row[:merge_request_diff_id] }.uniq.sort
+
+ Rails.logger.info("#{self.class.name}: rows inserted twice for IDs #{ids}")
+ end
+
def single_diff_rows(merge_request_diff)
sha_attribute = Gitlab::Database::ShaAttribute.new
commits = YAML.load(merge_request_diff.st_commits) rescue []
diff --git a/lib/gitlab/bare_repository_importer.rb b/lib/gitlab/bare_repository_importer.rb
index 9323bfc7fb2..1d98d187805 100644
--- a/lib/gitlab/bare_repository_importer.rb
+++ b/lib/gitlab/bare_repository_importer.rb
@@ -56,7 +56,8 @@ module Gitlab
name: project_path,
path: project_path,
repository_storage: storage_name,
- namespace_id: group&.id
+ namespace_id: group&.id,
+ skip_disk_validation: true
}
project = Projects::CreateService.new(user, project_params).execute
diff --git a/lib/gitlab/ci/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb
index ad78ae244b2..088adbdd267 100644
--- a/lib/gitlab/ci/ansi2html.rb
+++ b/lib/gitlab/ci/ansi2html.rb
@@ -155,7 +155,9 @@ module Gitlab
stream.each_line do |line|
s = StringScanner.new(line)
until s.eos?
- if s.scan(/\e([@-_])(.*?)([@-~])/)
+ if s.scan(/section_((?:start)|(?:end)):(\d+):([^\r]+)\r\033\[0K/)
+ handle_section(s)
+ elsif s.scan(/\e([@-_])(.*?)([@-~])/)
handle_sequence(s)
elsif s.scan(/\e(([@-_])(.*?)?)?$/)
break
@@ -183,6 +185,15 @@ module Gitlab
)
end
+ def handle_section(s)
+ action = s[1]
+ timestamp = s[2]
+ section = s[3]
+ line = s.matched()[0...-5] # strips \r\033[0K
+
+ @out << %{<div class="hidden" data-action="#{action}" data-timestamp="#{timestamp}" data-section="#{section}">#{line}</div>}
+ end
+
def handle_sequence(s)
indicator = s[1]
commands = s[2].split ';'
diff --git a/lib/gitlab/git/diff.rb b/lib/gitlab/git/diff.rb
index 096301d300f..ca94b4baa59 100644
--- a/lib/gitlab/git/diff.rb
+++ b/lib/gitlab/git/diff.rb
@@ -24,41 +24,13 @@ module Gitlab
SERIALIZE_KEYS = %i(diff new_path old_path a_mode b_mode new_file renamed_file deleted_file too_large).freeze
- class << self
- # The maximum size of a diff to display.
- def size_limit
- if RequestStore.active?
- RequestStore['gitlab_git_diff_size_limit'] ||= find_size_limit
- else
- find_size_limit
- end
- end
-
- # The maximum size before a diff is collapsed.
- def collapse_limit
- if RequestStore.active?
- RequestStore['gitlab_git_diff_collapse_limit'] ||= find_collapse_limit
- else
- find_collapse_limit
- end
- end
+ # The maximum size of a diff to display.
+ SIZE_LIMIT = 100.kilobytes
- def find_size_limit
- if Feature.enabled?('gitlab_git_diff_size_limit_increase')
- 200.kilobytes
- else
- 100.kilobytes
- end
- end
-
- def find_collapse_limit
- if Feature.enabled?('gitlab_git_diff_size_limit_increase')
- 100.kilobytes
- else
- 10.kilobytes
- end
- end
+ # The maximum size before a diff is collapsed.
+ COLLAPSE_LIMIT = 10.kilobytes
+ class << self
def between(repo, head, base, options = {}, *paths)
straight = options.delete(:straight) || false
@@ -172,7 +144,7 @@ module Gitlab
def too_large?
if @too_large.nil?
- @too_large = @diff.bytesize >= self.class.size_limit
+ @too_large = @diff.bytesize >= SIZE_LIMIT
else
@too_large
end
@@ -190,7 +162,7 @@ module Gitlab
def collapsed?
return @collapsed if defined?(@collapsed)
- @collapsed = !expanded && @diff.bytesize >= self.class.collapse_limit
+ @collapsed = !expanded && @diff.bytesize >= COLLAPSE_LIMIT
end
def collapse!
@@ -275,14 +247,14 @@ module Gitlab
hunk.each_line do |line|
size += line.content.bytesize
- if size >= self.class.size_limit
+ if size >= SIZE_LIMIT
too_large!
return true
end
end
end
- if !expanded && size >= self.class.collapse_limit
+ if !expanded && size >= COLLAPSE_LIMIT
collapse!
return true
end
diff --git a/lib/gitlab/git/hook.rb b/lib/gitlab/git/hook.rb
index 208e4bbaf60..e29a1f7afa1 100644
--- a/lib/gitlab/git/hook.rb
+++ b/lib/gitlab/git/hook.rb
@@ -22,22 +22,22 @@ module Gitlab
File.exist?(path)
end
- def trigger(gl_id, oldrev, newrev, ref)
+ def trigger(gl_id, gl_username, oldrev, newrev, ref)
return [true, nil] unless exists?
Bundler.with_clean_env do
case name
when "pre-receive", "post-receive"
- call_receive_hook(gl_id, oldrev, newrev, ref)
+ call_receive_hook(gl_id, gl_username, oldrev, newrev, ref)
when "update"
- call_update_hook(gl_id, oldrev, newrev, ref)
+ call_update_hook(gl_id, gl_username, oldrev, newrev, ref)
end
end
end
private
- def call_receive_hook(gl_id, oldrev, newrev, ref)
+ def call_receive_hook(gl_id, gl_username, oldrev, newrev, ref)
changes = [oldrev, newrev, ref].join(" ")
exit_status = false
@@ -45,6 +45,7 @@ module Gitlab
vars = {
'GL_ID' => gl_id,
+ 'GL_USERNAME' => gl_username,
'PWD' => repo_path,
'GL_PROTOCOL' => GL_PROTOCOL,
'GL_REPOSITORY' => repository.gl_repository
@@ -80,9 +81,13 @@ module Gitlab
[exit_status, exit_message]
end
- def call_update_hook(gl_id, oldrev, newrev, ref)
+ def call_update_hook(gl_id, gl_username, oldrev, newrev, ref)
Dir.chdir(repo_path) do
- stdout, stderr, status = Open3.capture3({ 'GL_ID' => gl_id }, path, ref, oldrev, newrev)
+ env = {
+ 'GL_ID' => gl_id,
+ 'GL_USERNAME' => gl_username
+ }
+ stdout, stderr, status = Open3.capture3(env, path, ref, oldrev, newrev)
[status.success?, (stderr.presence || stdout).gsub(/\R/, "<br>").html_safe]
end
end
diff --git a/lib/gitlab/git/hooks_service.rb b/lib/gitlab/git/hooks_service.rb
index ea8a87a1290..c327e9b1616 100644
--- a/lib/gitlab/git/hooks_service.rb
+++ b/lib/gitlab/git/hooks_service.rb
@@ -5,12 +5,13 @@ module Gitlab
attr_accessor :oldrev, :newrev, :ref
- def execute(committer, repository, oldrev, newrev, ref)
- @repository = repository
- @gl_id = committer.gl_id
- @oldrev = oldrev
- @newrev = newrev
- @ref = ref
+ def execute(pusher, repository, oldrev, newrev, ref)
+ @repository = repository
+ @gl_id = pusher.gl_id
+ @gl_username = pusher.name
+ @oldrev = oldrev
+ @newrev = newrev
+ @ref = ref
%w(pre-receive update).each do |hook_name|
status, message = run_hook(hook_name)
@@ -29,7 +30,7 @@ module Gitlab
def run_hook(name)
hook = Gitlab::Git::Hook.new(name, @repository)
- hook.trigger(@gl_id, oldrev, newrev, ref)
+ hook.trigger(@gl_id, @gl_username, oldrev, newrev, ref)
end
end
end
diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb
index 786e2e7e8dc..d835dcca8ba 100644
--- a/lib/gitlab/git/operation_service.rb
+++ b/lib/gitlab/git/operation_service.rb
@@ -152,13 +152,15 @@ module Gitlab
# (and have!) accidentally reset the ref to an earlier state, clobbering
# commits. See also https://github.com/libgit2/libgit2/issues/1534.
command = %W[#{Gitlab.config.git.bin_path} update-ref --stdin -z]
- _, status = popen(
+
+ output, status = popen(
command,
repository.path) do |stdin|
stdin.write("update #{ref}\x00#{newrev}\x00#{oldrev}\x00")
end
unless status.zero?
+ Gitlab::GitLogger.error("'git update-ref' in #{repository.path}: #{output}")
raise Gitlab::Git::CommitError.new(
"Could not update branch #{Gitlab::Git.branch_name(ref)}." \
" Please refresh and try again.")
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 6baff362dad..89b654253cb 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -20,13 +20,11 @@ module Gitlab
GitError = Class.new(StandardError)
DeleteBranchError = Class.new(StandardError)
CreateTreeError = Class.new(StandardError)
+ TagExistsError = Class.new(StandardError)
class << self
- # Unlike `new`, `create` takes the storage path, not the storage name
- def create(storage_path, name, bare: true, symlink_hooks_to: nil)
- repo_path = File.join(storage_path, name)
- repo_path += '.git' unless repo_path.end_with?('.git')
-
+ # Unlike `new`, `create` takes the repository path
+ def create(repo_path, bare: true, symlink_hooks_to: nil)
FileUtils.mkdir_p(repo_path, mode: 0770)
# Equivalent to `git --git-path=#{repo_path} init [--bare]`
@@ -55,14 +53,15 @@ module Gitlab
# Rugged repo object
attr_reader :rugged
- attr_reader :storage, :gl_repository, :relative_path
+ attr_reader :storage, :gl_repository, :relative_path, :gitaly_resolver
- # 'path' must be the path to a _bare_ git repository, e.g.
- # /path/to/my-repo.git
+ # This initializer method is only used on the client side (gitlab-ce).
+ # Gitaly-ruby uses a different initializer.
def initialize(storage, relative_path, gl_repository)
@storage = storage
@relative_path = relative_path
@gl_repository = gl_repository
+ @gitaly_resolver = Gitlab::GitalyClient
storage_path = Gitlab.config.repositories.storages[@storage]['path']
@path = File.join(storage_path, @relative_path)
@@ -191,6 +190,28 @@ module Gitlab
end
end
+ def has_local_branches?
+ gitaly_migrate(:has_local_branches) do |is_enabled|
+ if is_enabled
+ gitaly_ref_client.has_local_branches?
+ else
+ has_local_branches_rugged?
+ end
+ end
+ end
+
+ def has_local_branches_rugged?
+ rugged.branches.each(:local).any? do |ref|
+ begin
+ ref.name && ref.target # ensures the branch is valid
+
+ true
+ rescue Rugged::ReferenceError
+ false
+ end
+ end
+ end
+
# Returns the number of valid tags
def tag_count
gitaly_migrate(:tag_names) do |is_enabled|
@@ -636,42 +657,43 @@ module Gitlab
end
def add_branch(branch_name, user:, target:)
- target_object = Ref.dereference_object(lookup(target))
- raise InvalidRef.new("target not found: #{target}") unless target_object
-
- OperationService.new(user, self).add_branch(branch_name, target_object.oid)
- find_branch(branch_name)
- rescue Rugged::ReferenceError => ex
- raise InvalidRef, ex
+ gitaly_migrate(:operation_user_create_branch) do |is_enabled|
+ if is_enabled
+ gitaly_add_branch(branch_name, user, target)
+ else
+ rugged_add_branch(branch_name, user, target)
+ end
+ end
end
def add_tag(tag_name, user:, target:, message: nil)
- target_object = Ref.dereference_object(lookup(target))
- raise InvalidRef.new("target not found: #{target}") unless target_object
-
- user = Gitlab::Git::User.from_gitlab(user) unless user.respond_to?(:gl_id)
-
- options = nil # Use nil, not the empty hash. Rugged cares about this.
- if message
- options = {
- message: message,
- tagger: Gitlab::Git.committer_hash(email: user.email, name: user.name)
- }
+ gitaly_migrate(:operation_user_add_tag) do |is_enabled|
+ if is_enabled
+ gitaly_add_tag(tag_name, user: user, target: target, message: message)
+ else
+ rugged_add_tag(tag_name, user: user, target: target, message: message)
+ end
end
-
- OperationService.new(user, self).add_tag(tag_name, target_object.oid, options)
-
- find_tag(tag_name)
- rescue Rugged::ReferenceError => ex
- raise InvalidRef, ex
end
def rm_branch(branch_name, user:)
- OperationService.new(user, self).rm_branch(find_branch(branch_name))
+ gitaly_migrate(:operation_user_delete_branch) do |is_enabled|
+ if is_enabled
+ gitaly_operations_client.user_delete_branch(branch_name, user)
+ else
+ OperationService.new(user, self).rm_branch(find_branch(branch_name))
+ end
+ end
end
def rm_tag(tag_name, user:)
- OperationService.new(user, self).rm_tag(find_tag(tag_name))
+ gitaly_migrate(:operation_user_delete_tag) do |is_enabled|
+ if is_enabled
+ gitaly_operations_client.rm_tag(tag_name, user)
+ else
+ Gitlab::Git::OperationService.new(user, self).rm_tag(find_tag(tag_name))
+ end
+ end
end
def find_tag(name)
@@ -966,9 +988,9 @@ module Gitlab
def with_repo_tmp_commit(start_repository, start_branch_name, sha)
tmp_ref = fetch_ref(
- start_repository.path,
- "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}",
- "refs/tmp/#{SecureRandom.hex}/head"
+ start_repository,
+ source_ref: "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}",
+ target_ref: "refs/tmp/#{SecureRandom.hex}/head"
)
yield commit(sha)
@@ -1000,13 +1022,27 @@ module Gitlab
end
end
- def write_ref(ref_path, sha)
- rugged.references.create(ref_path, sha, force: true)
+ def write_ref(ref_path, ref)
+ raise ArgumentError, "invalid ref_path #{ref_path.inspect}" if ref_path.include?(' ')
+ raise ArgumentError, "invalid ref #{ref.inspect}" if ref.include?("\x00")
+
+ command = [Gitlab.config.git.bin_path] + %w[update-ref --stdin -z]
+ input = "update #{ref_path}\x00#{ref}\x00\x00"
+ output, status = circuit_breaker.perform do
+ popen(command, path) { |stdin| stdin.write(input) }
+ end
+
+ raise GitError, output unless status.zero?
end
- def fetch_ref(source_path, source_ref, target_ref)
- args = %W(fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref})
- message, status = run_git(args)
+ def fetch_ref(source_repository, source_ref:, target_ref:)
+ message, status = GitalyClient.migrate(:fetch_ref) do |is_enabled|
+ if is_enabled
+ gitaly_fetch_ref(source_repository, source_ref: source_ref, target_ref: target_ref)
+ else
+ local_fetch_ref(source_repository.path, source_ref: source_ref, target_ref: target_ref)
+ end
+ end
# Make sure ref was created, and raise Rugged::ReferenceError when not
raise Rugged::ReferenceError, message if status != 0
@@ -1015,9 +1051,9 @@ module Gitlab
end
# Refactoring aid; allows us to copy code from app/models/repository.rb
- def run_git(args)
+ def run_git(args, env: {})
circuit_breaker.perform do
- popen([Gitlab.config.git.bin_path, *args], path)
+ popen([Gitlab.config.git.bin_path, *args], path, env)
end
end
@@ -1041,11 +1077,17 @@ module Gitlab
# This method return true if repository contains some content visible in project page.
#
def has_visible_content?
- branch_count > 0
+ return @has_visible_content if defined?(@has_visible_content)
+
+ @has_visible_content = has_local_branches?
end
def gitaly_repository
- Gitlab::GitalyClient::Util.repository(@storage, @relative_path)
+ Gitlab::GitalyClient::Util.repository(@storage, @relative_path, @gl_repository)
+ end
+
+ def gitaly_operations_client
+ @gitaly_operations_client ||= Gitlab::GitalyClient::OperationService.new(self)
end
def gitaly_ref_client
@@ -1060,6 +1102,10 @@ module Gitlab
@gitaly_repository_client ||= Gitlab::GitalyClient::RepositoryService.new(self)
end
+ def gitaly_operation_client
+ @gitaly_operation_client ||= Gitlab::GitalyClient::OperationService.new(self)
+ end
+
def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block)
Gitlab::GitalyClient.migrate(method, status: status, &block)
rescue GRPC::NotFound => e
@@ -1382,6 +1428,33 @@ module Gitlab
false
end
+ def gitaly_add_tag(tag_name, user:, target:, message: nil)
+ gitaly_operations_client.add_tag(tag_name, user, target, message)
+ end
+
+ def rugged_add_tag(tag_name, user:, target:, message: nil)
+ target_object = Ref.dereference_object(lookup(target))
+ raise InvalidRef.new("target not found: #{target}") unless target_object
+
+ user = Gitlab::Git::User.from_gitlab(user) unless user.respond_to?(:gl_id)
+
+ options = nil # Use nil, not the empty hash. Rugged cares about this.
+ if message
+ options = {
+ message: message,
+ tagger: Gitlab::Git.committer_hash(email: user.email, name: user.name)
+ }
+ end
+
+ Gitlab::Git::OperationService.new(user, self).add_tag(tag_name, target_object.oid, options)
+
+ find_tag(tag_name)
+ rescue Rugged::ReferenceError => ex
+ raise InvalidRef, ex
+ rescue Rugged::TagError
+ raise TagExistsError
+ end
+
def rugged_create_branch(ref, start_point)
rugged_ref = rugged.branches.create(ref, start_point)
target_commit = Gitlab::Git::Commit.find(self, rugged_ref.target)
@@ -1424,6 +1497,46 @@ module Gitlab
file.write(gitattributes_content)
end
end
+
+ def gitaly_add_branch(branch_name, user, target)
+ gitaly_operation_client.user_create_branch(branch_name, user, target)
+ rescue GRPC::FailedPrecondition => ex
+ raise InvalidRef, ex
+ end
+
+ def rugged_add_branch(branch_name, user, target)
+ target_object = Ref.dereference_object(lookup(target))
+ raise InvalidRef.new("target not found: #{target}") unless target_object
+
+ OperationService.new(user, self).add_branch(branch_name, target_object.oid)
+ find_branch(branch_name)
+ rescue Rugged::ReferenceError => ex
+ raise InvalidRef, ex
+ end
+
+ def local_fetch_ref(source_path, source_ref:, target_ref:)
+ args = %W(fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref})
+ run_git(args)
+ end
+
+ def gitaly_fetch_ref(source_repository, source_ref:, target_ref:)
+ gitaly_ssh = File.absolute_path(File.join(Gitlab.config.gitaly.client_path, 'gitaly-ssh'))
+ gitaly_address = gitaly_resolver.address(source_repository.storage)
+ gitaly_token = gitaly_resolver.token(source_repository.storage)
+
+ request = Gitaly::SSHUploadPackRequest.new(repository: source_repository.gitaly_repository)
+ env = {
+ 'GITALY_ADDRESS' => gitaly_address,
+ 'GITALY_PAYLOAD' => request.to_json,
+ 'GITALY_WD' => Dir.pwd,
+ 'GIT_SSH_COMMAND' => "#{gitaly_ssh} upload-pack"
+ }
+ env['GITALY_TOKEN'] = gitaly_token if gitaly_token.present?
+
+ args = %W(fetch --no-tags -f ssh://gitaly/internal.git #{source_ref}:#{target_ref})
+
+ run_git(args, env: env)
+ end
end
end
end
diff --git a/lib/gitlab/git/rev_list.rb b/lib/gitlab/git/rev_list.rb
index e0943d3a3eb..92a6a672534 100644
--- a/lib/gitlab/git/rev_list.rb
+++ b/lib/gitlab/git/rev_list.rb
@@ -31,7 +31,7 @@ module Gitlab
output, status = popen(args, nil, Gitlab::Git::Env.all.stringify_keys)
unless status.zero?
- raise "Got a non-zero exit code while calling out `#{args.join(' ')}`."
+ raise "Got a non-zero exit code while calling out `#{args.join(' ')}`: #{output}"
end
output.split("\n")
diff --git a/lib/gitlab/git/user.rb b/lib/gitlab/git/user.rb
index ea634d39668..da74719ae87 100644
--- a/lib/gitlab/git/user.rb
+++ b/lib/gitlab/git/user.rb
@@ -1,24 +1,26 @@
module Gitlab
module Git
class User
- attr_reader :name, :email, :gl_id
+ attr_reader :username, :name, :email, :gl_id
def self.from_gitlab(gitlab_user)
- new(gitlab_user.name, gitlab_user.email, Gitlab::GlId.gl_id(gitlab_user))
+ new(gitlab_user.username, gitlab_user.name, gitlab_user.email, Gitlab::GlId.gl_id(gitlab_user))
end
+ # TODO support the username field in Gitaly https://gitlab.com/gitlab-org/gitaly/issues/628
def self.from_gitaly(gitaly_user)
- new(gitaly_user.name, gitaly_user.email, gitaly_user.gl_id)
+ new('', gitaly_user.name, gitaly_user.email, gitaly_user.gl_id)
end
- def initialize(name, email, gl_id)
+ def initialize(username, name, email, gl_id)
+ @username = username
@name = name
@email = email
@gl_id = gl_id
end
def ==(other)
- [name, email, gl_id] == [other.name, other.email, other.gl_id]
+ [username, name, email, gl_id] == [other.username, other.name, other.email, other.gl_id]
end
end
end
diff --git a/lib/gitlab/git/wiki.rb b/lib/gitlab/git/wiki.rb
new file mode 100644
index 00000000000..d651c931a38
--- /dev/null
+++ b/lib/gitlab/git/wiki.rb
@@ -0,0 +1,115 @@
+module Gitlab
+ module Git
+ class Wiki
+ DuplicatePageError = Class.new(StandardError)
+
+ CommitDetails = Struct.new(:name, :email, :message) do
+ def to_h
+ { name: name, email: email, message: message }
+ end
+ end
+
+ def self.default_ref
+ 'master'
+ end
+
+ # Initialize with a Gitlab::Git::Repository instance
+ def initialize(repository)
+ @repository = repository
+ end
+
+ def repository_exists?
+ @repository.exists?
+ end
+
+ def write_page(name, format, content, commit_details)
+ assert_type!(format, Symbol)
+ assert_type!(commit_details, CommitDetails)
+
+ gollum_wiki.write_page(name, format, content, commit_details.to_h)
+
+ nil
+ rescue Gollum::DuplicatePageError => e
+ raise Gitlab::Git::Wiki::DuplicatePageError, e.message
+ end
+
+ def delete_page(page_path, commit_details)
+ assert_type!(commit_details, CommitDetails)
+
+ gollum_wiki.delete_page(gollum_page_by_path(page_path), commit_details.to_h)
+ nil
+ end
+
+ def update_page(page_path, title, format, content, commit_details)
+ assert_type!(format, Symbol)
+ assert_type!(commit_details, CommitDetails)
+
+ gollum_wiki.update_page(gollum_page_by_path(page_path), title, format, content, commit_details.to_h)
+ nil
+ end
+
+ def pages
+ gollum_wiki.pages.map { |gollum_page| new_page(gollum_page) }
+ end
+
+ def page(title:, version: nil, dir: nil)
+ if version
+ version = Gitlab::Git::Commit.find(@repository, version).id
+ end
+
+ gollum_page = gollum_wiki.page(title, version, dir)
+ return unless gollum_page
+
+ new_page(gollum_page)
+ end
+
+ def file(name, version)
+ version ||= self.class.default_ref
+ gollum_file = gollum_wiki.file(name, version)
+ return unless gollum_file
+
+ Gitlab::Git::WikiFile.new(gollum_file)
+ end
+
+ def page_versions(page_path)
+ current_page = gollum_page_by_path(page_path)
+ current_page.versions.map do |gollum_git_commit|
+ gollum_page = gollum_wiki.page(current_page.title, gollum_git_commit.id)
+ new_version(gollum_page, gollum_git_commit.id)
+ end
+ end
+
+ def preview_slug(title, format)
+ gollum_wiki.preview_page(title, '', format).url_path
+ end
+
+ private
+
+ def gollum_wiki
+ @gollum_wiki ||= Gollum::Wiki.new(@repository.path)
+ end
+
+ def gollum_page_by_path(page_path)
+ page_name = Gollum::Page.canonicalize_filename(page_path)
+ page_dir = File.split(page_path).first
+
+ gollum_wiki.paged(page_name, page_dir)
+ end
+
+ def new_page(gollum_page)
+ Gitlab::Git::WikiPage.new(gollum_page, new_version(gollum_page, gollum_page.version.id))
+ end
+
+ def new_version(gollum_page, commit_id)
+ commit = Gitlab::Git::Commit.find(@repository, commit_id)
+ Gitlab::Git::WikiPageVersion.new(commit, gollum_page&.format)
+ end
+
+ def assert_type!(object, klass)
+ unless object.is_a?(klass)
+ raise ArgumentError, "expected a #{klass}, got #{object.inspect}"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/wiki_file.rb b/lib/gitlab/git/wiki_file.rb
new file mode 100644
index 00000000000..527f2a44dea
--- /dev/null
+++ b/lib/gitlab/git/wiki_file.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Git
+ class WikiFile
+ attr_reader :mime_type, :raw_data, :name
+
+ # This class is meant to be serializable so that it can be constructed
+ # by Gitaly and sent over the network to GitLab.
+ #
+ # Because Gollum::File is not serializable we must get all the data from
+ # 'gollum_file' during initialization, and NOT store it in an instance
+ # variable.
+ def initialize(gollum_file)
+ @mime_type = gollum_file.mime_type
+ @raw_data = gollum_file.raw_data
+ @name = gollum_file.name
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/wiki_page.rb b/lib/gitlab/git/wiki_page.rb
new file mode 100644
index 00000000000..a06bac4414f
--- /dev/null
+++ b/lib/gitlab/git/wiki_page.rb
@@ -0,0 +1,39 @@
+module Gitlab
+ module Git
+ class WikiPage
+ attr_reader :url_path, :title, :format, :path, :version, :raw_data, :name, :text_data, :historical
+
+ # This class is meant to be serializable so that it can be constructed
+ # by Gitaly and sent over the network to GitLab.
+ #
+ # Because Gollum::Page is not serializable we must get all the data from
+ # 'gollum_page' during initialization, and NOT store it in an instance
+ # variable.
+ #
+ # Note that 'version' is a WikiPageVersion instance which it itself
+ # serializable. That means it's OK to store 'version' in an instance
+ # variable.
+ def initialize(gollum_page, version)
+ @url_path = gollum_page.url_path
+ @title = gollum_page.title
+ @format = gollum_page.format
+ @path = gollum_page.path
+ @raw_data = gollum_page.raw_data
+ @name = gollum_page.name
+ @historical = gollum_page.historical?
+
+ @version = version
+ end
+
+ def historical?
+ @historical
+ end
+
+ def text_data
+ return @text_data if defined?(@text_data)
+
+ @text_data = @raw_data && Gitlab::EncodingHelper.encode!(@raw_data.dup)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/wiki_page_version.rb b/lib/gitlab/git/wiki_page_version.rb
new file mode 100644
index 00000000000..55f1afedcab
--- /dev/null
+++ b/lib/gitlab/git/wiki_page_version.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Git
+ class WikiPageVersion
+ attr_reader :commit, :format
+
+ # This class is meant to be serializable so that it can be constructed
+ # by Gitaly and sent over the network to GitLab.
+ #
+ # Both 'commit' (a Gitlab::Git::Commit) and 'format' (a string) are
+ # serializable.
+ def initialize(commit, format)
+ @commit = commit
+ @format = format
+ end
+
+ delegate :message, :sha, :id, :author_name, :authored_date, to: :commit
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 955d2307f88..87b300dcf7e 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -151,7 +151,7 @@ module Gitlab
actual_call_count = increment_call_count("gitaly_#{call_site}_actual")
# Do no enforce limits in production
- return if Rails.env.production?
+ return if Rails.env.production? || ENV["GITALY_DISABLE_REQUEST_LIMITS"]
# Check if this call is nested within a allow_n_plus_1_calls
# block and skip check if it is
@@ -233,6 +233,8 @@ module Gitlab
end
def self.encode(s)
+ return "" if s.nil?
+
s.dup.force_encoding(Encoding::ASCII_8BIT)
end
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 36da63fd586..a2b50f2507e 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -274,7 +274,7 @@ module Gitlab
repository: @gitaly_repo,
left_commit_id: from_id,
right_commit_id: to_id,
- paths: options.fetch(:paths, []).map { |path| GitalyClient.encode(path) }
+ paths: options.fetch(:paths, []).compact.map { |path| GitalyClient.encode(path) }
}
end
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
new file mode 100644
index 00000000000..81ddaf13e10
--- /dev/null
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -0,0 +1,79 @@
+module Gitlab
+ module GitalyClient
+ class OperationService
+ def initialize(repository)
+ @gitaly_repo = repository.gitaly_repository
+ @repository = repository
+ end
+
+ def rm_tag(tag_name, user)
+ request = Gitaly::UserDeleteTagRequest.new(
+ repository: @gitaly_repo,
+ tag_name: GitalyClient.encode(tag_name),
+ user: Util.gitaly_user(user)
+ )
+
+ response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_tag, request)
+
+ if pre_receive_error = response.pre_receive_error.presence
+ raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error
+ end
+ end
+
+ def add_tag(tag_name, user, target, message)
+ request = Gitaly::UserCreateTagRequest.new(
+ repository: @gitaly_repo,
+ user: Util.gitaly_user(user),
+ tag_name: GitalyClient.encode(tag_name),
+ target_revision: GitalyClient.encode(target),
+ message: GitalyClient.encode(message.to_s)
+ )
+
+ response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request)
+ if pre_receive_error = response.pre_receive_error.presence
+ raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error
+ elsif response.exists
+ raise Gitlab::Git::Repository::TagExistsError
+ end
+
+ Util.gitlab_tag_from_gitaly_tag(@repository, response.tag)
+ rescue GRPC::FailedPrecondition => e
+ raise Gitlab::Git::Repository::InvalidRef, e
+ end
+
+ def user_create_branch(branch_name, user, start_point)
+ request = Gitaly::UserCreateBranchRequest.new(
+ repository: @gitaly_repo,
+ branch_name: GitalyClient.encode(branch_name),
+ user: Util.gitaly_user(user),
+ start_point: GitalyClient.encode(start_point)
+ )
+ response = GitalyClient.call(@repository.storage, :operation_service,
+ :user_create_branch, request)
+ if response.pre_receive_error.present?
+ raise Gitlab::Git::HooksService::PreReceiveError.new(response.pre_receive_error)
+ end
+
+ branch = response.branch
+ return nil unless branch
+
+ target_commit = Gitlab::Git::Commit.decorate(@repository, branch.target_commit)
+ Gitlab::Git::Branch.new(@repository, branch.name, target_commit.id, target_commit)
+ end
+
+ def user_delete_branch(branch_name, user)
+ request = Gitaly::UserDeleteBranchRequest.new(
+ repository: @gitaly_repo,
+ branch_name: GitalyClient.encode(branch_name),
+ user: Util.gitaly_user(user)
+ )
+
+ response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_branch, request)
+
+ if pre_receive_error = response.pre_receive_error.presence
+ raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index 8ef873d5848..8214b7d63fa 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -57,6 +57,14 @@ module Gitlab
branch_names.count
end
+ # TODO implement a more efficient RPC for this https://gitlab.com/gitlab-org/gitaly/issues/616
+ def has_local_branches?
+ request = Gitaly::FindAllBranchNamesRequest.new(repository: @gitaly_repo)
+ response = GitalyClient.call(@storage, :ref_service, :find_all_branch_names, request).first
+
+ response&.names.present?
+ end
+
def local_branches(sort_by: nil)
request = Gitaly::FindLocalBranchesRequest.new(repository: @gitaly_repo)
request.sort_by = sort_by_param(sort_by) if sort_by
@@ -155,19 +163,7 @@ module Gitlab
def consume_tags_response(response)
response.flat_map do |message|
- message.tags.map do |gitaly_tag|
- if gitaly_tag.target_commit.present?
- gitaly_commit = Gitlab::Git::Commit.decorate(@repository, gitaly_tag.target_commit)
- end
-
- Gitlab::Git::Tag.new(
- @repository,
- encode!(gitaly_tag.name.dup),
- gitaly_tag.id,
- gitaly_commit,
- encode!(gitaly_tag.message.chomp)
- )
- end
+ message.tags.map { |gitaly_tag| Util.gitlab_tag_from_gitaly_tag(@repository, gitaly_tag) }
end
end
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index 177a1284f38..fdf912214e0 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -53,6 +53,11 @@ module Gitlab
GitalyClient.call(@storage, :repository_service, :fetch_remote, request)
end
+
+ def create_repository
+ request = Gitaly::CreateRepositoryRequest.new(repository: @gitaly_repo)
+ GitalyClient.call(@storage, :repository_service, :create_repository, request)
+ end
end
end
end
diff --git a/lib/gitlab/gitaly_client/util.rb b/lib/gitlab/gitaly_client/util.rb
index 8fc937496af..da43c616b94 100644
--- a/lib/gitlab/gitaly_client/util.rb
+++ b/lib/gitlab/gitaly_client/util.rb
@@ -2,14 +2,39 @@ module Gitlab
module GitalyClient
module Util
class << self
- def repository(repository_storage, relative_path)
+ def repository(repository_storage, relative_path, gl_repository)
Gitaly::Repository.new(
storage_name: repository_storage,
relative_path: relative_path,
+ gl_repository: gl_repository,
git_object_directory: Gitlab::Git::Env['GIT_OBJECT_DIRECTORY'].to_s,
git_alternate_object_directories: Array.wrap(Gitlab::Git::Env['GIT_ALTERNATE_OBJECT_DIRECTORIES'])
)
end
+
+ def gitaly_user(gitlab_user)
+ return unless gitlab_user
+
+ Gitaly::User.new(
+ gl_id: Gitlab::GlId.gl_id(gitlab_user),
+ name: GitalyClient.encode(gitlab_user.name),
+ email: GitalyClient.encode(gitlab_user.email)
+ )
+ end
+
+ def gitlab_tag_from_gitaly_tag(repository, gitaly_tag)
+ if gitaly_tag.target_commit.present?
+ commit = Gitlab::Git::Commit.decorate(repository, gitaly_tag.target_commit)
+ end
+
+ Gitlab::Git::Tag.new(
+ repository,
+ Gitlab::EncodingHelper.encode!(gitaly_tag.name.dup),
+ gitaly_tag.id,
+ commit,
+ Gitlab::EncodingHelper.encode!(gitaly_tag.message.chomp)
+ )
+ end
end
end
end
diff --git a/lib/gitlab/kubernetes.rb b/lib/gitlab/kubernetes.rb
index cdbdfa10d0e..da43bd0af4b 100644
--- a/lib/gitlab/kubernetes.rb
+++ b/lib/gitlab/kubernetes.rb
@@ -113,7 +113,7 @@ module Gitlab
def kubeconfig_embed_ca_pem(config, ca_pem)
cluster = config.dig(:clusters, 0, :cluster)
- cluster[:'certificate-authority-data'] = Base64.encode64(ca_pem)
+ cluster[:'certificate-authority-data'] = Base64.strict_encode64(ca_pem)
end
end
end
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index cd7e4ca7b7e..0afaa2306b5 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -22,8 +22,8 @@ module Gitlab
Gitlab::LDAP::Config.new(provider)
end
- def users(field, value, limit = nil)
- options = user_options(field, value, limit)
+ def users(fields, value, limit = nil)
+ options = user_options(Array(fields), value, limit)
entries = ldap_search(options).select do |entry|
entry.respond_to? config.uid
@@ -72,20 +72,24 @@ module Gitlab
private
- def user_options(field, value, limit)
- options = { attributes: Gitlab::LDAP::Person.ldap_attributes(config).compact.uniq }
+ def user_options(fields, value, limit)
+ options = {
+ attributes: Gitlab::LDAP::Person.ldap_attributes(config).compact.uniq,
+ base: config.base
+ }
+
options[:size] = limit if limit
- if field.to_sym == :dn
+ if fields.include?('dn')
+ raise ArgumentError, 'It is not currently possible to search the DN and other fields at the same time.' if fields.size > 1
+
options[:base] = value
options[:scope] = Net::LDAP::SearchScope_BaseObject
- options[:filter] = user_filter
else
- options[:base] = config.base
- options[:filter] = user_filter(Net::LDAP::Filter.eq(field, value))
+ filter = fields.map { |field| Net::LDAP::Filter.eq(field, value) }.inject(:|)
end
- options
+ options.merge(filter: user_filter(filter))
end
def user_filter(filter = nil)
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 4d6f8ac79de..9a6f7827b16 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -17,6 +17,12 @@ module Gitlab
adapter.user('dn', dn)
end
+ def self.find_by_email(email, adapter)
+ email_fields = adapter.config.attributes['email']
+
+ adapter.user(email_fields, email)
+ end
+
def self.disabled_via_active_directory?(dn, adapter)
adapter.dn_matches_filter?(dn, AD_USER_DISABLED)
end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index 3bf27b37ae6..1793097363e 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -17,41 +17,19 @@ module Gitlab
end
end
- def initialize(auth_hash)
- super
- update_user_attributes
- end
-
def save
super('LDAP')
end
# instance methods
- def gl_user
- @gl_user ||= find_by_uid_and_provider || find_by_email || build_new_user
+ def find_user
+ find_by_uid_and_provider || find_by_email || build_new_user
end
def find_by_uid_and_provider
self.class.find_by_uid_and_provider(auth_hash.uid, auth_hash.provider)
end
- def find_by_email
- ::User.find_by(email: auth_hash.email.downcase) if auth_hash.has_attribute?(:email)
- end
-
- def update_user_attributes
- if persisted?
- # find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved.
- identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider }
- identity ||= gl_user.identities.build(provider: auth_hash.provider)
-
- # For a new identity set extern_uid to the LDAP DN
- # For an existing identity with matching email but changed DN, update the DN.
- # For an existing identity with no change in DN, this line changes nothing.
- identity.extern_uid = auth_hash.uid
- end
- end
-
def changed?
gl_user.changed? || gl_user.identities.any?(&:changed?)
end
diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb
index e06d4dc45f7..68815be4d13 100644
--- a/lib/gitlab/o_auth/user.rb
+++ b/lib/gitlab/o_auth/user.rb
@@ -13,6 +13,7 @@ module Gitlab
def initialize(auth_hash)
self.auth_hash = auth_hash
update_profile if sync_profile_from_provider?
+ add_or_update_user_identities
end
def persisted?
@@ -44,47 +45,54 @@ module Gitlab
end
def gl_user
- @user ||= find_by_uid_and_provider
+ return @gl_user if defined?(@gl_user)
- if auto_link_ldap_user?
- @user ||= find_or_create_ldap_user
- end
+ @gl_user = find_user
+ end
- if signup_enabled?
- @user ||= build_new_user
- end
+ def find_user
+ user = find_by_uid_and_provider
- if external_provider? && @user
- @user.external = true
- end
+ user ||= find_or_build_ldap_user if auto_link_ldap_user?
+ user ||= build_new_user if signup_enabled?
+
+ user.external = true if external_provider? && user
- @user
+ user
end
protected
- def find_or_create_ldap_user
+ def add_or_update_user_identities
+ # find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved.
+ identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider }
+
+ identity ||= gl_user.identities.build(provider: auth_hash.provider)
+ identity.extern_uid = auth_hash.uid
+
+ if auto_link_ldap_user? && !gl_user.ldap_user? && ldap_person
+ log.info "Correct LDAP account has been found. identity to user: #{gl_user.username}."
+ gl_user.identities.build(provider: ldap_person.provider, extern_uid: ldap_person.dn)
+ end
+ end
+
+ def find_or_build_ldap_user
return unless ldap_person
- # If a corresponding person exists with same uid in a LDAP server,
- # check if the user already has a GitLab account.
user = Gitlab::LDAP::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider)
if user
- # Case when a LDAP user already exists in Gitlab. Add the OAuth identity to existing account.
log.info "LDAP account found for user #{user.username}. Building new #{auth_hash.provider} identity."
- user.identities.find_or_initialize_by(extern_uid: auth_hash.uid, provider: auth_hash.provider)
- else
- log.info "No existing LDAP account was found in GitLab. Checking for #{auth_hash.provider} account."
- user = find_by_uid_and_provider
- if user.nil?
- log.info "No user found using #{auth_hash.provider} provider. Creating a new one."
- user = build_new_user
- end
- log.info "Correct account has been found. Adding LDAP identity to user: #{user.username}."
- user.identities.new(provider: ldap_person.provider, extern_uid: ldap_person.dn)
+ return user
end
- user
+ log.info "No user found using #{auth_hash.provider} provider. Creating a new one."
+ build_new_user
+ end
+
+ def find_by_email
+ return unless auth_hash.has_attribute?(:email)
+
+ ::User.find_by(email: auth_hash.email.downcase)
end
def auto_link_ldap_user?
@@ -108,9 +116,9 @@ module Gitlab
end
def find_ldap_person(auth_hash, adapter)
- by_uid = Gitlab::LDAP::Person.find_by_uid(auth_hash.uid, adapter)
- # The `uid` might actually be a DN. Try it next.
- by_uid || Gitlab::LDAP::Person.find_by_dn(auth_hash.uid, adapter)
+ Gitlab::LDAP::Person.find_by_uid(auth_hash.uid, adapter) ||
+ Gitlab::LDAP::Person.find_by_email(auth_hash.uid, adapter) ||
+ Gitlab::LDAP::Person.find_by_dn(auth_hash.uid, adapter)
end
def ldap_config
@@ -152,7 +160,7 @@ module Gitlab
end
def build_new_user
- user_params = user_attributes.merge(extern_uid: auth_hash.uid, provider: auth_hash.provider, skip_confirmation: true)
+ user_params = user_attributes.merge(skip_confirmation: true)
Users::BuildService.new(nil, user_params).execute(skip_authorization: true)
end
diff --git a/lib/gitlab/saml/user.rb b/lib/gitlab/saml/user.rb
index 0f323a9e8b2..e0a9d1dee77 100644
--- a/lib/gitlab/saml/user.rb
+++ b/lib/gitlab/saml/user.rb
@@ -10,41 +10,20 @@ module Gitlab
super('SAML')
end
- def gl_user
- if auto_link_ldap_user?
- @user ||= find_or_create_ldap_user
- end
-
- @user ||= find_by_uid_and_provider
-
- if auto_link_saml_user?
- @user ||= find_by_email
- end
+ def find_user
+ user = find_by_uid_and_provider
- if signup_enabled?
- @user ||= build_new_user
- end
+ user ||= find_by_email if auto_link_saml_user?
+ user ||= find_or_build_ldap_user if auto_link_ldap_user?
+ user ||= build_new_user if signup_enabled?
- if external_users_enabled? && @user
+ if external_users_enabled? && user
# Check if there is overlap between the user's groups and the external groups
# setting then set user as external or internal.
- @user.external =
- if (auth_hash.groups & Gitlab::Saml::Config.external_groups).empty?
- false
- else
- true
- end
+ user.external = !(auth_hash.groups & Gitlab::Saml::Config.external_groups).empty?
end
- @user
- end
-
- def find_by_email
- if auth_hash.has_attribute?(:email)
- user = ::User.find_by(email: auth_hash.email.downcase)
- user.identities.new(extern_uid: auth_hash.uid, provider: auth_hash.provider) if user
- user
- end
+ user
end
def changed?
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 81ecdf43ef9..a99f8e2b5f8 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -65,7 +65,7 @@ module Gitlab
# Init new repository
#
- # storage - project's storage path
+ # storage - project's storage name
# name - project path with namespace
#
# Ex.
@@ -73,7 +73,19 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def add_repository(storage, name)
- Gitlab::Git::Repository.create(storage, name, bare: true, symlink_hooks_to: gitlab_shell_hooks_path)
+ relative_path = name.dup
+ relative_path << '.git' unless relative_path.end_with?('.git')
+
+ gitaly_migrate(:create_repository) do |is_enabled|
+ if is_enabled
+ repository = Gitlab::Git::Repository.new(storage, relative_path, '')
+ repository.gitaly_repository_client.create_repository
+ true
+ else
+ repo_path = File.join(Gitlab.config.repositories.storages[storage]['path'], relative_path)
+ Gitlab::Git::Repository.create(repo_path, bare: true, symlink_hooks_to: gitlab_shell_hooks_path)
+ end
+ end
rescue => err
Rails.logger.error("Failed to add repository #{storage}/#{name}: #{err}")
false
diff --git a/lib/gitlab/sidekiq_middleware/memory_killer.rb b/lib/gitlab/sidekiq_middleware/memory_killer.rb
index 104280f520a..d7d24eeb37b 100644
--- a/lib/gitlab/sidekiq_middleware/memory_killer.rb
+++ b/lib/gitlab/sidekiq_middleware/memory_killer.rb
@@ -25,7 +25,7 @@ module Gitlab
Sidekiq.logger.warn "current RSS #{current_rss} exceeds maximum RSS "\
"#{MAX_RSS}"
- Sidekiq.logger.warn "this thread will shut down PID #{Process.pid} - Worker #{worker.class} - JID-#{job['jid']}"\
+ Sidekiq.logger.warn "this thread will shut down PID #{Process.pid} - Worker #{worker.class} - JID-#{job['jid']} "\
"in #{GRACE_TIME} seconds"
sleep(GRACE_TIME)
diff --git a/lib/gitlab/sql/union.rb b/lib/gitlab/sql/union.rb
index 222021e8802..f30c771837a 100644
--- a/lib/gitlab/sql/union.rb
+++ b/lib/gitlab/sql/union.rb
@@ -12,8 +12,9 @@ module Gitlab
#
# Project.where("id IN (#{sql})")
class Union
- def initialize(relations)
+ def initialize(relations, remove_duplicates: true)
@relations = relations
+ @remove_duplicates = remove_duplicates
end
def to_sql
@@ -25,7 +26,11 @@ module Gitlab
@relations.map { |rel| rel.reorder(nil).to_sql }.reject(&:blank?)
end
- fragments.join("\nUNION\n")
+ fragments.join("\n#{union_keyword}\n")
+ end
+
+ def union_keyword
+ @remove_duplicates ? 'UNION' : 'UNION ALL'
end
end
end
diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb
index 4e1ec1402ea..1caa791c1be 100644
--- a/lib/gitlab/url_sanitizer.rb
+++ b/lib/gitlab/url_sanitizer.rb
@@ -1,7 +1,9 @@
module Gitlab
class UrlSanitizer
+ ALLOWED_SCHEMES = %w[http https ssh git].freeze
+
def self.sanitize(content)
- regexp = URI::Parser.new.make_regexp(%w(http https ssh git))
+ regexp = URI::Parser.new.make_regexp(ALLOWED_SCHEMES)
content.gsub(regexp) { |url| new(url).masked_url }
rescue Addressable::URI::InvalidURIError
@@ -11,9 +13,9 @@ module Gitlab
def self.valid?(url)
return false unless url.present?
- Addressable::URI.parse(url.strip)
+ uri = Addressable::URI.parse(url.strip)
- true
+ ALLOWED_SCHEMES.include?(uri.scheme)
rescue Addressable::URI::InvalidURIError
false
end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 17550cf9074..f200c694562 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -22,9 +22,9 @@ module Gitlab
params = {
GL_ID: Gitlab::GlId.gl_id(user),
GL_REPOSITORY: Gitlab::GlRepository.gl_repository(project, is_wiki),
+ GL_USERNAME: user&.username,
RepoPath: repo_path
}
-
server = {
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
@@ -89,6 +89,13 @@ module Gitlab
params = repository.archive_metadata(ref, Gitlab.config.gitlab.repository_downloads_path, format)
raise "Repository or ref not found" if params.empty?
+ if Gitlab::GitalyClient.feature_enabled?(:workhorse_archive)
+ params.merge!(
+ 'GitalyServer' => gitaly_server_hash(repository),
+ 'GitalyRepository' => repository.gitaly_repository.to_h
+ )
+ end
+
[
SEND_DATA_HEADER,
"git-archive:#{encode(params)}"
diff --git a/lib/system_check/app/git_user_default_ssh_config_check.rb b/lib/system_check/app/git_user_default_ssh_config_check.rb
index 7b486d78cf0..dfa8b8b3f5b 100644
--- a/lib/system_check/app/git_user_default_ssh_config_check.rb
+++ b/lib/system_check/app/git_user_default_ssh_config_check.rb
@@ -5,6 +5,7 @@ module SystemCheck
# whitelisted as it may change the SSH client's behaviour dramatically.
WHITELIST = %w[
authorized_keys
+ authorized_keys.lock
authorized_keys2
known_hosts
].freeze
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
index 259a755d724..a42f02a84fd 100644
--- a/lib/tasks/gitlab/assets.rake
+++ b/lib/tasks/gitlab/assets.rake
@@ -3,8 +3,8 @@ namespace :gitlab do
desc 'GitLab | Assets | Compile all frontend assets'
task compile: [
'yarn:check',
- 'rake:assets:precompile',
'gettext:po_to_json',
+ 'rake:assets:precompile',
'webpack:compile',
'fix_urls'
]
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index 42825f29e32..0e6aed32c52 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -79,7 +79,7 @@ namespace :gitlab do
if File.exist?(path_to_repo)
print '-'
else
- if Gitlab::Shell.new.add_repository(project.repository_storage_path,
+ if Gitlab::Shell.new.add_repository(project.repository_storage,
project.disk_path)
print '.'
else
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index 9d90f4ed5b1..38d63315fdc 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:22-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:45-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Bulgarian\n"
"Language: bg_BG\n"
@@ -29,6 +29,9 @@ msgstr[1] "%s Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð±Ñха пропуÑнати, за да не Ñ
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} подаде %{commit_timeago}"
+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 ""
@@ -51,6 +54,9 @@ msgid_plural "%d pipelines"
msgstr[0] "1 Ñхема"
msgstr[1] "%d Ñхеми"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Ðабор от графики отноÑно непрекъÑнатата интеграциÑ"
@@ -93,7 +99,7 @@ msgstr "ДобавÑне на нова папка"
msgid "All"
msgstr ""
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
@@ -117,10 +123,34 @@ msgstr ""
msgid "Are you sure?"
msgstr ""
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Прикачете файл чрез влачене и пуÑкане или %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -177,6 +207,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Клон"
@@ -194,6 +227,90 @@ 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 "Преглед на папката"
@@ -337,9 +454,6 @@ msgstr "Подадено от"
msgid "Compare"
msgstr "Сравнение"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "РъководÑтво за ÑътрудничеÑтво"
@@ -489,6 +603,9 @@ msgstr "Редактиране на плана %{id} за Ñхема"
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -516,6 +633,9 @@ msgstr "Ð’Ñеки меÑец (на 1-во чиÑло, в 4 ч. Ñутринта
msgid "Every week (Sundays at 4:00am)"
msgstr "Ð’ÑÑка Ñедмица (в неделÑ, в 4 ч. Ñутринта)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "СобÑтвеникът не може да бъде променен"
@@ -572,7 +692,28 @@ msgstr "Към Вашето разклонение"
msgid "GoToYourFork|Fork"
msgstr "Разклонение"
-msgid "Group overview"
+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 "Health Check"
@@ -593,12 +734,6 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
-msgid "Home"
-msgstr "Ðачало"
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "ОÑвежаването започна уÑпешно"
@@ -620,6 +755,9 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Изключено"
@@ -684,6 +822,9 @@ msgstr ""
msgid "Merge events"
msgstr ""
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -812,6 +953,18 @@ msgstr ""
msgid "Owner"
msgstr "СобÑтвеник"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -917,10 +1070,7 @@ msgstr "Ñ ÐµÑ‚Ð°Ð¿Ð¸"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -953,12 +1103,6 @@ msgstr "Връзката към изнеÑените данни на проекÑ
msgid "Project export started. A download link will be sent by email."
msgstr "ИзнаÑÑнето на проекта започна. Ще получите връзка към данните по е-поща."
-msgid "Project home"
-msgstr "Ðачална Ñтраница на проекта"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -983,27 +1127,30 @@ msgstr "Етап"
msgid "ProjectNetworkGraph|Graph"
msgstr "Графика"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -1019,6 +1166,9 @@ msgstr "Клонове"
msgid "RefSwitcher|Tags"
msgstr "Етикети"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "Свързани подаваниÑ"
@@ -1073,6 +1223,9 @@ msgstr "Запазване на плана за Ñхема"
msgid "Schedule a new pipeline"
msgstr "Създаване на нов план за Ñхема"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "Планиране на Ñхемите"
@@ -1112,6 +1265,12 @@ msgstr "зададете парола"
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Показване на %d Ñъбитие"
@@ -1120,6 +1279,102 @@ msgstr[1] "Показване на %d ÑъбитиÑ"
msgid "Snippets"
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 code"
msgstr "Изходен код"
@@ -1132,6 +1387,9 @@ msgstr ""
msgid "StarProject|Star"
msgstr "Звезда"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "Създайте %{new_merge_request} Ñ Ñ‚ÐµÐ·Ð¸ промени"
@@ -1141,6 +1399,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Преминаване към клон/етикет"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "Етикет"
@@ -1206,6 +1467,9 @@ msgstr "СтойноÑтта, коÑто Ñе намира в Ñредата нÐ
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "Това означава, че нÑма да можете да изпращате код, докато не Ñъздадете празно хранилище или не внеÑете ÑъщеÑтвуващо такова."
@@ -1381,9 +1645,15 @@ msgstr ""
msgid "Use your global notification setting"
msgstr "Използване на глобалната Ви наÑтройка за извеÑтиÑта"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "Преглед на отворената заÑвка за Ñливане"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Вътрешен"
@@ -1456,6 +1726,12 @@ msgstr "ÐÑма да можете да изтеглÑте или изпраща
msgid "Your name"
msgstr "Вашето име"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "ден"
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index 19961043ede..fc3c60166b7 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:22-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:45-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: German\n"
"Language: de_DE\n"
@@ -18,8 +18,8 @@ msgstr ""
msgid "%d commit"
msgid_plural "%d commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d Commit"
+msgstr[1] "%d Commits"
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
@@ -27,6 +27,9 @@ msgstr[0] "%s zusätzlicher Commit wurde ausgelassen um Leistungsprobleme zu ver
msgstr[1] "%s zusätzliche Commits wurden ausgelassen um Leistungsprobleme zu verhindern."
msgid "%{commit_author_link} committed %{commit_timeago}"
+msgstr "%{commit_author_link} hat %{commit_timeago} committet"
+
+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."
@@ -40,8 +43,8 @@ msgstr "%{number_of_failures} von %{maximum_failures} Fehlschlägen. GitLab wird
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{storage_name}: fehlgeschlagener Speicherzugriff auf Host:"
+msgstr[1] "%{storage_name}: %{failed_attempts} fehlgeschlagene Speicherzugriffe:"
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(beachte die Informationen zur Installation auf %{link})."
@@ -51,6 +54,9 @@ msgid_plural "%d pipelines"
msgstr[0] ""
msgstr[1] ""
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Eine Sammlung von Graphen bezüglich kontinuierlicher Integration"
@@ -67,13 +73,13 @@ msgid "Access to failing storages has been temporarily disabled to allow the mou
msgstr "Zugriff auf fehlerhafte Speicher wurde vorübergehend deaktiviert, um die Wiederherstellung zu ermöglichen. Für den zukünftigen Zugriff, behebe bitte das Problem und setze danach die Speicherinformationen zurück."
msgid "Account"
-msgstr ""
+msgstr "Konto"
msgid "Active"
msgstr "Aktiv"
msgid "Activity"
-msgstr ""
+msgstr "Aktivität"
msgid "Add Changelog"
msgstr "Änderungsliste hinzufügen "
@@ -93,8 +99,8 @@ msgstr "Erstelle eine neues Verzeichnis"
msgid "All"
msgstr "Alle"
-msgid "Appearances"
-msgstr "Erscheinungsbild"
+msgid "Appearance"
+msgstr ""
msgid "Applications"
msgstr "Anwendungen"
@@ -117,10 +123,34 @@ msgstr "Bist Du sicher, dass Du den Systemüberwachungstoken zurücksetzen wills
msgid "Are you sure?"
msgstr "Bist Du sicher?"
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Datei mittels Drag &amp; Drop oder %{upload_link} hinzufügen"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -177,10 +207,13 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Zweig"
+msgstr[1] "Zweige"
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}"
@@ -194,6 +227,90 @@ msgstr "Branch wechseln"
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 "Verzeichnisse durchsuchen"
@@ -210,7 +327,7 @@ msgid "ByAuthor|by"
msgstr "von"
msgid "CI / CD"
-msgstr ""
+msgstr "CI / CD"
msgid "CI configuration"
msgstr "CI-Konfiguration"
@@ -240,7 +357,7 @@ msgid "Charts"
msgstr "Diagramme"
msgid "Chat"
-msgstr ""
+msgstr "Chat"
msgid "Cherry-pick this commit"
msgstr "Diesen Commit herauspicken "
@@ -307,8 +424,8 @@ msgstr "Kommentare"
msgid "Commit"
msgid_plural "Commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Commit"
+msgstr[1] "Commits"
msgid "Commit duration in minutes for last 30 commits"
msgstr "Dauer der Commits in Minuten für die letzten 30 Commits"
@@ -323,7 +440,7 @@ msgid "CommitMessage|Add %{file_name}"
msgstr "%{file_name} hinzufügen"
msgid "Commits"
-msgstr ""
+msgstr "Commits"
msgid "Commits feed"
msgstr "Liste der Commits"
@@ -337,9 +454,6 @@ msgstr "Committed von"
msgid "Compare"
msgstr "Vergleichen"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "Mitarbeitsanleitung"
@@ -442,7 +556,7 @@ msgid "Description"
msgstr "Beschreibung"
msgid "Details"
-msgstr ""
+msgstr "Details"
msgid "Directory name"
msgstr "Verzeichnisname"
@@ -489,6 +603,9 @@ msgstr "Pipeline Zeitplan bearbeiten %{id}"
msgid "Emails"
msgstr "E-Mails"
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "Filtere alle"
@@ -516,6 +633,9 @@ msgstr "Monatlich (am Ersten um 4:00 Uhr)"
msgid "Every week (Sundays at 4:00am)"
msgstr "Wöchentlich (Sonntags um 4:00 Uhr)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Wechsel des Besitzers fehlgeschlagen"
@@ -572,8 +692,29 @@ msgstr "Gehe zu Deinem Ableger"
msgid "GoToYourFork|Fork"
msgstr "Ableger"
-msgid "Group overview"
-msgstr "Gruppen-Ãœbersicht"
+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 "Health Check"
msgstr "Systemzustand"
@@ -593,12 +734,6 @@ msgstr "Keine Probleme erkannt"
msgid "HealthCheck|Unhealthy"
msgstr "Problematisch"
-msgid "Home"
-msgstr "Startseite"
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "Aufräumen erfolgreich gestartet"
@@ -620,6 +755,9 @@ msgstr "Ticketereignisse"
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Deaktiviert"
@@ -662,7 +800,7 @@ msgid "Leave project"
msgstr "Verlasse das Projekt"
msgid "License"
-msgstr "Lizenz"
+msgstr ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
@@ -670,7 +808,7 @@ msgstr[0] "Limitiere die Anzeige auf höchstens %d Ereignis"
msgstr[1] "Limitiere die Anzeige auf höchstens %d Ereignisse"
msgid "Locked Files"
-msgstr "Gesperrte Dateien"
+msgstr ""
msgid "Median"
msgstr "Median"
@@ -684,14 +822,17 @@ msgstr ""
msgid "Merge events"
msgstr "Ereignisse zusammenführen"
-msgid "Messages"
+msgid "Merge request"
msgstr ""
+msgid "Messages"
+msgstr "Nachrichten"
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "einen SSH Schlüssel hinzufügst"
msgid "Monitoring"
-msgstr ""
+msgstr "Ãœberwachung"
msgid "More information is available|here"
msgstr "hier"
@@ -812,6 +953,18 @@ msgstr "Ãœbersicht"
msgid "Owner"
msgstr "Besitzer"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr "Passwort"
@@ -900,7 +1053,7 @@ msgid "Pipelines for last week"
msgstr ""
msgid "Pipelines for last year"
-msgstr ""
+msgstr "Pipelines des letzten Jahres"
msgid "Pipeline|all"
msgstr "Alle"
@@ -917,12 +1070,9 @@ msgstr "mit Stages"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
+msgid "Profile"
msgstr ""
-msgid "Project"
-msgstr "Projekt"
-
msgid "Project '%{project_name}' queued for deletion."
msgstr "Das Projekt '%{project_name}' wurde zur Löschung eingeplant."
@@ -953,12 +1103,6 @@ msgstr "Der Link für den Export des Projektes ist abgelaufen. Bitte generiere e
msgid "Project export started. A download link will be sent by email."
msgstr "Export des Projektes gestartet. Ein Link zum herunterladen wir Dir per E-Mail zugesandt."
-msgid "Project home"
-msgstr "Startseite des Projektes"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr "Abonnieren"
@@ -983,27 +1127,30 @@ msgstr "Stage"
msgid "ProjectNetworkGraph|Graph"
msgstr "Diagramm"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr ""
-
msgid "ProjectsDropdown|Projects you visit often will appear here"
-msgstr ""
+msgstr "ProjectsDropdown | Projekte, die Sie häufig besuchen, werden hier angezeigt"
msgid "ProjectsDropdown|Search your projects"
msgstr ""
-msgid "ProjectsDropdown|Something went wrong on our end"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr "Ãœbertragungsereignisse"
@@ -1019,6 +1166,9 @@ msgstr "Branches"
msgid "RefSwitcher|Tags"
msgstr "Tags"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "Zugehörige Commits"
@@ -1065,7 +1215,7 @@ msgid "Revert this merge request"
msgstr "Merge Request zurücksetzen"
msgid "SSH Keys"
-msgstr ""
+msgstr "SSH-Schlüssel"
msgid "Save pipeline schedule"
msgstr "Zeitplan der Pipeline speichern"
@@ -1073,6 +1223,9 @@ msgstr "Zeitplan der Pipeline speichern"
msgid "Schedule a new pipeline"
msgstr "Plane eine neue Pipeline"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "Pipelines planen"
@@ -1110,6 +1263,12 @@ msgid "SetPasswordToCloneLink|set a password"
msgstr "ein Passwort festlegst"
msgid "Settings"
+msgstr "Einstellungen"
+
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
msgstr ""
msgid "Showing %d event"
@@ -1120,11 +1279,107 @@ msgstr[1] "Zeige %d Ereignisse"
msgid "Snippets"
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 code"
msgstr "Quellcode"
msgid "Spam Logs"
-msgstr ""
+msgstr "Spam-Protokolle"
msgid "Specify the following URL during the Runner setup:"
msgstr "Lege die folgende URL während des Runner Setups fest:"
@@ -1132,6 +1387,9 @@ msgstr "Lege die folgende URL während des Runner Setups fest:"
msgid "StarProject|Star"
msgstr "Favorisieren"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "Beginne einen %{new_merge_request} mit diesen Änderungen"
@@ -1141,6 +1399,9 @@ msgstr "Starte den Runner!"
msgid "Switch branch/tag"
msgstr "Zu Branch/Tag wechseln"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] ""
@@ -1206,6 +1467,9 @@ msgstr "Der mittlere aller erfassten Werte. Zum Beispiel ist für 3, 5, 9 der Me
msgid "There are problems accessing Git storage: "
msgstr "Es gibt ein Problem beim Zugriff auf den Gitspeicher:"
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "Dies bedeutet, dass Du keinen Code übertragen kannst, bevor Du kein leeres Repositorium erstellt oder ein Existierendes importiert hast."
@@ -1222,7 +1486,7 @@ msgid "Time until first merge request"
msgstr "Zeit bis zum ersten Merge Request"
msgid "Timeago|%s days ago"
-msgstr "seit %s Tagen"
+msgstr ""
msgid "Timeago|%s days remaining"
msgstr "%s Tage verbleibend"
@@ -1231,13 +1495,13 @@ msgid "Timeago|%s hours remaining"
msgstr "%s Stunden verbleibend"
msgid "Timeago|%s minutes ago"
-msgstr "seit %s Minuten "
+msgstr ""
msgid "Timeago|%s minutes remaining"
msgstr "%s Minuten verbleibend"
msgid "Timeago|%s months ago"
-msgstr "seit %s Monaten"
+msgstr ""
msgid "Timeago|%s months remaining"
msgstr "%s Monate verbleibend"
@@ -1246,13 +1510,13 @@ msgid "Timeago|%s seconds remaining"
msgstr "%s Sekunden verbleibend"
msgid "Timeago|%s weeks ago"
-msgstr "seit %s Wochen"
+msgstr ""
msgid "Timeago|%s weeks remaining"
msgstr "%s Wochen verbleibend"
msgid "Timeago|%s years ago"
-msgstr "seit %s Jahren"
+msgstr ""
msgid "Timeago|%s years remaining"
msgstr "%s Jahre verbleibend"
@@ -1381,9 +1645,15 @@ msgstr "Benutze den folgenden Registrierungstoken während des Setups:"
msgid "Use your global notification setting"
msgstr "Benutze Deine globalen Benachrichtigungseinstellungen"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "Zeige offene Merge Requests."
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Intern"
@@ -1456,6 +1726,12 @@ msgstr "Du kannst erst mittels SSH übertragen (push) oder abrufen (pull), nachd
msgid "Your name"
msgstr "Dein Name"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "Tag"
diff --git a/locale/en/gitlab.po b/locale/en/gitlab.po
index 0ac591d4927..b50685514e1 100644
--- a/locale/en/gitlab.po
+++ b/locale/en/gitlab.po
@@ -1057,7 +1057,7 @@ msgstr ""
msgid "Timeago|a week ago"
msgstr ""
-msgid "Timeago|a while"
+msgid "Timeago|in a while"
msgstr ""
msgid "Timeago|a year ago"
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index f9f61a109f6..e8c2195e4e3 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:22-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:45-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Esperanto\n"
"Language: eo_UY\n"
@@ -29,6 +29,9 @@ msgstr[1] "%s enmetadoj estis transsaltitaj, por ne troÅarÄi la sistemon."
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} enmetis %{commit_timeago}"
+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 ""
@@ -51,6 +54,9 @@ msgid_plural "%d pipelines"
msgstr[0] "1 ĉenstablo"
msgstr[1] "%d ĉenstabloj"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Aro da diagramoj pri la seninterrompa integrado"
@@ -93,7 +99,7 @@ msgstr "Aldoni novan dosierujon"
msgid "All"
msgstr ""
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
@@ -117,10 +123,34 @@ msgstr ""
msgid "Are you sure?"
msgstr ""
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Alkroĉu dosieron per Åovmetado aÅ­ %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -177,6 +207,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Branĉo"
@@ -194,6 +227,90 @@ msgstr "Iri al branĉo"
msgid "Branches"
msgstr "Branĉoj"
+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 "Foliumi dosierujon"
@@ -337,9 +454,6 @@ msgstr "Enmetita de"
msgid "Compare"
msgstr "Kompari"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "Gvidlinioj por kontribuado"
@@ -489,6 +603,9 @@ msgstr "Redakti ĉenstablan planon %{id}"
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -516,6 +633,9 @@ msgstr "Ĉiumonate (en la 1a de la monato, je 4:00)"
msgid "Every week (Sundays at 4:00am)"
msgstr "Ĉiusemajne (en dimanĉo, je 4:00)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Ne eblas ÅanÄi la posedanton"
@@ -572,7 +692,28 @@ msgstr "Al via disbranĉigo"
msgid "GoToYourFork|Fork"
msgstr "Disbranĉigo"
-msgid "Group overview"
+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 "Health Check"
@@ -593,12 +734,6 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
-msgid "Home"
-msgstr "Hejmo"
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "La refreÅigo komenciÄis sukcese"
@@ -620,6 +755,9 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "MalÅaltita"
@@ -684,6 +822,9 @@ msgstr ""
msgid "Merge events"
msgstr ""
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -812,6 +953,18 @@ msgstr ""
msgid "Owner"
msgstr "Posedanto"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -917,10 +1070,7 @@ msgstr "kun etapoj"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -953,12 +1103,6 @@ msgstr "La ligilo por la projekta elporto eksvalidiÄis. Bonvolu krei novan elpo
msgid "Project export started. A download link will be sent by email."
msgstr "La elporto de la projekto komenciÄis. Vi ricevos ligilon per retpoÅto por elÅuti la datenoj."
-msgid "Project home"
-msgstr "Hejmo de la projekto"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -983,27 +1127,30 @@ msgstr "Etapo"
msgid "ProjectNetworkGraph|Graph"
msgstr "Grafeo"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -1019,6 +1166,9 @@ msgstr "Branĉoj"
msgid "RefSwitcher|Tags"
msgstr "Etikedoj"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "Rilataj enmetadoj"
@@ -1073,6 +1223,9 @@ msgstr "Konservi ĉenstablan planon"
msgid "Schedule a new pipeline"
msgstr "Plani novan ĉenstablon"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "Planado de la ĉenstabloj"
@@ -1112,6 +1265,12 @@ msgstr "kreos pasvorton"
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Estas montrata %d evento"
@@ -1120,6 +1279,102 @@ msgstr[1] "Estas montrataj %d eventoj"
msgid "Snippets"
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 code"
msgstr "Kodo"
@@ -1132,6 +1387,9 @@ msgstr ""
msgid "StarProject|Star"
msgstr "Steligi"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "Kreu %{new_merge_request} kun ĉi tiuj ÅanÄoj"
@@ -1141,6 +1399,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Iri al branĉo/etikedo"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "Etikedo"
@@ -1206,6 +1467,9 @@ msgstr "La valoro, kiu troviÄas en la mezo de aro da rigardataj valoroj. Ekzemp
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "Ĉi tiu signifas, ke vi ne povos alpuÅi kodon, antaÅ­ ol vi kreos malplenan deponejon aÅ­ enportos jam ekzistantan."
@@ -1381,9 +1645,15 @@ msgstr ""
msgid "Use your global notification setting"
msgstr "Uzi vian Äeneralan agordon pri la sciigoj"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "Vidi la malfermitan peton pri kunfando"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Interna"
@@ -1456,6 +1726,12 @@ msgstr "Vi ne povos eltiri aÅ­ alpuÅi kodon per SSH antaÅ­ ol vi %{add_ssh_key_
msgid "Your name"
msgstr "Via nomo"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "tago"
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index ccf4b0abf9f..29a010f9428 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:19-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:43-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Spanish\n"
"Language: es_ES\n"
@@ -29,6 +29,9 @@ msgstr[1] "%s cambios adicionales han sido omitidos para evitar problemas de ren
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} cambió %{commit_timeago}"
+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 ""
@@ -51,6 +54,9 @@ msgid_plural "%d pipelines"
msgstr[0] ""
msgstr[1] ""
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Una colección de gráficos sobre Integración Continua"
@@ -93,7 +99,7 @@ msgstr "Agregar nuevo directorio"
msgid "All"
msgstr ""
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
@@ -117,10 +123,34 @@ msgstr ""
msgid "Are you sure?"
msgstr ""
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Adjunte un archivo arrastrando &amp; soltando o %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -177,6 +207,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Rama"
@@ -194,6 +227,90 @@ msgstr "Cambiar rama"
msgid "Branches"
msgstr "Ramas"
+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 "Examinar directorio"
@@ -337,9 +454,6 @@ msgstr "Enviado por"
msgid "Compare"
msgstr "Comparar"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "Guía de contribución"
@@ -489,6 +603,9 @@ msgstr "Editar Programación del Pipeline %{id}"
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -516,6 +633,9 @@ msgstr "Todos los meses (el día 1 a las 4:00 am)"
msgid "Every week (Sundays at 4:00am)"
msgstr "Todas las semanas (domingos a las 4:00 am)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Error al cambiar el propietario"
@@ -572,7 +692,28 @@ msgstr "Ir a tu bifurcación"
msgid "GoToYourFork|Fork"
msgstr "Bifurcación"
-msgid "Group overview"
+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 "Health Check"
@@ -593,12 +734,6 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
-msgid "Home"
-msgstr "Inicio"
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "Servicio de limpieza iniciado con éxito"
@@ -620,6 +755,9 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Deshabilitado"
@@ -684,6 +822,9 @@ msgstr ""
msgid "Merge events"
msgstr ""
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -812,6 +953,18 @@ msgstr ""
msgid "Owner"
msgstr "Propietario"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -917,10 +1070,7 @@ msgstr "con etapas"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -953,12 +1103,6 @@ msgstr "El enlace de exportación del proyecto ha caducado. Por favor, genera un
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 "Project home"
-msgstr "Inicio del proyecto"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -983,27 +1127,30 @@ msgstr "Etapa"
msgid "ProjectNetworkGraph|Graph"
msgstr "Historial gráfico"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -1019,6 +1166,9 @@ msgstr "Ramas"
msgid "RefSwitcher|Tags"
msgstr "Etiquetas"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "Cambios Relacionados"
@@ -1073,6 +1223,9 @@ msgstr "Guardar programación del pipeline"
msgid "Schedule a new pipeline"
msgstr "Programar un nuevo pipeline"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "Programación de Pipelines"
@@ -1112,6 +1265,12 @@ msgstr "establecer una contraseña"
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Mostrando %d evento"
@@ -1120,6 +1279,102 @@ msgstr[1] "Mostrando %d eventos"
msgid "Snippets"
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 code"
msgstr "Código fuente"
@@ -1132,6 +1387,9 @@ msgstr ""
msgid "StarProject|Star"
msgstr "Destacar"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "Iniciar una %{new_merge_request} con estos cambios"
@@ -1141,6 +1399,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Cambiar rama/etiqueta"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "Etiqueta"
@@ -1206,6 +1467,9 @@ msgstr "El valor en el punto medio de una serie de valores observados. Por ejemp
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "Esto significa que no puede enviar código hasta que cree un repositorio vacío o importe uno existente."
@@ -1381,9 +1645,15 @@ msgstr ""
msgid "Use your global notification setting"
msgstr "Utiliza tu configuración de notificación global"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "Ver solicitud de fusión abierta"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Interno"
@@ -1456,6 +1726,12 @@ msgstr "No podrás actualizar o enviar código al proyecto a través de SSH hast
msgid "Your name"
msgstr "Tu nombre"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "día"
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index c98156e026e..28d9c6a3e56 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:22-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:45-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: French\n"
"Language: fr_FR\n"
@@ -29,27 +29,33 @@ msgstr[1] "%s validations supplémentaires ont été masquées afin d'éviter de
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} a validé %{commit_timeago}"
-msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
+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 "%{number_of_failures} sur %{maximum_failures} tentative(s). GitLab va vous permettre d'accéder à la prochaine tentative."
+
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will block access for %{number_of_seconds} seconds."
-msgstr ""
+msgstr "%{number_of_failures} échecs sur %{maximum_failures}. GitLab va bloquer l’accès pendant %{number_of_seconds} secondes."
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
-msgstr ""
+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 "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{storage_name} : la tentative d’accès au stockage a échouée sur l’hôte :"
+msgstr[1] "%{storage_name} : %{failed_attempts} tentatives d’accès au stockage ont échouées :"
msgid "(checkout the %{link} for information on how to install it)."
-msgstr ""
+msgstr "(Lisez %{link} pour savoir comment l'installer)."
msgid "1 pipeline"
msgid_plural "%d pipelines"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 pipeline"
+msgstr[1] "%d pipelines"
+
+msgid "1st contribution!"
+msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Un ensemble de graphiques concernant l’Intégration Continue (CI)"
@@ -58,16 +64,16 @@ msgid "About auto deploy"
msgstr "A propos de l'auto-déploiement"
msgid "Abuse Reports"
-msgstr ""
+msgstr "Rapports d’abus"
msgid "Access Tokens"
-msgstr ""
+msgstr "Jetons d'Accès"
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 ""
+msgstr "L'accès aux stockages défaillants a été temporairement désactivé pour permettre au montage de récupérer. Réinitialiser les informations de stockage dès que le problème est résolu pour permettre l’accès à nouveau."
msgid "Account"
-msgstr ""
+msgstr "Compte"
msgid "Active"
msgstr "Actif"
@@ -91,13 +97,13 @@ msgid "Add new directory"
msgstr "Ajouter un nouveau dossier"
msgid "All"
-msgstr ""
+msgstr "Tous"
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
-msgstr ""
+msgstr "Applications"
msgid "Archived project! Repository is read-only"
msgstr "Projet archivé ! Le dépôt est en lecture seule"
@@ -106,21 +112,45 @@ msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Êtes-vous sûr de vouloir supprimer ce pipeline programmé"
msgid "Are you sure you want to discard your changes?"
-msgstr ""
+msgstr "Êtes-vous sûr de vouloir annuler vos modifications ?"
msgid "Are you sure you want to reset registration token?"
-msgstr ""
+msgstr "Êtes-vous sûr de vouloir réinitialiser le jeton d’inscription ?"
msgid "Are you sure you want to reset the health check token?"
-msgstr ""
+msgstr "Êtes-vous sûr de vouloir réinitialiser le jeton de bilan de santé ?"
msgid "Are you sure?"
+msgstr "Êtes-vous certain ?"
+
+msgid "Artifacts"
msgstr ""
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Attachez un fichier par glisser &amp; déposer ou %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -177,10 +207,13 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Branche"
+msgstr[1] "Branches"
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}"
@@ -192,6 +225,90 @@ msgid "BranchSwitcherTitle|Switch branch"
msgstr "Changer de branche"
msgid "Branches"
+msgstr "Branches"
+
+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"
@@ -210,7 +327,7 @@ msgid "ByAuthor|by"
msgstr "par"
msgid "CI / CD"
-msgstr ""
+msgstr "Intégration continu / Déploiement continu"
msgid "CI configuration"
msgstr "Configuration de l'intégration continue (CI)"
@@ -219,19 +336,19 @@ msgid "Cancel"
msgstr "Annuler"
msgid "Cancel edit"
-msgstr ""
+msgstr "Annuler modification"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Sélectionner dans la branche"
msgid "ChangeTypeActionLabel|Revert in branch"
-msgstr "Annuler dans la branche"
+msgstr "Défaire dans la branche"
msgid "ChangeTypeAction|Cherry-pick"
msgstr "Sélectionner"
msgid "ChangeTypeAction|Revert"
-msgstr "Annuler"
+msgstr "Défaire"
msgid "Changelog"
msgstr "Journal des modifications"
@@ -240,7 +357,7 @@ msgid "Charts"
msgstr "Graphiques"
msgid "Chat"
-msgstr ""
+msgstr "Chat"
msgid "Cherry-pick this commit"
msgstr "Sélectionner cette validation"
@@ -261,10 +378,10 @@ msgid "CiStatusLabel|manual action"
msgstr "action manuelle"
msgid "CiStatusLabel|passed"
-msgstr "passé"
+msgstr "réussi"
msgid "CiStatusLabel|passed with warnings"
-msgstr "passé avec des avertissements"
+msgstr "réussi avec des avertissements"
msgid "CiStatusLabel|pending"
msgstr "en attente"
@@ -279,7 +396,7 @@ msgid "CiStatusText|blocked"
msgstr "bloqué"
msgid "CiStatusText|canceled"
-msgstr "annulé "
+msgstr "annulé"
msgid "CiStatusText|created"
msgstr "créé"
@@ -291,7 +408,7 @@ msgid "CiStatusText|manual"
msgstr "manuel"
msgid "CiStatusText|passed"
-msgstr "passé"
+msgstr "réussi"
msgid "CiStatusText|pending"
msgstr "en attente"
@@ -303,7 +420,7 @@ msgid "CiStatus|running"
msgstr "en cours"
msgid "Comments"
-msgstr ""
+msgstr "Commentaires"
msgid "Commit"
msgid_plural "Commits"
@@ -337,9 +454,6 @@ msgstr "Validé par"
msgid "Compare"
msgstr "Comparer"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "Guilde de contribution"
@@ -359,7 +473,7 @@ msgid "Create New Directory"
msgstr "Créer un nouveau dossier"
msgid "Create a new branch"
-msgstr ""
+msgstr "Créer une nouvelle branche"
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}."
@@ -436,19 +550,19 @@ msgstr[0] "Déploiement"
msgstr[1] "Déploiements"
msgid "Deploy Keys"
-msgstr ""
+msgstr "Clés de déploiement"
msgid "Description"
-msgstr ""
+msgstr "Description"
msgid "Details"
-msgstr ""
+msgstr "Détails"
msgid "Directory name"
msgstr "Nom du dossier"
msgid "Discard changes"
-msgstr ""
+msgstr "Supprimer les modifications"
msgid "Don't show again"
msgstr "Ne plus montrer"
@@ -487,25 +601,28 @@ msgid "Edit Pipeline Schedule %{id}"
msgstr "Éditer le pipeline programmé %{id}"
msgid "Emails"
+msgstr "Courriels"
+
+msgid "Enable in settings"
msgstr ""
msgid "EventFilterBy|Filter by all"
-msgstr ""
+msgstr "Aucun filtre"
msgid "EventFilterBy|Filter by comments"
-msgstr ""
+msgstr "Filtrer par commentaires"
msgid "EventFilterBy|Filter by issue events"
-msgstr ""
+msgstr "Filtrer par événements d'incident"
msgid "EventFilterBy|Filter by merge events"
-msgstr ""
+msgstr "Filtrer par événements de fusion"
msgid "EventFilterBy|Filter by push events"
-msgstr ""
+msgstr "Filtrer par événements de poussée"
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "Filtrer par équipe"
msgid "Every day (at 4:00am)"
msgstr "Chaque jour (à 4:00 du matin)"
@@ -516,6 +633,9 @@ msgstr "Chaque mois (le 1er à 4:00 du matin)"
msgid "Every week (Sundays at 4:00am)"
msgstr "Chaque semaine (dimanche à 4:00 du matin)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Échec du changement de propriétaire"
@@ -555,16 +675,16 @@ 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 "GPG Keys"
-msgstr ""
+msgstr "Clés GPG"
msgid "Geo Nodes"
msgstr ""
msgid "Git storage health information has been reset"
-msgstr ""
+msgstr "Les informations de santé du stockage Git ont été réinitialisées"
msgid "GitLab Runner section"
-msgstr ""
+msgstr "Section de Runner GitLab"
msgid "Go to your fork"
msgstr "Aller à votre fourche"
@@ -572,33 +692,48 @@ msgstr "Aller à votre fourche"
msgid "GoToYourFork|Fork"
msgstr "Fourche"
-msgid "Group overview"
+msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
-msgid "Health Check"
+msgid "GroupSettings|Share with group lock"
msgstr ""
-msgid "Health information can be retrieved from the following endpoints. More information is available"
+msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
msgstr ""
-msgid "HealthCheck|Access token is"
+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 "HealthCheck|Healthy"
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
msgstr ""
-msgid "HealthCheck|No Health Problems Detected"
+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 "HealthCheck|Unhealthy"
+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 "Home"
-msgstr "Accueil"
-
-msgid "Hooks"
+msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name}"
msgstr ""
+msgid "Health Check"
+msgstr "Bilan de santé"
+
+msgid "Health information can be retrieved from the following endpoints. More information is available"
+msgstr "Des informations de santé peuvent être récupérées depuis les adresses suivantes. Plus d’informations"
+
+msgid "HealthCheck|Access token is"
+msgstr "Le jeton d’accès est"
+
+msgid "HealthCheck|Healthy"
+msgstr "En bonne santé"
+
+msgid "HealthCheck|No Health Problems Detected"
+msgstr "Aucun problème détecté"
+
+msgid "HealthCheck|Unhealthy"
+msgstr "En mauvaise santé"
+
msgid "Housekeeping successfully started"
msgstr "Maintenance démarrée avec succès"
@@ -606,7 +741,7 @@ msgid "Import repository"
msgstr "Importer un dépôt"
msgid "Install a Runner compatible with GitLab CI"
-msgstr ""
+msgstr "Installez un Runner compatible avec l'intégration continue de GitLab"
msgid "Interval Pattern"
msgstr "Schéma d’intervalle"
@@ -615,9 +750,12 @@ msgid "Introducing Cycle Analytics"
msgstr "Introduction à l'analyseur de cycle"
msgid "Issue events"
-msgstr ""
+msgstr "Événements de l'incident"
msgid "Issues"
+msgstr "Incidents"
+
+msgid "Jobs"
msgstr ""
msgid "LFSStatus|Disabled"
@@ -644,10 +782,10 @@ msgid "Last commit"
msgstr "Dernière validation"
msgid "LastPushEvent|You pushed to"
-msgstr ""
+msgstr "Vous avez poussé sur"
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "à"
msgid "Learn more in the"
msgstr "En apprendre plus dans le"
@@ -676,25 +814,28 @@ msgid "Median"
msgstr "Médian"
msgid "Members"
-msgstr ""
+msgstr "Membres"
msgid "Merge Requests"
-msgstr ""
+msgstr "Demandes de fusion"
msgid "Merge events"
+msgstr "Événements de fusion"
+
+msgid "Merge request"
msgstr ""
msgid "Messages"
-msgstr ""
+msgstr "Messages"
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "ajouter une clef SSH"
msgid "Monitoring"
-msgstr ""
+msgstr "Surveillance"
msgid "More information is available|here"
-msgstr ""
+msgstr "ici"
msgid "New Issue"
msgid_plural "New Issues"
@@ -795,7 +936,7 @@ msgid "NotificationLevel|Watch"
msgstr "Surveillé"
msgid "Notifications"
-msgstr ""
+msgstr "Notifications"
msgid "OfSearchInADropdown|Filter"
msgstr "Filtre"
@@ -804,20 +945,32 @@ msgid "OpenedNDaysAgo|Opened"
msgstr "Ouvert"
msgid "Options"
-msgstr ""
+msgstr "Paramètres"
msgid "Overview"
-msgstr ""
+msgstr "Vue d'ensemble"
msgid "Owner"
msgstr "Propriétaire"
-msgid "Password"
+msgid "Pagination|Last »"
msgstr ""
-msgid "Pipeline"
+msgid "Pagination|Next"
msgstr ""
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
+msgid "Password"
+msgstr "Mot de Passe"
+
+msgid "Pipeline"
+msgstr "Pipeline"
+
msgid "Pipeline Health"
msgstr "Santé du Pipeline"
@@ -888,19 +1041,19 @@ msgid "PipelineSheduleIntervalPattern|Custom"
msgstr "Personnalisé"
msgid "Pipelines"
-msgstr ""
+msgstr "Pipelines"
msgid "Pipelines charts"
msgstr "Graphique des pipelines"
msgid "Pipelines for last month"
-msgstr ""
+msgstr "Pipelines pour le dernier mois"
msgid "Pipelines for last week"
-msgstr ""
+msgstr "Pipelines pour la dernière semaine"
msgid "Pipelines for last year"
-msgstr ""
+msgstr "Pipelines pour la dernière année"
msgid "Pipeline|all"
msgstr "Tous"
@@ -915,12 +1068,9 @@ msgid "Pipeline|with stages"
msgstr "avec les étapes"
msgid "Preferences"
-msgstr ""
-
-msgid "Profile Settings"
-msgstr ""
+msgstr "Préférences"
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -939,7 +1089,7 @@ msgid "Project access must be granted explicitly to each user."
msgstr "L’accès au projet doit être explicitement accordé à chaque utilisateur."
msgid "Project details"
-msgstr ""
+msgstr "Détails du projet"
msgid "Project export could not be deleted."
msgstr "L'export du projet n'a pas pu être supprimé."
@@ -953,14 +1103,8 @@ msgstr "Le lien de l’export du projet a expiré. Merci de générer un nouvel
msgid "Project export started. A download link will be sent by email."
msgstr "L'export du projet a débuté. Un lien de téléchargement sera envoyé par courriel."
-msgid "Project home"
-msgstr "Accueil du projet"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
-msgstr ""
+msgstr "S’abonner"
msgid "ProjectFeature|Disabled"
msgstr "Désactivé"
@@ -983,29 +1127,32 @@ msgstr "Étape"
msgid "ProjectNetworkGraph|Graph"
msgstr "Graphique "
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
-msgstr ""
-
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr ""
+msgstr "Chargement des projets"
msgid "ProjectsDropdown|Projects you visit often will appear here"
-msgstr ""
+msgstr "Les projets que vous visitez souvent apparaîtront ici"
msgid "ProjectsDropdown|Search your projects"
-msgstr ""
+msgstr "Chercher dans vos projets"
-msgid "ProjectsDropdown|Something went wrong on our end"
+msgid "ProjectsDropdown|Something went wrong on our end."
msgstr ""
+msgid "ProjectsDropdown|Sorry, no projects matched your search"
+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 "Push Rules"
msgstr ""
msgid "Push events"
-msgstr ""
+msgstr "Évènements de poussée"
msgid "Read more"
msgstr "Lire plus"
@@ -1019,6 +1166,9 @@ msgstr "Branches"
msgid "RefSwitcher|Tags"
msgstr "Étiquettes"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "Validations liés"
@@ -1044,19 +1194,19 @@ msgid "Remove project"
msgstr "Supprimer le projet"
msgid "Repository"
-msgstr ""
+msgstr "Dépôt"
msgid "Request Access"
msgstr "Demander l'accès"
msgid "Reset git storage health information"
-msgstr ""
+msgstr "Réinitialiser les informations de santé du stockage Git"
msgid "Reset health check access token"
-msgstr ""
+msgstr "Réinitialiser le jeton d’accès au bilan de santé"
msgid "Reset runners registration token"
-msgstr ""
+msgstr "Réinitialiser le jeton d’inscription des Runners"
msgid "Revert this commit"
msgstr "Annuler cette validation"
@@ -1065,7 +1215,7 @@ msgid "Revert this merge request"
msgstr "Annuler cette demande de fusion"
msgid "SSH Keys"
-msgstr ""
+msgstr "Clés SSH"
msgid "Save pipeline schedule"
msgstr "Sauvegarder le pipeline programmé"
@@ -1073,6 +1223,9 @@ msgstr "Sauvegarder le pipeline programmé"
msgid "Schedule a new pipeline"
msgstr "Programmer un nouveau pipeline"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "Programmer des pipelines"
@@ -1086,13 +1239,13 @@ msgid "Select a timezone"
msgstr "Sélectionnez un fuseau horaire"
msgid "Select existing branch"
-msgstr ""
+msgstr "Sélectionnez une branche existante"
msgid "Select target branch"
msgstr "Sélectionnez une branche cible"
msgid "Service Templates"
-msgstr ""
+msgstr "Modèles de 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}."
@@ -1110,6 +1263,12 @@ msgid "SetPasswordToCloneLink|set a password"
msgstr "définir un mot de passe"
msgid "Settings"
+msgstr "Paramètres"
+
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
msgstr ""
msgid "Showing %d event"
@@ -1118,29 +1277,131 @@ msgstr[0] "Affichage de %d évènement"
msgstr[1] "Affichage de %d évènements"
msgid "Snippets"
+msgstr "Extraits de code"
+
+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 code"
msgstr "Code source"
msgid "Spam Logs"
-msgstr ""
+msgstr "Journaux des messages indésirables"
msgid "Specify the following URL during the Runner setup:"
-msgstr ""
+msgstr "Spécifiez l’URL suivante lors de la configuration du Runner :"
msgid "StarProject|Star"
msgstr "S'abonner"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "Créer une %{new_merge_request} avec ces changements"
msgid "Start the Runner!"
-msgstr ""
+msgstr "Démarrer le Runner !"
msgid "Switch branch/tag"
msgstr "Changer de branche / d'étiquette"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "Étiquette"
@@ -1153,7 +1414,7 @@ msgid "Target Branch"
msgstr "Branche cible"
msgid "Team"
-msgstr ""
+msgstr "Équipe"
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."
@@ -1204,6 +1465,9 @@ 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 problems accessing Git storage: "
+msgstr "Il y a des difficultés à accéder aux données Git : "
+
+msgid "This is the author's first Merge Request to this project. Handle with care."
msgstr ""
msgid "This means you can not push code until you create an empty repository or import existing one."
@@ -1376,14 +1640,20 @@ msgid "UploadLink|click to upload"
msgstr "Cliquez pour envoyer"
msgid "Use the following registration token during setup:"
-msgstr ""
+msgstr "Utiliser le jeton d’inscription suivant pendant l’installation :"
msgid "Use your global notification setting"
msgstr "Utiliser vos paramètres de notification globaux"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "Afficher la demande de fusion"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Interne"
@@ -1403,7 +1673,7 @@ msgid "We don't have enough data to show this stage."
msgstr "Nous n'avons pas suffisamment de données pour afficher cette étape."
msgid "Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "Withdraw Access Request"
msgstr "Retirer la demande d'accès"
@@ -1456,6 +1726,12 @@ msgstr "Vous ne pourrez pas récupérer ou pousser de code par SSH tant que vous
msgid "Your name"
msgstr "Votre nom"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "jour"
@@ -1469,6 +1745,6 @@ msgstr "courriels de notification"
msgid "parent"
msgid_plural "parents"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "parent"
+msgstr[1] "parents"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 600432be3bf..99f773e6bca 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: 2017-09-27 15:43+0100\n"
-"PO-Revision-Date: 2017-09-27 15:43+0100\n"
+"POT-Creation-Date: 2017-10-03 16:06-0400\n"
+"PO-Revision-Date: 2017-10-03 16:06-0400\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
@@ -134,6 +134,9 @@ msgstr ""
msgid "Authentication Log"
msgstr ""
+msgid "Author"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
msgstr ""
@@ -361,6 +364,9 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
+msgid "Clone repository"
+msgstr ""
+
msgid "Comments"
msgstr ""
@@ -369,6 +375,9 @@ msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
+msgid "Commit Message"
+msgstr ""
+
msgid "Commit duration in minutes for last 30 commits"
msgstr ""
@@ -411,9 +420,6 @@ msgstr ""
msgid "Create New Directory"
msgstr ""
-msgid "Create a new branch"
-msgstr ""
-
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr ""
@@ -610,6 +616,9 @@ msgstr[1] ""
msgid "ForkedFromProjectPath|Forked from"
msgstr ""
+msgid "Format"
+msgstr ""
+
msgid "From issue creation until deploy to production"
msgstr ""
@@ -673,6 +682,9 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
+msgid "History"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr ""
@@ -714,10 +726,19 @@ msgstr[1] ""
msgid "Last Pipeline"
msgstr ""
-msgid "Last Update"
+msgid "Last commit"
msgstr ""
-msgid "Last commit"
+msgid "Last edited %{date}"
+msgstr ""
+
+msgid "Last edited by %{name}"
+msgstr ""
+
+msgid "Last update"
+msgstr ""
+
+msgid "Last updated"
msgstr ""
msgid "LastPushEvent|You pushed to"
@@ -1141,6 +1162,9 @@ msgstr ""
msgid "SSH Keys"
msgstr ""
+msgid "Save changes"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr ""
@@ -1162,9 +1186,6 @@ msgstr ""
msgid "Select a timezone"
msgstr ""
-msgid "Select existing branch"
-msgstr ""
-
msgid "Select target branch"
msgstr ""
@@ -1382,7 +1403,7 @@ msgstr ""
msgid "There are problems accessing Git storage: "
msgstr ""
-msgid "This is the author's first Merge Request to this project. Handle with care."
+msgid "This is the author's first Merge Request to this project."
msgstr ""
msgid "This means you can not push code until you create an empty repository or import existing one."
@@ -1466,9 +1487,6 @@ msgstr ""
msgid "Timeago|a week ago"
msgstr ""
-msgid "Timeago|a while"
-msgstr ""
-
msgid "Timeago|a year ago"
msgstr ""
@@ -1520,6 +1538,9 @@ msgstr ""
msgid "Timeago|in 1 year"
msgstr ""
+msgid "Timeago|in a while"
+msgstr ""
+
msgid "Timeago|less than a minute ago"
msgstr ""
@@ -1590,6 +1611,105 @@ 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 "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 "Withdraw Access Request"
msgstr ""
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index 0249c4fe9eb..804817e96e9 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:20-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:44-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@@ -29,6 +29,9 @@ msgstr[1] "%s commit aggiuntivi sono stati omessi per evitare degradi di prestaz
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} ha committato %{commit_timeago}"
+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 ""
@@ -51,6 +54,9 @@ msgid_plural "%d pipelines"
msgstr[0] ""
msgstr[1] ""
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Un insieme di grafici riguardo la Continuous Integration"
@@ -93,7 +99,7 @@ msgstr "Aggiungi una directory (cartella)"
msgid "All"
msgstr ""
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
@@ -117,10 +123,34 @@ msgstr ""
msgid "Are you sure?"
msgstr ""
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Aggiungi un file tramite trascina &amp; rilascia ( drag &amp; drop) o %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -177,6 +207,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] ""
@@ -194,6 +227,90 @@ msgstr "Cambia branch"
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 "Naviga direttori"
@@ -337,9 +454,6 @@ msgstr "Committato da "
msgid "Compare"
msgstr "Confronta"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "Guida per contribuire"
@@ -489,6 +603,9 @@ msgstr "Cambia programmazione della pipeline %{id}"
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -516,6 +633,9 @@ msgstr "Ogni primo giorno del mese (alle 4 del mattino)"
msgid "Every week (Sundays at 4:00am)"
msgstr "Ogni settimana (Di domenica alle 4 del mattino)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Impossibile cambiare owner"
@@ -572,7 +692,28 @@ msgstr "Vai il tuo fork"
msgid "GoToYourFork|Fork"
msgstr "Fork"
-msgid "Group overview"
+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 "Health Check"
@@ -593,12 +734,6 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
-msgid "Home"
-msgstr ""
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "Housekeeping iniziato con successo"
@@ -620,6 +755,9 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Disabilitato"
@@ -684,6 +822,9 @@ msgstr ""
msgid "Merge events"
msgstr ""
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -812,6 +953,18 @@ msgstr ""
msgid "Owner"
msgstr ""
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -917,10 +1070,7 @@ msgstr "con più stadi"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -953,12 +1103,6 @@ msgstr "Il link d'esportazione del progetto è scaduto. Genera una nuova esporta
msgid "Project export started. A download link will be sent by email."
msgstr "Esportazione del progetto iniziata. Un link di download sarà inviato via email."
-msgid "Project home"
-msgstr "Home di progetto"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -983,27 +1127,30 @@ msgstr "Stadio"
msgid "ProjectNetworkGraph|Graph"
msgstr "Grafico"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -1019,6 +1166,9 @@ msgstr "Branches"
msgid "RefSwitcher|Tags"
msgstr "Tags"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "Commit correlati"
@@ -1073,6 +1223,9 @@ msgstr "Salva pianificazione pipeline"
msgid "Schedule a new pipeline"
msgstr "Pianifica una nuova Pipeline"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "Pianificazione pipelines"
@@ -1112,6 +1265,12 @@ msgstr "imposta una password"
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Visualizza %d evento"
@@ -1120,6 +1279,102 @@ msgstr[1] "Visualizza %d eventi"
msgid "Snippets"
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 code"
msgstr "Codice Sorgente"
@@ -1132,6 +1387,9 @@ msgstr ""
msgid "StarProject|Star"
msgstr "Star"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "inizia una %{new_merge_request} con queste modifiche"
@@ -1141,6 +1399,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Cambia branch/tag"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] ""
@@ -1206,6 +1467,9 @@ msgstr "Il valore falsato nel mezzo di una serie di dati osservati. ES: tra 3,5,
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "Questo significa che non è possibile effettuare push di codice fino a che non crei una repository vuota o ne importi una esistente"
@@ -1381,9 +1645,15 @@ msgstr ""
msgid "Use your global notification setting"
msgstr "Usa le tue impostazioni globali "
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "Mostra la richieste di merge aperte"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Interno"
@@ -1456,6 +1726,12 @@ msgstr "Non sarai in grado di effettuare push o pull tramite SSH fino a che %{ad
msgid "Your name"
msgstr "Il tuo nome"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "giorno"
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index c66dd3c1b6b..2a08abda7ce 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:20-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:44-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Japanese\n"
"Language: ja_JP\n"
@@ -27,6 +27,9 @@ msgstr[0] "パフォーマンス低下をé¿ã‘ã‚‹ãŸã‚ %s 個ã®ã‚³ãƒŸãƒƒãƒˆã‚
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_timeago}ã«%{commit_author_link}ãŒã‚³ãƒŸãƒƒãƒˆã—ã¾ã—ãŸã€‚"
+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 ""
@@ -47,6 +50,9 @@ msgid "1 pipeline"
msgid_plural "%d pipelines"
msgstr[0] "%d 個ã®ãƒ‘イプライン"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "CIã«ã¤ã„ã¦ã®ã‚°ãƒ©ãƒ•"
@@ -89,7 +95,7 @@ msgstr "æ–°è¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’追加"
msgid "All"
msgstr ""
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
@@ -113,10 +119,34 @@ msgstr ""
msgid "Are you sure?"
msgstr ""
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "ドラッグ&ドロップã¾ãŸã¯ %{upload_link} ã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’添付"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -173,6 +203,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "ブランãƒ"
@@ -189,6 +222,90 @@ 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 "ディレクトリを表示"
@@ -331,9 +448,6 @@ msgstr "コミット担当者: "
msgid "Compare"
msgstr "比較"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "貢献者å‘ã‘ガイド"
@@ -482,6 +596,9 @@ msgstr "パイプラインスケジュール %{id} を編集"
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -509,6 +626,9 @@ msgstr "毎月 (1æ—¥ã®åˆå‰4:00)"
msgid "Every week (Sundays at 4:00am)"
msgstr "毎週 (日曜日ã®åˆå‰4:00)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "オーナーを変更ã§ãã¾ã›ã‚“ã§ã—ãŸ"
@@ -564,7 +684,28 @@ msgstr "自分ã®ãƒ•ã‚©ãƒ¼ã‚¯ã¸ç§»å‹•"
msgid "GoToYourFork|Fork"
msgstr "フォーク"
-msgid "Group overview"
+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 "Health Check"
@@ -585,12 +726,6 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
-msgid "Home"
-msgstr "ホーム"
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "ãƒã‚¦ã‚¹ã‚­ãƒ¼ãƒ”ングã¯æ­£å¸¸ã«èµ·å‹•ã—ã¾ã—ãŸã€‚"
@@ -612,6 +747,9 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "無効"
@@ -674,6 +812,9 @@ msgstr ""
msgid "Merge events"
msgstr ""
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -801,6 +942,18 @@ msgstr ""
msgid "Owner"
msgstr "オーナー"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -906,10 +1059,7 @@ msgstr "ステージã‚ã‚Š"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -942,12 +1092,6 @@ msgstr "プロジェクトã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãƒªãƒ³ã‚¯ã¯æœŸé™åˆ‡ã‚Œã«ãªã‚Š
msgid "Project export started. A download link will be sent by email."
msgstr "プロジェクトã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã‚’開始ã—ã¾ã—ãŸã€‚ダウンロードã®ãƒªãƒ³ã‚¯ã¯ãƒ¡ãƒ¼ãƒ«ã§é€ä¿¡ã—ã¾ã™"
-msgid "Project home"
-msgstr "プロジェクトホーム"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -972,27 +1116,30 @@ msgstr "ステージ"
msgid "ProjectNetworkGraph|Graph"
msgstr "ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚°ãƒ©ãƒ•"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -1008,6 +1155,9 @@ msgstr "ブランãƒ"
msgid "RefSwitcher|Tags"
msgstr "ã‚¿ã‚°"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "関連ã™ã‚‹ã‚³ãƒŸãƒƒãƒˆ"
@@ -1062,6 +1212,9 @@ msgstr "パイプラインスケジュールをä¿å­˜"
msgid "Schedule a new pipeline"
msgstr "æ–°ã—ã„パイプラインã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’作æˆ"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "パイプラインスケジューリング"
@@ -1101,6 +1254,12 @@ msgstr "パスワードを設定"
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "%d ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’表示中"
@@ -1108,6 +1267,102 @@ msgstr[0] "%d ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’表示中"
msgid "Snippets"
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 code"
msgstr "ソースコード"
@@ -1120,6 +1375,9 @@ msgstr ""
msgid "StarProject|Star"
msgstr "スターを付ã‘ã‚‹"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "ã“ã®å¤‰æ›´ã§ %{new_merge_request} を作æˆã™ã‚‹"
@@ -1129,6 +1387,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "ブランãƒãƒ»ã‚¿ã‚°åˆ‡ã‚Šæ›¿ãˆ"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "ã‚¿ã‚°"
@@ -1193,6 +1454,9 @@ msgstr "得られãŸä¸€é€£ã®ãƒ‡ãƒ¼ã‚¿ã‚’å°ã•ã„é †ã«ä¸¦ã¹ãŸã¨ãã«ä¸­å¤®
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "空レãƒã‚¸ãƒˆãƒªãƒ¼ã‚’作æˆã¾ãŸã¯æ—¢å­˜ãƒ¬ãƒã‚¸ãƒˆãƒªãƒ¼ã‚’インãƒãƒ¼ãƒˆã‚’ã—ãªã‘ã‚Œã°ã€ã‚³ãƒ¼ãƒ‰ã®ãƒ—ッシュã¯ã§ãã¾ã›ã‚“。"
@@ -1366,9 +1630,15 @@ msgstr ""
msgid "Use your global notification setting"
msgstr "全体通知設定を利用"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "オープンãªãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’表示"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "内部"
@@ -1441,6 +1711,12 @@ msgstr "%{add_ssh_key_link} をプロファイルã«è¿½åŠ ã—ã¦ã„ãªã„ã®ã§ã
msgid "Your name"
msgstr "åå‰"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "æ—¥"
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index bbf4aa15cd7..de4a13d3765 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:19-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:43-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Korean\n"
"Language: ko_KR\n"
@@ -27,6 +27,9 @@ msgstr[0] "%s 추가 ì»¤ë°‹ì€ ì„±ëŠ¥ ì´ìŠˆë¥¼ 방지하기 위해 ìƒëžµë˜ì—ˆ
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_timeago} ì— %{commit_author_link} ë‹˜ì´ ì»¤ë°‹í•˜ì˜€ìŠµë‹ˆë‹¤. "
+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 "%{number_of_failures} / %{maximum_failures} 실패. GitLab ì€ ë‹¤ìŒ ì‹œë„ì—ì„œ 성공하면 ì ‘ê·¼ì„ í—ˆìš©í•  것입니다."
@@ -47,6 +50,9 @@ msgid "1 pipeline"
msgid_plural "%d pipelines"
msgstr[0] "%d 파ì´í”„ë¼ì¸"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "지ì†ì ì¸ í†µí•©ì— ê´€í•œ 그래프 모ìŒ"
@@ -89,7 +95,7 @@ msgstr "새 디렉토리 추가"
msgid "All"
msgstr "ì „ì²´"
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
@@ -113,10 +119,34 @@ msgstr "헬스 ì²´í¬ í† í°ì„ 초기화 하시겠습니까?"
msgid "Are you sure?"
msgstr "확실합니까?"
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "드래그 &amp; 드롭 ë˜ëŠ” %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -173,6 +203,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "브랜치"
@@ -189,6 +222,90 @@ 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 "디렉토리 찾아보기"
@@ -331,9 +448,6 @@ msgstr "커밋한 사용ìž"
msgid "Compare"
msgstr "비êµ"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "ê¸°ì—¬ì— ëŒ€í•œ 안내"
@@ -482,6 +596,9 @@ msgstr "파ì´í”„ë¼ì¸ 스케줄 편집 %{id}"
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "모든 ê°’ì„ ê¸°ì¤€ìœ¼ë¡œ í•„í„°"
@@ -509,6 +626,9 @@ msgstr "매월 (1ì¼ ì˜¤ì „ 4ì‹œ)"
msgid "Every week (Sundays at 4:00am)"
msgstr "매주 (ì¼ìš”ì¼ ì˜¤ì „ 4ì‹œì—)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "소유ìžë¥¼ 변경하지 못했습니다"
@@ -564,7 +684,28 @@ msgstr "ë‹¹ì‹ ì˜ í¬í¬ë¡œ ì´ë™í•˜ì„¸ìš”"
msgid "GoToYourFork|Fork"
msgstr "í¬í¬"
-msgid "Group overview"
+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 "Health Check"
@@ -585,12 +726,6 @@ msgstr " 헬스 문제가 발견ë˜ì§€ 않았습니다."
msgid "HealthCheck|Unhealthy"
msgstr "비정ìƒ"
-msgid "Home"
-msgstr "홈"
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "Housekeepingì´ ì„±ê³µì ìœ¼ë¡œ 시작ë˜ì—ˆìŠµë‹ˆë‹¤"
@@ -612,6 +747,9 @@ msgstr "ì´ìŠˆ ì´ë²¤íŠ¸"
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Disabled"
@@ -674,6 +812,9 @@ msgstr ""
msgid "Merge events"
msgstr "머지 ì´ë²¤íŠ¸"
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -801,6 +942,18 @@ msgstr ""
msgid "Owner"
msgstr "소유ìž"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -906,10 +1059,7 @@ msgstr "스테ì´ì§•"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -942,12 +1092,6 @@ msgstr "프로ì íŠ¸ 내보내기 ë§í¬ê°€ 만료ë˜ì—ˆìŠµë‹ˆë‹¤. 프로ì íŠ¸
msgid "Project export started. A download link will be sent by email."
msgstr "프로ì íŠ¸ 내보내기가 시작ë˜ì—ˆìŠµë‹ˆë‹¤. 다운로드 ë§í¬ëŠ” ì´ë©”ì¼ë¡œ 전송ë©ë‹ˆë‹¤."
-msgid "Project home"
-msgstr "프로ì íŠ¸ 홈"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr "구ë…"
@@ -972,27 +1116,30 @@ msgstr "스테ì´ì§•"
msgid "ProjectNetworkGraph|Graph"
msgstr "그래프"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr "푸쉬 ì´ë²¤íŠ¸"
@@ -1008,6 +1155,9 @@ msgstr "브랜치"
msgid "RefSwitcher|Tags"
msgstr "태그"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "관련 커밋"
@@ -1062,6 +1212,9 @@ msgstr "파ì´í”„ë¼ì¸ 스케줄 저장"
msgid "Schedule a new pipeline"
msgstr "새로운 파ì´í”„ë¼ì¸ 스케줄 잡기"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "파ì´í”„ë¼ì¸ 스케줄ë§"
@@ -1101,6 +1254,12 @@ msgstr "패스워드 설정"
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "%d ê°œì˜ ì´ë²¤íŠ¸ 표시 중"
@@ -1108,6 +1267,102 @@ msgstr[0] "%d ê°œì˜ ì´ë²¤íŠ¸ 표시 중"
msgid "Snippets"
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 code"
msgstr "소스 코드"
@@ -1120,6 +1375,9 @@ msgstr "Runner 설정 중 ë‹¤ìŒ URLì„ ì§€ì •í•˜ì„¸ìš”."
msgid "StarProject|Star"
msgstr "별표"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "ì´ ë³€ê²½ 사항으로 %{new_merge_request} ì„ ì‹œìž‘í•˜ì‹­ì‹œì˜¤."
@@ -1129,6 +1387,9 @@ msgstr "Runner 시작!"
msgid "Switch branch/tag"
msgstr "스위치 브랜치/태그"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "태그"
@@ -1193,6 +1454,9 @@ msgstr "ê°’ì€ ì¼ë ¨ì˜ 관측 ê°’ 중ì ì— 있습니다. 예를 들어, 3, 5,
msgid "There are problems accessing Git storage: "
msgstr "git storageì— ì ‘ê·¼í•˜ëŠ”ë° ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. "
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "즉, 빈 저장소를 만들거나 기존 저장소를 가져올 때까지 코드를 Push 할 수 없습니다."
@@ -1366,9 +1630,15 @@ msgstr "설정 ì¤‘ì— ë‹¤ìŒ ë“±ë¡ í† í° ì´ìš© : "
msgid "Use your global notification setting"
msgstr "전체 알림 설정 사용"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "열린 머지 리퀘스트보기"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "내부"
@@ -1441,6 +1711,12 @@ msgstr "ë‹¹ì‹ ì˜ í”„ë¡œí•„ì— %{add_ssh_key_link} 를 하기 ì „ì—는 SSH를 í
msgid "Your name"
msgstr "ê·€í•˜ì˜ ì´ë¦„"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "ì¼"
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index 250d3bd413c..45a444fac43 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:20-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:43-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
@@ -18,17 +18,20 @@ msgstr ""
msgid "%d commit"
msgid_plural "%d commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d commit"
+msgstr[1] "%d commits"
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%s andere commit is weggelaten om prestatieproblemen te voorkomen."
+msgstr[1] "%s andere commits zijn weggelaten om prestatieproblemen te voorkomen."
msgid "%{commit_author_link} committed %{commit_timeago}"
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 ""
@@ -44,60 +47,63 @@ msgstr[0] ""
msgstr[1] ""
msgid "(checkout the %{link} for information on how to install it)."
-msgstr ""
+msgstr "(bekijk de %{link} voor meer info over hoe je het kan installeren)."
msgid "1 pipeline"
msgid_plural "%d pipelines"
msgstr[0] ""
msgstr[1] ""
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr ""
msgid "About auto deploy"
-msgstr ""
+msgstr "Over auto deploy"
msgid "Abuse Reports"
-msgstr ""
+msgstr "Misbruik rapporten"
msgid "Access Tokens"
-msgstr ""
+msgstr "Toegangstokens"
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 ""
+msgstr "Account"
msgid "Active"
-msgstr ""
+msgstr "Actief"
msgid "Activity"
-msgstr ""
+msgstr "Activiteit"
msgid "Add Changelog"
-msgstr ""
+msgstr "Changelog toevoegen"
msgid "Add Contribution guide"
msgstr ""
msgid "Add License"
-msgstr ""
+msgstr "Licentie toevoegen"
msgid "Add an SSH key to your profile to pull or push via SSH."
msgstr ""
msgid "Add new directory"
-msgstr ""
+msgstr "Nieuwe map toevoegen"
msgid "All"
-msgstr ""
+msgstr "Alles"
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
-msgstr ""
+msgstr "Applicaties"
msgid "Archived project! Repository is read-only"
msgstr ""
@@ -117,10 +123,34 @@ msgstr ""
msgid "Are you sure?"
msgstr ""
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr ""
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -177,6 +207,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] ""
@@ -192,35 +225,119 @@ msgid "BranchSwitcherTitle|Switch branch"
msgstr ""
msgid "Branches"
+msgstr "Branches"
+
+msgid "Branches|Cant find HEAD commit for this branch"
msgstr ""
-msgid "Browse Directory"
+msgid "Branches|Compare"
msgstr ""
-msgid "Browse File"
+msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
msgstr ""
-msgid "Browse Files"
+msgid "Branches|Delete branch"
msgstr ""
-msgid "Browse files"
+msgid "Branches|Delete merged branches"
msgstr ""
-msgid "ByAuthor|by"
+msgid "Branches|Delete protected branch"
msgstr ""
-msgid "CI / CD"
+msgid "Branches|Delete protected branch '%{branch_name}'?"
msgstr ""
-msgid "CI configuration"
+msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?"
msgstr ""
-msgid "Cancel"
+msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
msgstr ""
-msgid "Cancel edit"
+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 "Bladeren in map"
+
+msgid "Browse File"
+msgstr "Bekijk bestand"
+
+msgid "Browse Files"
+msgstr "Door bestanden bladeren"
+
+msgid "Browse files"
+msgstr "Door bestanden bladeren"
+
+msgid "ByAuthor|by"
+msgstr "door"
+
+msgid "CI / CD"
+msgstr "CI / CD"
+
+msgid "CI configuration"
+msgstr "CI Configuratie"
+
+msgid "Cancel"
+msgstr "Annuleren"
+
+msgid "Cancel edit"
+msgstr "Bewerken annuleren"
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -237,25 +354,25 @@ msgid "Changelog"
msgstr ""
msgid "Charts"
-msgstr ""
+msgstr "Grafieken"
msgid "Chat"
-msgstr ""
+msgstr "Chat"
msgid "Cherry-pick this commit"
-msgstr ""
+msgstr "Cherry-pick deze commit"
msgid "Cherry-pick this merge request"
msgstr ""
msgid "CiStatusLabel|canceled"
-msgstr ""
+msgstr "geannuleerd"
msgid "CiStatusLabel|created"
-msgstr ""
+msgstr "gemaakt"
msgid "CiStatusLabel|failed"
-msgstr ""
+msgstr "mislukt"
msgid "CiStatusLabel|manual action"
msgstr ""
@@ -270,40 +387,40 @@ msgid "CiStatusLabel|pending"
msgstr ""
msgid "CiStatusLabel|skipped"
-msgstr ""
+msgstr "overgeslagen"
msgid "CiStatusLabel|waiting for manual action"
msgstr ""
msgid "CiStatusText|blocked"
-msgstr ""
+msgstr "geblokkeerd"
msgid "CiStatusText|canceled"
msgstr ""
msgid "CiStatusText|created"
-msgstr ""
+msgstr "gemaakt"
msgid "CiStatusText|failed"
msgstr ""
msgid "CiStatusText|manual"
-msgstr ""
+msgstr "handmatig"
msgid "CiStatusText|passed"
-msgstr ""
+msgstr "geslaagd"
msgid "CiStatusText|pending"
msgstr ""
msgid "CiStatusText|skipped"
-msgstr ""
+msgstr "overgeslagen"
msgid "CiStatus|running"
msgstr ""
msgid "Comments"
-msgstr ""
+msgstr "Opmerkingen"
msgid "Commit"
msgid_plural "Commits"
@@ -317,28 +434,25 @@ msgid "Commit message"
msgstr ""
msgid "CommitBoxTitle|Commit"
-msgstr ""
+msgstr "Commit"
msgid "CommitMessage|Add %{file_name}"
-msgstr ""
+msgstr "%{file_name} toevoegen"
msgid "Commits"
-msgstr ""
+msgstr "Commits"
msgid "Commits feed"
msgstr ""
msgid "Commits|History"
-msgstr ""
+msgstr "Geschiedenis"
msgid "Committed by"
-msgstr ""
+msgstr "Gecommit door"
msgid "Compare"
-msgstr ""
-
-msgid "Container Registry"
-msgstr ""
+msgstr "Vergelijk"
msgid "Contribution guide"
msgstr ""
@@ -365,7 +479,7 @@ msgid "Create a personal access token on your account to pull or push via %{prot
msgstr ""
msgid "Create directory"
-msgstr ""
+msgstr "Maak map aan"
msgid "Create empty bare repository"
msgstr ""
@@ -489,6 +603,9 @@ msgstr ""
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -516,6 +633,9 @@ msgstr ""
msgid "Every week (Sundays at 4:00am)"
msgstr ""
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr ""
@@ -572,7 +692,28 @@ msgstr ""
msgid "GoToYourFork|Fork"
msgstr ""
-msgid "Group overview"
+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 "Health Check"
@@ -593,12 +734,6 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
-msgid "Home"
-msgstr ""
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr ""
@@ -620,6 +755,9 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr ""
@@ -684,6 +822,9 @@ msgstr ""
msgid "Merge events"
msgstr ""
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -698,8 +839,8 @@ msgstr ""
msgid "New Issue"
msgid_plural "New Issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Nieuwe issue"
+msgstr[1] "Nieuwe issues"
msgid "New Pipeline Schedule"
msgstr ""
@@ -812,6 +953,18 @@ msgstr ""
msgid "Owner"
msgstr ""
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -917,10 +1070,7 @@ msgstr ""
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -953,12 +1103,6 @@ msgstr ""
msgid "Project export started. A download link will be sent by email."
msgstr ""
-msgid "Project home"
-msgstr ""
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -983,27 +1127,30 @@ msgstr ""
msgid "ProjectNetworkGraph|Graph"
msgstr ""
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -1019,6 +1166,9 @@ msgstr ""
msgid "RefSwitcher|Tags"
msgstr ""
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr ""
@@ -1073,6 +1223,9 @@ msgstr ""
msgid "Schedule a new pipeline"
msgstr ""
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr ""
@@ -1112,6 +1265,12 @@ msgstr ""
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] ""
@@ -1120,6 +1279,102 @@ msgstr[1] ""
msgid "Snippets"
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 code"
msgstr ""
@@ -1132,6 +1387,9 @@ msgstr ""
msgid "StarProject|Star"
msgstr ""
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr ""
@@ -1141,6 +1399,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] ""
@@ -1206,6 +1467,9 @@ msgstr ""
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr ""
@@ -1381,9 +1645,15 @@ msgstr ""
msgid "Use your global notification setting"
msgstr ""
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr ""
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr ""
@@ -1456,6 +1726,12 @@ msgstr ""
msgid "Your name"
msgstr ""
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] ""
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 5469f77d950..318c719c2ed 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:18-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:42-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Portuguese, Brazilian\n"
"Language: pt_BR\n"
@@ -29,6 +29,9 @@ msgstr[1] "%s commits adicionais foram omitidos para prevenir problemas de perfo
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} fez commit %{commit_timeago}"
+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 ""
@@ -51,6 +54,9 @@ msgid_plural "%d pipelines"
msgstr[0] ""
msgstr[1] ""
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Uma coleção de gráficos sobre Integração Contínua"
@@ -93,7 +99,7 @@ msgstr "Adicionar novo diretório"
msgid "All"
msgstr ""
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
@@ -117,10 +123,34 @@ msgstr ""
msgid "Are you sure?"
msgstr ""
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Para anexar arquivo, arraste e solte ou %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -177,6 +207,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] ""
@@ -194,6 +227,90 @@ msgstr "Mudar de branch"
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 "Navegar no Diretório"
@@ -337,9 +454,6 @@ msgstr "Commit feito por"
msgid "Compare"
msgstr "Comparar"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "Guia de contribuição"
@@ -489,6 +603,9 @@ msgstr "Alterar Agendamento do Pipeline %{id}"
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -516,6 +633,9 @@ msgstr "Todos os meses (no dia primeiro às 4:00)"
msgid "Every week (Sundays at 4:00am)"
msgstr "Toda semana (domingos às 4:00)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Erro ao alterar o proprietário"
@@ -572,7 +692,28 @@ msgstr "Ir para seu fork"
msgid "GoToYourFork|Fork"
msgstr "Fork"
-msgid "Group overview"
+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 "Health Check"
@@ -593,12 +734,6 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
-msgid "Home"
-msgstr "Início"
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "Manutenção iniciada com sucesso"
@@ -620,6 +755,9 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Desabilitado"
@@ -684,6 +822,9 @@ msgstr ""
msgid "Merge events"
msgstr ""
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -812,6 +953,18 @@ msgstr ""
msgid "Owner"
msgstr "Proprietário"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -917,10 +1070,7 @@ msgstr "com etapas"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -953,12 +1103,6 @@ msgstr "O link para a exportação do projeto expirou. Favor gerar uma nova expo
msgid "Project export started. A download link will be sent by email."
msgstr "Exportação do projeto iniciada. Um link para baixá-la será enviado por email."
-msgid "Project home"
-msgstr "Página inicial do projeto"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -983,27 +1127,30 @@ msgstr "Etapa"
msgid "ProjectNetworkGraph|Graph"
msgstr "Ãrvore"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -1019,6 +1166,9 @@ msgstr "Branches"
msgid "RefSwitcher|Tags"
msgstr "Tags"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "Commits Relacionados"
@@ -1073,6 +1223,9 @@ msgstr "Salvar agendamento da pipeline"
msgid "Schedule a new pipeline"
msgstr "Agendar nova pipeline"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "Agendando pipelines"
@@ -1112,6 +1265,12 @@ msgstr "defina uma senha"
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Mostrando %d evento"
@@ -1120,6 +1279,102 @@ msgstr[1] "Mostrando %d eventos"
msgid "Snippets"
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 code"
msgstr "Código-fonte"
@@ -1132,6 +1387,9 @@ msgstr ""
msgid "StarProject|Star"
msgstr "Marcar"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "Iniciar um %{new_merge_request} a partir dessas alterações"
@@ -1141,6 +1399,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Trocar branch/tag"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] ""
@@ -1206,6 +1467,9 @@ msgstr "O valor situado no ponto médio de uma série de valores observados. Ex.
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "Isto significa que você não pode entregar código até que crie um repositório vazio ou importe um existente."
@@ -1381,9 +1645,15 @@ msgstr ""
msgid "Use your global notification setting"
msgstr "Utilizar configuração de notificação global"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "Ver merge request aberto"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Interno"
@@ -1456,6 +1726,12 @@ msgstr "Você não conseguirá fazer pull ou push no projeto via SSH até que a
msgid "Your name"
msgstr "Seu nome"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "dia"
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index 808bc9dedce..507dc187cdb 100644
--- a/locale/ru/gitlab.po
+++ b/locale/ru/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:19-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:43-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Russian\n"
"Language: ru_RU\n"
@@ -31,23 +31,26 @@ msgstr[2] "%s добавленные коммиты были иÑключены
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} коммичено %{commit_timeago}"
-msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
+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 "%{number_of_failures} из %{maximum_failures} возможных попыток. Ð’Ñ‹ можете попытатьÑÑ ÐµÑ‰Ðµ раз."
+
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will block access for %{number_of_seconds} seconds."
-msgstr ""
+msgstr "%{number_of_failures} из %{maximum_failures} возможных неудачных попыток. GitLab заблокирует доÑтуп на %{number_of_seconds} Ñекунд."
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
-msgstr ""
+msgstr "%{number_of_failures} из %{maximum_failures} возможных неудачных попыток. GitLab не будет автоматичеÑки повторÑÑ‚ÑŒ попытку. СброÑьте информацию хранилища поÑле уÑÑ‚Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ñ‹."
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[0] "%{storage_name}: Ð½ÐµÑƒÐ´Ð°Ñ‡Ð½Ð°Ñ Ð¿Ð¾Ð¿Ñ‹Ñ‚ÐºÐ° доÑтупа к хранилищу на хоÑте:"
+msgstr[1] "%{storage_name}: %{failed_attempts} - неудачные попытки доÑтупа к хранилищу:"
+msgstr[2] "%{storage_name}: %{failed_attempts} - неудачные попытки доÑтупа к хранилищу:"
msgid "(checkout the %{link} for information on how to install it)."
-msgstr ""
+msgstr "(перейдите по ÑÑылке %{link} Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ об уÑтановке)."
msgid "1 pipeline"
msgid_plural "%d pipelines"
@@ -55,23 +58,26 @@ msgstr[0] "1 конвейер"
msgstr[1] "%d конвейеры"
msgstr[2] "%d конвейеры"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Графики отноÑительно непрерывной интеграции"
msgid "About auto deploy"
-msgstr "ÐвтоматичеÑкое развертывание"
+msgstr "Об автоматичеÑком развёртывании"
msgid "Abuse Reports"
-msgstr ""
+msgstr "Отчёты о Жалобах"
msgid "Access Tokens"
-msgstr ""
+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 ""
+msgstr "ДоÑтуп к вышедшим из ÑÑ‚Ñ€Ð¾Ñ Ñ…Ñ€Ð°Ð½Ð¸Ð»Ð¸Ñ‰Ð°Ð¼ временно отключен Ð´Ð»Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñти Ð¼Ð¾Ð½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² целÑÑ… воÑÑтановлениÑ. СброÑьте информацию о хранилищах поÑле уÑÑ‚Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ñ‹, чтобы разрешить доÑтуп."
msgid "Account"
-msgstr ""
+msgstr "Ð£Ñ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ"
msgid "Active"
msgstr "Ðктивный"
@@ -95,13 +101,13 @@ msgid "Add new directory"
msgstr "Добавить каталог"
msgid "All"
-msgstr ""
+msgstr "Ð’Ñе"
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
-msgstr ""
+msgstr "ПриложениÑ"
msgid "Archived project! Repository is read-only"
msgstr "Ðрхивный проект! Репозиторий доÑтупен только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ"
@@ -113,18 +119,42 @@ msgid "Are you sure you want to discard your changes?"
msgstr "Ð’Ñ‹ уверены, что Ð’Ñ‹ хотите отменить Ваши изменениÑ?"
msgid "Are you sure you want to reset registration token?"
-msgstr ""
+msgstr "Ð’Ñ‹ уверены, что Ð’Ñ‹ хотите ÑброÑить Ñтот ключ региÑтрации?"
msgid "Are you sure you want to reset the health check token?"
-msgstr ""
+msgstr "Ð’Ñ‹ уверены, что Ð’Ñ‹ хотите ÑброÑить Ñтот ключ проверки работоÑпоÑобноÑти?"
msgid "Are you sure?"
msgstr "Вы уверены?"
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Приложить файл через drag &amp; drop или %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -181,6 +211,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Ветка"
@@ -199,6 +232,90 @@ 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 "Обзор"
@@ -215,7 +332,7 @@ msgid "ByAuthor|by"
msgstr "по автору"
msgid "CI / CD"
-msgstr ""
+msgstr "CI / CD"
msgid "CI configuration"
msgstr "ÐаÑтройка CI"
@@ -245,7 +362,7 @@ msgid "Charts"
msgstr "Диаграммы"
msgid "Chat"
-msgstr ""
+msgstr "Чат"
msgid "Cherry-pick this commit"
msgstr "Подобрать в Ñтом коммите"
@@ -343,9 +460,6 @@ msgstr "ФикÑировано"
msgid "Compare"
msgstr "Сравнить"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "РуководÑтво учаÑтника"
@@ -443,13 +557,13 @@ msgstr[1] "Размещение"
msgstr[2] "Размещение"
msgid "Deploy Keys"
-msgstr ""
+msgstr "Ключи РазвертываниÑ"
msgid "Description"
msgstr "ОпиÑание"
msgid "Details"
-msgstr ""
+msgstr "ÐŸÐ¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ"
msgid "Directory name"
msgstr "Каталог"
@@ -494,25 +608,28 @@ msgid "Edit Pipeline Schedule %{id}"
msgstr "Изменить раÑпиÑание конвейера %{id}"
msgid "Emails"
+msgstr "Email-адреÑа"
+
+msgid "Enable in settings"
msgstr ""
msgid "EventFilterBy|Filter by all"
-msgstr ""
+msgstr "Фильтр по вÑему"
msgid "EventFilterBy|Filter by comments"
-msgstr ""
+msgstr "Фильтр по комментарию"
msgid "EventFilterBy|Filter by issue events"
-msgstr ""
+msgstr "Фильтр по ÑобытиÑм обÑуждений"
msgid "EventFilterBy|Filter by merge events"
-msgstr ""
+msgstr "Фильтр по ÑобытиÑм ÑлиÑний"
msgid "EventFilterBy|Filter by push events"
-msgstr ""
+msgstr "Фильтр по ÑобытиÑм отправки"
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "Фильтр по команде"
msgid "Every day (at 4:00am)"
msgstr "Ежедневно (в 4:00)"
@@ -523,6 +640,9 @@ msgstr "ЕжемеÑÑчно (каждое 1-е чиÑло в 4:00)"
msgid "Every week (Sundays at 4:00am)"
msgstr "Еженедельно (по воÑкреÑениÑми в 4:00)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Ðе удалоÑÑŒ изменить владельца"
@@ -563,13 +683,13 @@ msgid "From merge request merge until deploy to production"
msgstr "От запроÑа на ÑлиÑние до Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð² рабочей Ñреде"
msgid "GPG Keys"
-msgstr ""
+msgstr "GPG Ключи"
msgid "Geo Nodes"
msgstr ""
msgid "Git storage health information has been reset"
-msgstr ""
+msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ ÑтабильноÑти Git хранилища была Ñброшена"
msgid "GitLab Runner section"
msgstr "Ð¡ÐµÐºÑ†Ð¸Ñ Gitlab Runner"
@@ -580,33 +700,48 @@ msgstr "Перейти к вашему форку"
msgid "GoToYourFork|Fork"
msgstr "Форк"
-msgid "Group overview"
+msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
-msgid "Health Check"
+msgid "GroupSettings|Share with group lock"
msgstr ""
-msgid "Health information can be retrieved from the following endpoints. More information is available"
+msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
msgstr ""
-msgid "HealthCheck|Access token is"
+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 "HealthCheck|Healthy"
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
msgstr ""
-msgid "HealthCheck|No Health Problems Detected"
+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 "HealthCheck|Unhealthy"
+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 "Home"
-msgstr "ГлавнаÑ"
-
-msgid "Hooks"
+msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name}"
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 "Housekeeping successfully started"
msgstr "ОчиÑтка уÑпешно запущена"
@@ -623,9 +758,12 @@ msgid "Introducing Cycle Analytics"
msgstr "Внедрение Цикла Ðналитик"
msgid "Issue events"
-msgstr ""
+msgstr "Ð¡Ð¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð·Ð°Ð´Ð°Ñ‡Ð¸"
msgid "Issues"
+msgstr "Задачи"
+
+msgid "Jobs"
msgstr ""
msgid "LFSStatus|Disabled"
@@ -635,7 +773,7 @@ msgid "LFSStatus|Enabled"
msgstr "Включено"
msgid "Labels"
-msgstr ""
+msgstr "Метки"
msgid "Last %d day"
msgid_plural "Last %d days"
@@ -653,10 +791,10 @@ msgid "Last commit"
msgstr "ПоÑледний коммит"
msgid "LastPushEvent|You pushed to"
-msgstr ""
+msgstr "Вы отправили в"
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "в"
msgid "Learn more in the"
msgstr "Узнайте больше в"
@@ -686,25 +824,28 @@ msgid "Median"
msgstr "Среднее"
msgid "Members"
-msgstr ""
+msgstr "УчаÑтники"
msgid "Merge Requests"
-msgstr ""
+msgstr "ЗапроÑÑ‹ на СлиÑние"
msgid "Merge events"
+msgstr "Ð¡Ð¾Ð±Ñ‹Ñ‚Ð¸Ñ ÑлиÑний"
+
+msgid "Merge request"
msgstr ""
msgid "Messages"
-msgstr ""
+msgstr "СообщениÑ"
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "добавить ключ SSH"
msgid "Monitoring"
-msgstr ""
+msgstr "Мониторинг"
msgid "More information is available|here"
-msgstr ""
+msgstr "Больше информации доÑтупно|тут"
msgid "New Issue"
msgid_plural "New Issues"
@@ -806,7 +947,7 @@ msgid "NotificationLevel|Watch"
msgstr "ОтÑлеживать"
msgid "Notifications"
-msgstr ""
+msgstr "УведомлениÑ"
msgid "OfSearchInADropdown|Filter"
msgstr "Фильтр"
@@ -818,14 +959,26 @@ msgid "Options"
msgstr "ÐаÑтройки"
msgid "Overview"
-msgstr ""
+msgstr "Обзор"
msgid "Owner"
msgstr "Владелец"
-msgid "Password"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
msgstr ""
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
+msgid "Password"
+msgstr "Пароль"
+
msgid "Pipeline"
msgstr "Конвейер"
@@ -905,13 +1058,13 @@ msgid "Pipelines charts"
msgstr "Диаграмма конвейера"
msgid "Pipelines for last month"
-msgstr ""
+msgstr "Конвеер за поÑледний меÑÑц"
msgid "Pipelines for last week"
-msgstr ""
+msgstr "Конвеер за поÑледнюю неделю"
msgid "Pipelines for last year"
-msgstr ""
+msgstr "Конвееры за поÑледний год"
msgid "Pipeline|all"
msgstr "вÑе"
@@ -926,12 +1079,9 @@ msgid "Pipeline|with stages"
msgstr "Ñо ÑтадиÑми"
msgid "Preferences"
-msgstr ""
+msgstr "ПредпочтениÑ"
-msgid "Profile Settings"
-msgstr ""
-
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -950,7 +1100,7 @@ msgid "Project access must be granted explicitly to each user."
msgstr "ДоÑтуп к проекту должен предоÑтавлÑÑ‚ÑŒÑÑ Ñвно каждому пользователю."
msgid "Project details"
-msgstr ""
+msgstr "Детали проекта"
msgid "Project export could not be deleted."
msgstr "Ðевозможно удалить ÑкÑпорт проекта."
@@ -964,14 +1114,8 @@ msgstr "ИÑтек Ñрок дейÑÑ‚Ð²Ð¸Ñ ÑÑылки на проект. СÐ
msgid "Project export started. A download link will be sent by email."
msgstr "Ðачат ÑкÑпорт проекта. СÑылка Ð´Ð»Ñ ÑÐºÐ°Ñ‡Ð¸Ð²Ð°Ð½Ð¸Ñ Ð±ÑƒÐ´ÐµÑ‚ отправлена по Ñлектронной почте."
-msgid "Project home"
-msgstr "ДомашнÑÑ Ñтраница"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
-msgstr ""
+msgstr "ПодпиÑатьÑÑ"
msgid "ProjectFeature|Disabled"
msgstr "Отключено"
@@ -994,35 +1138,38 @@ msgstr "Этап"
msgid "ProjectNetworkGraph|Graph"
msgstr "Граф"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
-msgstr ""
-
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr ""
+msgstr "Загрузка проектов"
msgid "ProjectsDropdown|Projects you visit often will appear here"
-msgstr ""
+msgstr "Проекты, которые вы чаÑто поÑещаете, будут отображатьÑÑ Ð·Ð´ÐµÑÑŒ"
msgid "ProjectsDropdown|Search your projects"
-msgstr ""
+msgstr "ПоиÑк по вашим проектам"
-msgid "ProjectsDropdown|Something went wrong on our end"
+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 "Эта функциональноÑÑ‚ÑŒ требует поддержки localStorage в вашем браузере"
+
+msgid "Push Rules"
msgstr ""
msgid "Push events"
-msgstr ""
+msgstr "Ð¡Ð¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸"
msgid "Read more"
msgstr "Подробнее"
msgid "Readme"
-msgstr ""
+msgstr "ИнÑтрукциÑ"
msgid "RefSwitcher|Branches"
msgstr "Ветки"
@@ -1030,6 +1177,9 @@ msgstr "Ветки"
msgid "RefSwitcher|Tags"
msgstr "Теги"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "СвÑзанные коммиты"
@@ -1055,19 +1205,19 @@ msgid "Remove project"
msgstr "Удалить проект"
msgid "Repository"
-msgstr ""
+msgstr "Репозиторий"
msgid "Request Access"
msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ñтупа"
msgid "Reset git storage health information"
-msgstr ""
+msgstr "СброÑить информацию о работоÑпоÑобноÑти Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ git"
msgid "Reset health check access token"
-msgstr ""
+msgstr "СброÑить ключ доÑтупа проверки работоÑпоÑобноÑти"
msgid "Reset runners registration token"
-msgstr ""
+msgstr "СброÑить ключ региÑтрации Gitlab Runners"
msgid "Revert this commit"
msgstr "Отменить Ñто изменение"
@@ -1076,7 +1226,7 @@ msgid "Revert this merge request"
msgstr "Отменить Ñтот Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
msgid "SSH Keys"
-msgstr ""
+msgstr "SSH Ключи"
msgid "Save pipeline schedule"
msgstr "Сохранить раÑпиÑание конвейра"
@@ -1084,6 +1234,9 @@ msgstr "Сохранить раÑпиÑание конвейра"
msgid "Schedule a new pipeline"
msgstr "РаÑпиÑание нового конвейера"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "Планирование конвейеров"
@@ -1097,13 +1250,13 @@ msgid "Select a timezone"
msgstr "Выбор временной зоны"
msgid "Select existing branch"
-msgstr ""
+msgstr "Выбрать ÑущеÑтвующую ветвь"
msgid "Select target branch"
msgstr "Выбор целевой ветки"
msgid "Service Templates"
-msgstr ""
+msgstr "Шаблоны Служб"
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "УÑтановите пароль в Ñвоем аккаунте, чтобы отправлÑÑ‚ÑŒ или получать код через %{protocol}."
@@ -1121,6 +1274,12 @@ msgid "SetPasswordToCloneLink|set a password"
msgstr "уÑтановить пароль"
msgid "Settings"
+msgstr "ÐаÑтройки"
+
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
msgstr ""
msgid "Showing %d event"
@@ -1130,29 +1289,131 @@ msgstr[1] "Показано %d Ñобытий"
msgstr[2] "Показано %d Ñобытий"
msgid "Snippets"
+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 code"
msgstr "ИÑходный код"
msgid "Spam Logs"
-msgstr ""
+msgstr "Спам Логи"
msgid "Specify the following URL during the Runner setup:"
-msgstr ""
+msgstr "Укажите Ñледующий URL во Ð²Ñ€ÐµÐ¼Ñ Ð½Ð°Ñтройки Gitlab Runner:"
msgid "StarProject|Star"
msgstr "Отметить"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "Ðачать %{new_merge_request} Ñ Ñтих изменений"
msgid "Start the Runner!"
-msgstr ""
+msgstr "ЗапуÑтить GitLab Runner!"
msgid "Switch branch/tag"
msgstr "Переключить ветка/тег"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "Тег"
@@ -1166,7 +1427,7 @@ msgid "Target Branch"
msgstr "Ветка"
msgid "Team"
-msgstr ""
+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 "Ðа Ñтапе напиÑÐ°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° показывает Ð²Ñ€ÐµÐ¼Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ коммита до ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа на ÑлиÑние. Данные автоматичеÑки добавÑÑ‚ÑÑ Ð¿Ð¾Ñле того, как вы Ñоздать Ñвой первый Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние."
@@ -1217,6 +1478,9 @@ 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 problems accessing Git storage: "
+msgstr "Проблемы Ñ Ð´Ð¾Ñтупом к Git хранилищу: "
+
+msgid "This is the author's first Merge Request to this project. Handle with care."
msgstr ""
msgid "This means you can not push code until you create an empty repository or import existing one."
@@ -1391,14 +1655,20 @@ msgid "UploadLink|click to upload"
msgstr "кликните Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸"
msgid "Use the following registration token during setup:"
-msgstr ""
+msgstr "ИÑпользуйте Ñледующий токен региÑтрации в процеÑÑе уÑтановки:"
msgid "Use your global notification setting"
msgstr "ИÑпользуютÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ñ‹Ð¹ наÑтройки уведомлений"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "ПроÑмотреть открытый Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Ограниченный"
@@ -1418,7 +1688,7 @@ msgid "We don't have enough data to show this stage."
msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾ Ñтапу отÑутÑтвует."
msgid "Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "Withdraw Access Request"
msgstr "Отменить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ñтупа"
@@ -1471,6 +1741,12 @@ msgstr "Ð’Ñ‹ не Ñможете получать и отправлÑÑ‚ÑŒ код
msgid "Your name"
msgstr "Ваше имÑ"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "день"
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index 1dc42901daf..ffbbe88cc51 100644
--- a/locale/uk/gitlab.po
+++ b/locale/uk/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:20-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:43-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Ukrainian\n"
"Language: uk_UA\n"
@@ -31,23 +31,26 @@ msgstr[2] "%s доданих коммітів були виключені длÑ
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} комміт %{commit_timeago}"
-msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
+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 "%{number_of_failures} від %{maximum_failures} невдач. GitLab надаÑÑ‚ÑŒ доÑтуп на наÑтупну Ñпробу."
+
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will block access for %{number_of_seconds} seconds."
-msgstr ""
+msgstr "%{number_of_failures} із %{maximum_failures} невдач. GitLab заблокує доÑтуп на %{number_of_seconds} Ñекунд."
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
-msgstr ""
+msgstr "%{number_of_failures} від %{maximum_failures} невдач. GitLab автоматично не повторюватиме Ñпробу. Скиньте інформацію Ñховища при уÑуненні проблеми."
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[0] "%{storage_name}: Ñпроба невдалого доÑтупу до Ñховища на хоÑÑ‚Ñ–:"
+msgstr[1] "%{storage_name}: %{failed_attempts} невдалі Ñпроби доÑтупу до Ñховища:"
+msgstr[2] "%{storage_name}: %{failed_attempts} невдалих Ñпроб доÑтупу до Ñховища:"
msgid "(checkout the %{link} for information on how to install it)."
-msgstr ""
+msgstr "(перейдіть за поÑиланнÑм %{link} Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ— ÑтоÑовно вÑтановленнÑ)."
msgid "1 pipeline"
msgid_plural "%d pipelines"
@@ -55,6 +58,9 @@ msgstr[0] "1 конвеєр"
msgstr[1] "%d конвеєра"
msgstr[2] "%d конвеєрів"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Це набір графічних елементів Ð´Ð»Ñ Ð±ÐµÐ·Ð¿ÐµÑ€ÐµÑ€Ð²Ð½Ð¾Ñ— інтеграції"
@@ -62,16 +68,16 @@ msgid "About auto deploy"
msgstr "Про авто розгортаннÑ"
msgid "Abuse Reports"
-msgstr ""
+msgstr "Звіти про зловживаннÑ"
msgid "Access Tokens"
-msgstr ""
+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 ""
+msgstr "ДоÑтуп до помилкових Ñховищ тимчаÑово відключений Ð´Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ÑÑ‚Ñ– Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚Ð° відновленнÑ. Скиньте інформацію про Ñховища піÑÐ»Ñ ÑƒÑÑƒÐ½ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð¸, щоб дозволити доÑтуп."
msgid "Account"
-msgstr ""
+msgstr "Обліковий запиÑ"
msgid "Active"
msgstr "Ðктивний"
@@ -97,11 +103,11 @@ msgstr "Додати новий каталог"
msgid "All"
msgstr "Ð’ÑÑ–"
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
-msgstr ""
+msgstr "Додатки"
msgid "Archived project! Repository is read-only"
msgstr "Заархівований проект! Репозиторій доÑтупний лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ"
@@ -116,15 +122,39 @@ msgid "Are you sure you want to reset registration token?"
msgstr "Ви впевнені, що бажаєте Ñкинути реєÑтраційний токен?"
msgid "Are you sure you want to reset the health check token?"
-msgstr ""
+msgstr "Ви впевнені, що Ви хочете Ñкинути цей ключ перевірки працездатноÑÑ‚Ñ–?"
msgid "Are you sure?"
+msgstr "Ви впевнені?"
+
+msgid "Artifacts"
msgstr ""
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Прикріпити файл за допомогою перетÑÐ³ÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -181,6 +211,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Гілка"
@@ -199,6 +232,90 @@ 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 "ПереглÑнути каталог"
@@ -215,7 +332,7 @@ msgid "ByAuthor|by"
msgstr "від"
msgid "CI / CD"
-msgstr ""
+msgstr "CI / CD"
msgid "CI configuration"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ CI"
@@ -224,7 +341,7 @@ msgid "Cancel"
msgstr "СкаÑувати"
msgid "Cancel edit"
-msgstr ""
+msgstr "Відмінити правку"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Вибрати в гілці"
@@ -245,7 +362,7 @@ msgid "Charts"
msgstr "Графіки"
msgid "Chat"
-msgstr ""
+msgstr "Чат"
msgid "Cherry-pick this commit"
msgstr "Cherry-pick в цьому комміті"
@@ -308,7 +425,7 @@ msgid "CiStatus|running"
msgstr "виконуєтьÑÑ"
msgid "Comments"
-msgstr ""
+msgstr "Коментарі"
msgid "Commit"
msgid_plural "Commits"
@@ -343,9 +460,6 @@ msgstr "Комміт від"
msgid "Compare"
msgstr "ПорівнÑти"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "Керівництво контриб’юторів"
@@ -365,7 +479,7 @@ msgid "Create New Directory"
msgstr "Створити новий каталог"
msgid "Create a new branch"
-msgstr ""
+msgstr "Створити нову гілку"
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Створити токен доÑтупу Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ аккауета, щоб відправлÑти або отримувати через %{protocol}."
@@ -443,19 +557,19 @@ msgstr[1] "РозгортаннÑ"
msgstr[2] "Розгортань"
msgid "Deploy Keys"
-msgstr ""
+msgstr "Ключи Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ"
msgid "Description"
msgstr "ОпиÑ"
msgid "Details"
-msgstr ""
+msgstr "Деталі"
msgid "Directory name"
msgstr "Ім'Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ñƒ"
msgid "Discard changes"
-msgstr ""
+msgstr "СкаÑувати зміни"
msgid "Don't show again"
msgstr "Ðе показувати знову"
@@ -494,25 +608,28 @@ msgid "Edit Pipeline Schedule %{id}"
msgstr "Редагувати Розклад Конвеєра %{id}"
msgid "Emails"
+msgstr "ÐдреÑи електронної пошти"
+
+msgid "Enable in settings"
msgstr ""
msgid "EventFilterBy|Filter by all"
-msgstr ""
+msgstr "Ð’ÑÑ–"
msgid "EventFilterBy|Filter by comments"
-msgstr ""
+msgstr "Коментарю"
msgid "EventFilterBy|Filter by issue events"
-msgstr ""
+msgstr "Проблеми"
msgid "EventFilterBy|Filter by merge events"
-msgstr ""
+msgstr "Запити на злиттÑ"
msgid "EventFilterBy|Filter by push events"
-msgstr ""
+msgstr "По відправленні комміту"
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "За командою"
msgid "Every day (at 4:00am)"
msgstr "Кожен день (в 4:00 ранку)"
@@ -523,6 +640,9 @@ msgstr "Кожен міÑÑць (1-го чиÑла о 4:00 ранку)"
msgid "Every week (Sundays at 4:00am)"
msgstr "Ð©Ð¾Ñ‚Ð¸Ð¶Ð½Ñ (в неділю о 4:00 ранку)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ влаÑника"
@@ -563,16 +683,16 @@ msgid "From merge request merge until deploy to production"
msgstr "З об'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð½Ð° ПРОД"
msgid "GPG Keys"
-msgstr ""
+msgstr "GPG ключі"
msgid "Geo Nodes"
msgstr ""
msgid "Git storage health information has been reset"
-msgstr ""
+msgstr "Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Git була Ñкинута"
msgid "GitLab Runner section"
-msgstr ""
+msgstr "Розділ GitLab Runner"
msgid "Go to your fork"
msgstr "Перейти до вашого форку"
@@ -580,33 +700,48 @@ msgstr "Перейти до вашого форку"
msgid "GoToYourFork|Fork"
msgstr "Форк"
-msgid "Group overview"
+msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
msgstr ""
-msgid "Health Check"
+msgid "GroupSettings|Share with group lock"
msgstr ""
-msgid "Health information can be retrieved from the following endpoints. More information is available"
+msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
msgstr ""
-msgid "HealthCheck|Access token is"
+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 "HealthCheck|Healthy"
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
msgstr ""
-msgid "HealthCheck|No Health Problems Detected"
+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 "HealthCheck|Unhealthy"
+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 "Home"
-msgstr "Головна"
-
-msgid "Hooks"
+msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name}"
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 "Housekeeping successfully started"
msgstr "ÐžÑ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ ÑƒÑпішно розпочато"
@@ -614,7 +749,7 @@ msgid "Import repository"
msgstr "Імпорт репозеторіÑ"
msgid "Install a Runner compatible with GitLab CI"
-msgstr ""
+msgstr "Ð’Ñтановіть Runner, ÑуміÑний з GitLab CI"
msgid "Interval Pattern"
msgstr "Шаблон інтервалу"
@@ -623,9 +758,12 @@ msgid "Introducing Cycle Analytics"
msgstr "ПредÑтавлÑємо аналітику циклу"
msgid "Issue events"
-msgstr ""
+msgstr "Події проблем"
msgid "Issues"
+msgstr "Проблеми"
+
+msgid "Jobs"
msgstr ""
msgid "LFSStatus|Disabled"
@@ -635,7 +773,7 @@ msgid "LFSStatus|Enabled"
msgstr "Увімкнено"
msgid "Labels"
-msgstr ""
+msgstr "Мітки"
msgid "Last %d day"
msgid_plural "Last %d days"
@@ -653,10 +791,10 @@ msgid "Last commit"
msgstr "ОÑтанній комміт"
msgid "LastPushEvent|You pushed to"
-msgstr ""
+msgstr "Ви надіÑлали зміни до"
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "в"
msgid "Learn more in the"
msgstr "ДізнайтеÑÑŒ більше"
@@ -686,25 +824,28 @@ msgid "Median"
msgstr "Медіана"
msgid "Members"
-msgstr ""
+msgstr "КориÑтувачі"
msgid "Merge Requests"
-msgstr ""
+msgstr "Запит на злиттÑ"
msgid "Merge events"
+msgstr "Події запит на злиттÑ"
+
+msgid "Merge request"
msgstr ""
msgid "Messages"
-msgstr ""
+msgstr "ПовідомленнÑ"
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "не додаÑте SSH ключ"
msgid "Monitoring"
-msgstr ""
+msgstr "Моніторинг"
msgid "More information is available|here"
-msgstr ""
+msgstr "тут"
msgid "New Issue"
msgid_plural "New Issues"
@@ -806,7 +947,7 @@ msgid "NotificationLevel|Watch"
msgstr "ВідÑтежувати"
msgid "Notifications"
-msgstr ""
+msgstr "СповіщеннÑ"
msgid "OfSearchInADropdown|Filter"
msgstr "Фільтр"
@@ -818,14 +959,26 @@ msgid "Options"
msgstr "Параметри"
msgid "Overview"
-msgstr ""
+msgstr "ОглÑд"
msgid "Owner"
msgstr "ВлаÑник"
-msgid "Password"
+msgid "Pagination|Last »"
msgstr ""
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
+msgid "Password"
+msgstr "Пароль"
+
msgid "Pipeline"
msgstr "Конвеєр"
@@ -905,13 +1058,13 @@ msgid "Pipelines charts"
msgstr "Чарти Конвеєрів"
msgid "Pipelines for last month"
-msgstr ""
+msgstr "Конвеєри за оÑтанній міÑÑць"
msgid "Pipelines for last week"
-msgstr ""
+msgstr "Конвеєри за оÑтанній тиждень"
msgid "Pipelines for last year"
-msgstr ""
+msgstr "Конвеєри за оÑтанній рік"
msgid "Pipeline|all"
msgstr "вÑÑ–"
@@ -926,12 +1079,9 @@ msgid "Pipeline|with stages"
msgstr "зі ÑтадіÑми"
msgid "Preferences"
-msgstr ""
-
-msgid "Profile Settings"
-msgstr ""
+msgstr "ÐалаштуваннÑ"
-msgid "Project"
+msgid "Profile"
msgstr ""
msgid "Project '%{project_name}' queued for deletion."
@@ -950,7 +1100,7 @@ msgid "Project access must be granted explicitly to each user."
msgstr "ДоÑтуп до проекту повинен надаватиÑÑ ÐºÐ¾Ð¶Ð½Ð¾Ð¼Ñƒ кориÑтувачеві."
msgid "Project details"
-msgstr ""
+msgstr "Деталі проекту"
msgid "Project export could not be deleted."
msgstr "Ðеможливо видалити екÑпорт проекту."
@@ -964,14 +1114,8 @@ msgstr "ЗакінчивÑÑ Ñ‚ÐµÑ€Ð¼Ñ–Ð½ дії поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° проÐ
msgid "Project export started. A download link will be sent by email."
msgstr "Розпочато екÑпорт проекту. ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ð»Ñ ÑÐºÐ°Ñ‡ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÑƒÐ´Ðµ надіÑлана електронною поштою."
-msgid "Project home"
-msgstr "Ð”Ð¾Ð¼Ð°ÑˆÐ½Ñ Ñторінка проекту"
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
-msgstr ""
+msgstr "ПідпиÑатиÑÑ"
msgid "ProjectFeature|Disabled"
msgstr "Вимкнено"
@@ -994,29 +1138,32 @@ msgstr "Етап"
msgid "ProjectNetworkGraph|Graph"
msgstr "ІÑторіÑ"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
-msgstr ""
-
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr ""
+msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð²"
msgid "ProjectsDropdown|Projects you visit often will appear here"
-msgstr ""
+msgstr "Проекти, Ñкі ви чаÑто відвідуєте, будуть відображені тут"
msgid "ProjectsDropdown|Search your projects"
-msgstr ""
+msgstr "Пошук по ваших проектах"
-msgid "ProjectsDropdown|Something went wrong on our end"
+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 "Ð¦Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±ÑƒÑ” підтримки localStorage вашим браузером"
+
+msgid "Push Rules"
msgstr ""
msgid "Push events"
-msgstr ""
+msgstr "Push події"
msgid "Read more"
msgstr "Докладніше"
@@ -1030,6 +1177,9 @@ msgstr "Гілки"
msgid "RefSwitcher|Tags"
msgstr "Теги"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "Пов'Ñзані Комміти"
@@ -1055,19 +1205,19 @@ msgid "Remove project"
msgstr "Видалити проект"
msgid "Repository"
-msgstr ""
+msgstr "Репозиторій"
msgid "Request Access"
msgstr "Запит доÑтупу"
msgid "Reset git storage health information"
-msgstr ""
+msgstr "Скиньте інформацію про працездатніÑÑ‚ÑŒ Ñховища git"
msgid "Reset health check access token"
-msgstr ""
+msgstr "Скиньте токен доÑтупу Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ перевірки працездатноÑÑ‚Ñ–"
msgid "Reset runners registration token"
-msgstr ""
+msgstr "Скинути реєÑтраційний токен runner-ів"
msgid "Revert this commit"
msgstr "СкаÑувати цей комміт"
@@ -1076,7 +1226,7 @@ msgid "Revert this merge request"
msgstr "СкаÑувати цей запит на злиттÑ"
msgid "SSH Keys"
-msgstr ""
+msgstr "Ключі SSH"
msgid "Save pipeline schedule"
msgstr "Зберегти Розклад Конвеєра"
@@ -1084,6 +1234,9 @@ msgstr "Зберегти Розклад Конвеєра"
msgid "Schedule a new pipeline"
msgstr "Розклад нового конвеєра"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "ÐŸÐ»Ð°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð²"
@@ -1097,13 +1250,13 @@ msgid "Select a timezone"
msgstr "Вибрати чаÑовий поÑÑ"
msgid "Select existing branch"
-msgstr ""
+msgstr "Виберіть гілку"
msgid "Select target branch"
msgstr "Вибір цільової гілки"
msgid "Service Templates"
-msgstr ""
+msgstr "Ð¡ÐµÑ€Ð²Ñ–Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñ–Ð²"
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Ð’Ñтановіть пароль Ñвого облікового запиÑу, щоб відправлÑти або отримувати код через %{protocol}."
@@ -1121,6 +1274,12 @@ msgid "SetPasswordToCloneLink|set a password"
msgstr "вÑтановити пароль"
msgid "Settings"
+msgstr "ÐалаштуваннÑ"
+
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
msgstr ""
msgid "Showing %d event"
@@ -1130,29 +1289,131 @@ msgstr[1] "Показано %d події"
msgstr[2] "Показано %d подій"
msgid "Snippets"
+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 code"
msgstr "Код"
msgid "Spam Logs"
-msgstr ""
+msgstr "Спам-журнал"
msgid "Specify the following URL during the Runner setup:"
-msgstr ""
+msgstr "Зазначте наÑтупний URL під Ñ‡Ð°Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Runner-а:"
msgid "StarProject|Star"
msgstr "ПідпиÑатиÑÑ"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "Почати %{new_merge_request} з цих змін"
msgid "Start the Runner!"
-msgstr ""
+msgstr "ЗапуÑÑ‚Ñ–Ñ‚ÑŒ Runner!"
msgid "Switch branch/tag"
msgstr "тег"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "Тег"
@@ -1166,7 +1427,7 @@ msgid "Target Branch"
msgstr "Цільова гілка"
msgid "Team"
-msgstr ""
+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 "Ðа Ñтадії напиÑÐ°Ð½Ð½Ñ ÐºÐ¾Ð´Ñƒ, показує Ñ‡Ð°Ñ Ð¿ÐµÑ€ÑˆÐ¾Ð³Ð¾ комміту до ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на об'єднаннÑ. Дані будуть автоматично додані піÑÐ»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ першого запиту на об'єднаннÑ."
@@ -1217,6 +1478,9 @@ 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 problems accessing Git storage: "
+msgstr "Є проблеми з доÑтупом до Ñховища: "
+
+msgid "This is the author's first Merge Request to this project. Handle with care."
msgstr ""
msgid "This means you can not push code until you create an empty repository or import existing one."
@@ -1391,14 +1655,20 @@ msgid "UploadLink|click to upload"
msgstr "ÐатиÑніть, щоб завантажити"
msgid "Use the following registration token during setup:"
-msgstr ""
+msgstr "ВикориÑтовувати токен під Ñ‡Ð°Ñ ÑƒÑтановки:"
msgid "Use your global notification setting"
msgstr "ВикориÑтовуютьÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ñ– Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½ÑŒ"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "ПереглÑд відкритих запитів на злиттÑ"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "Внутрішній"
@@ -1418,7 +1688,7 @@ msgid "We don't have enough data to show this stage."
msgstr "Ми не маємо доÑтатньо даних Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ цього етапу."
msgid "Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "Withdraw Access Request"
msgstr "СкаÑувати запит доÑтупу"
@@ -1471,6 +1741,12 @@ msgstr "Ви не зможете отримувати Ñ– відправлÑти
msgid "Your name"
msgstr "Ваше ім'Ñ"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "день"
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index d6f756e813f..4a05b159008 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:21-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:44-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@@ -27,6 +27,9 @@ msgstr[0] "为æ高页é¢åŠ è½½é€Ÿåº¦åŠæ€§èƒ½ï¼Œå·²çœç•¥äº† %s 次æ交。"
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "ç”± %{commit_author_link} æ交于 %{commit_timeago}"
+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 "已失败 %{number_of_failures} 次/最多å…许失败失败 %{maximum_failures} 次,GitLab 将继续é‡è¯•ã€‚"
@@ -47,6 +50,9 @@ msgid "1 pipeline"
msgid_plural "%d pipelines"
msgstr[0] "%d æ¡æµæ°´çº¿"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "æŒç»­é›†æˆæ•°æ®å›¾"
@@ -89,8 +95,8 @@ msgstr "添加目录"
msgid "All"
msgstr "全部"
-msgid "Appearances"
-msgstr "外观样å¼"
+msgid "Appearance"
+msgstr ""
msgid "Applications"
msgstr "应用程åº"
@@ -113,65 +119,92 @@ msgstr "确定è¦é‡ç½®å¥åº·æ£€æŸ¥ä»¤ç‰Œå—?"
msgid "Are you sure?"
msgstr "确定å—?"
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "拖放文件到此处或者 %{upload_link}"
-msgid "Authentication log"
-msgstr "认è¯æ—¥å¿—"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
+msgstr ""
msgid "Billing"
-msgstr "è´¦å•"
+msgstr ""
msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
-msgstr "%{group_name} ç›®å‰æ­£åœ¨ä½¿ç”¨ %{plan_link} 方案。"
+msgstr ""
msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
-msgstr "当æŸäº›æ–¹æ¡ˆå½“å‰ä¸å¯ç”¨æ—¶è‡ªåŠ¨é™çº§å’Œå‡çº§ã€‚"
+msgstr ""
msgid "BillingPlans|Current plan"
-msgstr "当å‰æ–¹æ¡ˆ"
+msgstr ""
msgid "BillingPlans|Customer Support"
-msgstr "客户支æŒ"
+msgstr ""
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
-msgstr "通过阅读%{faq_link} 了解关于æ¯ä¸ªæ–¹æ¡ˆçš„更多信æ¯ã€‚"
+msgstr ""
msgid "BillingPlans|Manage plan"
-msgstr "管ç†æ–¹æ¡ˆ"
+msgstr ""
msgid "BillingPlans|Please contact %{customer_support_link} in that case."
-msgstr "在这ç§æƒ…况下,请è”ç³» %{customer_support_link}。"
+msgstr ""
msgid "BillingPlans|See all %{plan_name} features"
-msgstr "查看 %{plan_name} 的所有功能"
+msgstr ""
msgid "BillingPlans|This group uses the plan associated with its parent group."
-msgstr "该群组使用与它的父团队相关è”的计划。"
+msgstr ""
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
-msgstr "请访问 %{parent_billing_page_link} 的计费方案部分æ¥ç®¡ç†è¯¥å›¢é˜Ÿçš„计费方案,。"
+msgstr ""
msgid "BillingPlans|Upgrade"
-msgstr "å‡çº§"
+msgstr ""
msgid "BillingPlans|You are currently on the %{plan_link} plan."
-msgstr "ä½ ç›®å‰æ­£åœ¨ä½¿ç”¨ %{plan_link} 方案。"
+msgstr ""
msgid "BillingPlans|frequently asked questions"
-msgstr "常è§é—®é¢˜"
+msgstr ""
msgid "BillingPlans|monthly"
-msgstr "æ¯æœˆ"
+msgstr ""
msgid "BillingPlans|paid annually at %{price_per_year}"
-msgstr "æ¯å¹´æ”¯ä»˜ %{price_per_year}"
+msgstr ""
msgid "BillingPlans|per user"
-msgstr "æ¯ä¸ªç”¨æˆ·"
+msgstr ""
msgid "Billinglans|Downgrade"
-msgstr "é™çº§"
+msgstr ""
+
+msgid "Board"
+msgstr ""
msgid "Branch"
msgid_plural "Branches"
@@ -189,6 +222,90 @@ 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 "æµè§ˆç›®å½•"
@@ -331,9 +448,6 @@ msgstr "æ交者:"
msgid "Compare"
msgstr "比较"
-msgid "Container Registry"
-msgstr "容器注册表"
-
msgid "Contribution guide"
msgstr "贡献指å—"
@@ -341,7 +455,7 @@ msgid "Contributors"
msgstr "贡献者"
msgid "Copy SSH public key to clipboard"
-msgstr "å°† SSH 公钥å¤åˆ¶åˆ°å‰ªè´´æ¿"
+msgstr ""
msgid "Copy URL to clipboard"
msgstr "å¤åˆ¶ URL 到剪贴æ¿"
@@ -482,6 +596,9 @@ msgstr "编辑 %{id} æµæ°´çº¿è®¡åˆ’"
msgid "Emails"
msgstr "电å­é‚®ä»¶"
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "全部"
@@ -509,6 +626,9 @@ msgstr "æ¯æœˆæ‰§è¡Œï¼ˆæ¯æœˆ 1 日凌晨 4 点)"
msgid "Every week (Sundays at 4:00am)"
msgstr "æ¯å‘¨æ‰§è¡Œï¼ˆå‘¨æ—¥å‡Œæ™¨ 4 点)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "无法å˜æ›´æ‰€æœ‰è€…"
@@ -550,7 +670,7 @@ msgid "GPG Keys"
msgstr "GPG 密钥"
msgid "Geo Nodes"
-msgstr "Geo 节点"
+msgstr ""
msgid "Git storage health information has been reset"
msgstr "Git 存储å¥åº·ä¿¡æ¯å·²é‡ç½®"
@@ -564,8 +684,29 @@ msgstr "跳转到派生项目"
msgid "GoToYourFork|Fork"
msgstr "跳转到派生项目"
-msgid "Group overview"
-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 "Health Check"
msgstr "å¥åº·æ£€æŸ¥"
@@ -585,12 +726,6 @@ msgstr "没有检测到å¥åº·é—®é¢˜"
msgid "HealthCheck|Unhealthy"
msgstr "éžå¥åº·"
-msgid "Home"
-msgstr "首页"
-
-msgid "Hooks"
-msgstr "é’©å­"
-
msgid "Housekeeping successfully started"
msgstr "已开始维护"
@@ -612,6 +747,9 @@ msgstr "议题事件"
msgid "Issues"
msgstr "议题"
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "åœç”¨"
@@ -653,14 +791,14 @@ msgid "Leave project"
msgstr "退出项目"
msgid "License"
-msgstr "许å¯"
+msgstr ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "最多显示 %d 个事件"
msgid "Locked Files"
-msgstr "é”定的文件"
+msgstr ""
msgid "Median"
msgstr "中ä½æ•°"
@@ -674,6 +812,9 @@ msgstr "åˆå¹¶è¯·æ±‚"
msgid "Merge events"
msgstr "åˆå¹¶äº‹ä»¶"
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr "消æ¯"
@@ -801,6 +942,18 @@ msgstr "概览"
msgid "Owner"
msgstr "所有者"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr "密ç "
@@ -817,7 +970,7 @@ msgid "Pipeline Schedules"
msgstr "æµæ°´çº¿è®¡åˆ’"
msgid "Pipeline quota"
-msgstr "æµæ°´çº¿é…é¢"
+msgstr ""
msgid "PipelineCharts|Failed:"
msgstr "失败:"
@@ -906,11 +1059,8 @@ msgstr "于阶段"
msgid "Preferences"
msgstr "å好设置"
-msgid "Profile Settings"
-msgstr "账户设置"
-
-msgid "Project"
-msgstr "项目"
+msgid "Profile"
+msgstr ""
msgid "Project '%{project_name}' queued for deletion."
msgstr "项目 '%{project_name}' 已进入删除队列。"
@@ -942,12 +1092,6 @@ msgstr "项目导出链接已过期。请从项目设置中é‡æ–°ç”Ÿæˆé¡¹ç›®å¯¼
msgid "Project export started. A download link will be sent by email."
msgstr "项目导出已开始。下载链接将通过电å­é‚®ä»¶å‘é€ã€‚"
-msgid "Project home"
-msgstr "项目首页"
-
-msgid "Project overview"
-msgstr "项目概览"
-
msgid "ProjectActivityRSS|Subscribe"
msgstr "订阅"
@@ -972,25 +1116,28 @@ msgstr "阶段"
msgid "ProjectNetworkGraph|Graph"
msgstr "分支图"
-msgid "Push Rules"
-msgstr "推é€è§„则"
-
-msgid "ProjectsDropdown|Loading projects"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr ""
+msgid "ProjectsDropdown|Loading projects"
+msgstr "加载项目中"
msgid "ProjectsDropdown|Projects you visit often will appear here"
-msgstr ""
+msgstr "您ç»å¸¸è®¿é—®çš„项目将出现在这里"
msgid "ProjectsDropdown|Search your projects"
-msgstr ""
+msgstr "æœç´¢æ‚¨çš„项目"
-msgid "ProjectsDropdown|Something went wrong on our end"
+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 "此功能需è¦æµè§ˆå™¨æ”¯æŒ localStorage"
+
+msgid "Push Rules"
msgstr ""
msgid "Push events"
@@ -1008,6 +1155,9 @@ msgstr "分支"
msgid "RefSwitcher|Tags"
msgstr "标签"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "相关的æ交"
@@ -1062,6 +1212,9 @@ msgstr "ä¿å­˜æµæ°´çº¿è®¡åˆ’"
msgid "Schedule a new pipeline"
msgstr "新建æµæ°´çº¿è®¡åˆ’"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "æµæ°´çº¿è®¡åˆ’"
@@ -1101,6 +1254,12 @@ msgstr "设置密ç "
msgid "Settings"
msgstr "设置"
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "显示 %d 个事件"
@@ -1108,6 +1267,102 @@ msgstr[0] "显示 %d 个事件"
msgid "Snippets"
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 code"
msgstr "æºä»£ç "
@@ -1120,6 +1375,9 @@ msgstr "在 Runner 设置时指定以下 URL:"
msgid "StarProject|Star"
msgstr "星标"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "由此更改 %{new_merge_request}"
@@ -1129,6 +1387,9 @@ msgstr "å¯åŠ¨ Runner!"
msgid "Switch branch/tag"
msgstr "切æ¢åˆ†æ”¯/标签"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "标签"
@@ -1193,6 +1454,9 @@ msgstr "中ä½æ•°æ˜¯ä¸€ä¸ªæ•°åˆ—中最中间的值。例如在 3ã€5ã€9 之间ï
msgid "There are problems accessing Git storage: "
msgstr "访问 Git 存储时出现问题:"
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "在创建一个空的存储库或导入现有存储库之å‰ï¼Œå°†æ— æ³•æŽ¨é€ä»£ç ã€‚"
@@ -1366,9 +1630,15 @@ msgstr "在安装过程中使用以下注册令牌:"
msgid "Use your global notification setting"
msgstr "使用全局通知设置"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "查看待处ç†çš„åˆå¹¶è¯·æ±‚"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "内部"
@@ -1441,6 +1711,12 @@ msgstr "在账å·ä¸­ %{add_ssh_key_link} 之å‰å°†æ— æ³•é€šè¿‡ SSH 拉å–或推é
msgid "Your name"
msgstr "您的åå­—"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "天"
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index 48b86508d1e..c3b6cc72aed 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:21-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:44-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Traditional, Hong Kong\n"
"Language: zh_HK\n"
@@ -27,6 +27,9 @@ msgstr[0] "為æ高é é¢åŠ è¼‰é€Ÿåº¦åŠæ€§èƒ½ï¼Œå·²çœç•¥äº† %s 次æ交。"
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "ç”± %{commit_author_link} æ交於 %{commit_timeago}"
+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 "已失敗 %{number_of_failures} 次,最大失敗 %{maximum_failures} 次,GitLab å°‡é‡è©¦ã€‚"
@@ -47,6 +50,9 @@ msgid "1 pipeline"
msgid_plural "%d pipelines"
msgstr[0] "%d æ¢æµæ°´ç·š"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "相關æŒçºŒé›†æˆçš„圖åƒé›†åˆ"
@@ -89,7 +95,7 @@ msgstr "添加新目錄"
msgid "All"
msgstr "全部"
-msgid "Appearances"
+msgid "Appearance"
msgstr ""
msgid "Applications"
@@ -113,10 +119,34 @@ msgstr "確定è¦é‡ç½®å¥åº·æª¢æŸ¥ä»¤ç‰Œå—Žï¼Ÿ"
msgid "Are you sure?"
msgstr "確定嗎?"
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "拖放文件到此處或者 %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -173,6 +203,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "分支"
@@ -189,6 +222,90 @@ 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 "ç€è¦½ç›®éŒ„"
@@ -331,9 +448,6 @@ msgstr "æ交者:"
msgid "Compare"
msgstr "比較"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "è²¢ç»æŒ‡å—"
@@ -482,6 +596,9 @@ msgstr "編輯 %{id} æµæ°´ç·šè¨ˆåŠƒ"
msgid "Emails"
msgstr ""
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "全部"
@@ -509,6 +626,9 @@ msgstr "æ¯æœˆåŸ·è¡Œï¼ˆæ¯æœˆ 1 日淩晨 4 點)"
msgid "Every week (Sundays at 4:00am)"
msgstr "æ¯é€±åŸ·è¡Œï¼ˆå‘¨æ—¥æ·©æ™¨ 4 點)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "無法變更所有者"
@@ -564,7 +684,28 @@ msgstr "跳轉到派生項目"
msgid "GoToYourFork|Fork"
msgstr "跳轉到派生項目"
-msgid "Group overview"
+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 "Health Check"
@@ -585,12 +726,6 @@ msgstr "沒有檢測到å¥åº·å•é¡Œ"
msgid "HealthCheck|Unhealthy"
msgstr "ä¸è‰¯"
-msgid "Home"
-msgstr "首é "
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "已開始維護"
@@ -612,6 +747,9 @@ msgstr "議題事件 (issue event)"
msgid "Issues"
msgstr ""
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "åœç”¨"
@@ -674,6 +812,9 @@ msgstr ""
msgid "Merge events"
msgstr "åˆä½µäº‹ä»¶ (merge event)"
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -801,6 +942,18 @@ msgstr ""
msgid "Owner"
msgstr "所有者"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr ""
@@ -906,12 +1059,9 @@ msgstr "於階段"
msgid "Preferences"
msgstr ""
-msgid "Profile Settings"
+msgid "Profile"
msgstr ""
-msgid "Project"
-msgstr "專案"
-
msgid "Project '%{project_name}' queued for deletion."
msgstr "項目 '%{project_name}' 已進入刪除隊列。"
@@ -942,12 +1092,6 @@ msgstr "項目導出éˆæŽ¥å·²éŽæœŸã€‚請從項目設置中é‡æ–°ç”Ÿæˆé …目導
msgid "Project export started. A download link will be sent by email."
msgstr "項目導出已開始。下載éˆæŽ¥å°‡é€šéŽé›»å­éƒµä»¶ç™¼é€ã€‚"
-msgid "Project home"
-msgstr "項目首é "
-
-msgid "Project overview"
-msgstr ""
-
msgid "ProjectActivityRSS|Subscribe"
msgstr "訂閱"
@@ -972,27 +1116,30 @@ msgstr "階段"
msgid "ProjectNetworkGraph|Graph"
msgstr "分支圖"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-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"
+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 "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr "推é€äº‹ä»¶ (push event) "
@@ -1008,6 +1155,9 @@ msgstr "分支"
msgid "RefSwitcher|Tags"
msgstr "標籤"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "相關的æ交"
@@ -1062,6 +1212,9 @@ msgstr "ä¿å­˜æµæ°´ç·šè¨ˆåŠƒ"
msgid "Schedule a new pipeline"
msgstr "新建æµæ°´ç·šè¨ˆåŠƒ"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "æµæ°´ç·šè¨ˆåŠƒ"
@@ -1101,6 +1254,12 @@ msgstr "設置密碼"
msgid "Settings"
msgstr ""
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "顯示 %d 個事件"
@@ -1108,6 +1267,102 @@ msgstr[0] "顯示 %d 個事件"
msgid "Snippets"
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 code"
msgstr "æºä»£ç¢¼"
@@ -1120,6 +1375,9 @@ msgstr "在 Runner 設置時指定以下 URL:"
msgid "StarProject|Star"
msgstr "星標"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "由此更改 %{new_merge_request}"
@@ -1129,6 +1387,9 @@ msgstr "é‹ä½œ Runner!"
msgid "Switch branch/tag"
msgstr "切æ›åˆ†æ”¯/標籤"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "標籤"
@@ -1193,6 +1454,9 @@ msgstr "中ä½æ•¸æ˜¯å£¹å€‹æ•¸åˆ—中最中間的值。例如在 3ã€5ã€9 之間ï
msgid "There are problems accessing Git storage: "
msgstr "è¨ªå• Git 存儲時出ç¾å•é¡Œï¼š"
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "在創建壹個空的存儲庫或導入ç¾æœ‰å­˜å„²åº«ä¹‹å‰ï¼Œæ‚¨å°‡ç„¡æ³•æŽ¨é€ä»£ç¢¼ã€‚"
@@ -1366,9 +1630,15 @@ msgstr "在安è£éŽç¨‹ä¸­ä½¿ç”¨ä»¥ä¸‹è¨»å†Šä»¤ç‰Œï¼š"
msgid "Use your global notification setting"
msgstr "使用全局通知設置"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "查看開啟的åˆä¸¦è«‹æ±‚"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "內部"
@@ -1441,6 +1711,12 @@ msgstr "在賬號中 %{add_ssh_key_link} 之å‰å°‡ç„¡æ³•é€šéŽ SSH 拉å–或推é
msgid "Your name"
msgstr "您的åå­—"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "天"
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index da6a98bdb5c..8a14cd01566 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: 2017-09-06 08:32+0200\n"
-"PO-Revision-Date: 2017-09-15 05:21-0400\n"
+"POT-Creation-Date: 2017-09-27 16:26+0200\n"
+"PO-Revision-Date: 2017-09-27 13:44-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Traditional\n"
"Language: zh_TW\n"
@@ -27,6 +27,9 @@ msgstr[0] "因效能考é‡ï¼Œä¸é¡¯ç¤º %s 個更動 (commit)。"
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_author_link} 在 %{commit_timeago} é€äº¤"
+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 "已失敗 %{number_of_failures} 次,在失敗 %{maximum_failures} æ¬¡å‰ GitLab 會é‡è©¦ã€‚"
@@ -47,6 +50,9 @@ msgid "1 pipeline"
msgid_plural "%d pipelines"
msgstr[0] "%d æ¢æµæ°´ç·š"
+msgid "1st contribution!"
+msgstr ""
+
msgid "A collection of graphs regarding Continuous Integration"
msgstr "æŒçºŒæ•´åˆ (CI) 相關的圖表"
@@ -63,7 +69,7 @@ msgid "Access to failing storages has been temporarily disabled to allow the mou
msgstr "已暫時åœç”¨å¤±æ•—çš„ Git 儲存空間。當儲存空間æ¢å¾©æ­£å¸¸å¾Œï¼Œè«‹é‡ç½®å„²å­˜ç©ºé–“å¥åº·æŒ‡æ•¸ã€‚"
msgid "Account"
-msgstr ""
+msgstr "帳號"
msgid "Active"
msgstr "啟用"
@@ -89,8 +95,8 @@ msgstr "新增目錄"
msgid "All"
msgstr "全部"
-msgid "Appearances"
-msgstr "外觀"
+msgid "Appearance"
+msgstr ""
msgid "Applications"
msgstr "應用程å¼"
@@ -113,10 +119,34 @@ msgstr "確定è¦é‡ç½®å¥åº·æª¢æŸ¥å­˜å–憑證 (access token) 嗎?"
msgid "Are you sure?"
msgstr "確定嗎?"
+msgid "Artifacts"
+msgstr ""
+
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "拖放檔案到此處或者 %{upload_link}"
-msgid "Authentication log"
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Auto DevOps (Beta)"
+msgstr ""
+
+msgid "Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "Auto DevOps documentation"
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
+msgstr ""
+
+msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the"
msgstr ""
msgid "Billing"
@@ -173,6 +203,9 @@ msgstr ""
msgid "Billinglans|Downgrade"
msgstr ""
+msgid "Board"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "分支 (branch) "
@@ -189,6 +222,90 @@ msgstr "切æ›åˆ†æ”¯ (branch)"
msgid "Branches"
msgstr "分支 (branch) "
+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 "ç€è¦½ç›®éŒ„"
@@ -331,9 +448,6 @@ msgstr "é€äº¤è€…為 "
msgid "Compare"
msgstr "比較"
-msgid "Container Registry"
-msgstr ""
-
msgid "Contribution guide"
msgstr "å”作指å—"
@@ -429,7 +543,7 @@ msgid_plural "Deploys"
msgstr[0] "部署"
msgid "Deploy Keys"
-msgstr ""
+msgstr "部署金鑰"
msgid "Description"
msgstr "æè¿°"
@@ -482,6 +596,9 @@ msgstr "編輯 %{id} æµæ°´ç·š (pipeline) 排程"
msgid "Emails"
msgstr "é›»å­éƒµä»¶"
+msgid "Enable in settings"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "顯示全部"
@@ -509,6 +626,9 @@ msgstr "æ¯æœˆåŸ·è¡Œï¼ˆæ¯æœˆä¸€æ—¥æ·©æ™¨å››é»žï¼‰"
msgid "Every week (Sundays at 4:00am)"
msgstr "æ¯é€±åŸ·è¡Œï¼ˆé€±æ—¥æ·©æ™¨ 四點)"
+msgid "Explore projects"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr "無法變更所有權"
@@ -547,7 +667,7 @@ msgid "From merge request merge until deploy to production"
msgstr "從請求被åˆä½µå¾Œ (merge request merged) 直到部署至營é‹ç’°å¢ƒ"
msgid "GPG Keys"
-msgstr ""
+msgstr "GPG 金鑰"
msgid "Geo Nodes"
msgstr ""
@@ -564,8 +684,29 @@ msgstr "å‰å¾€æ‚¨çš„分支 (fork) "
msgid "GoToYourFork|Fork"
msgstr "å‰å¾€æ‚¨çš„分支 (fork) "
-msgid "Group overview"
-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 "Health Check"
msgstr "å¥åº·æª¢æŸ¥"
@@ -585,12 +726,6 @@ msgstr "沒有檢測到å¥åº·å•é¡Œ"
msgid "HealthCheck|Unhealthy"
msgstr "ä¸è‰¯"
-msgid "Home"
-msgstr "首é "
-
-msgid "Hooks"
-msgstr ""
-
msgid "Housekeeping successfully started"
msgstr "已開始維護"
@@ -612,6 +747,9 @@ msgstr "議題 (issue) 事件"
msgid "Issues"
msgstr "議題"
+msgid "Jobs"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "åœç”¨"
@@ -669,13 +807,16 @@ msgid "Members"
msgstr "æˆå“¡"
msgid "Merge Requests"
-msgstr ""
+msgstr "åˆä½µè«‹æ±‚ (merge request)"
msgid "Merge events"
msgstr "åˆä½µ (merge) 事件"
+msgid "Merge request"
+msgstr ""
+
msgid "Messages"
-msgstr "訊æ¯"
+msgstr "公告"
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "新增 SSH 金鑰"
@@ -801,6 +942,18 @@ msgstr "總覽"
msgid "Owner"
msgstr "所有權"
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
msgid "Password"
msgstr "密碼"
@@ -904,14 +1057,11 @@ msgid "Pipeline|with stages"
msgstr "於階段"
msgid "Preferences"
-msgstr ""
+msgstr "å好設定"
-msgid "Profile Settings"
+msgid "Profile"
msgstr ""
-msgid "Project"
-msgstr "專案"
-
msgid "Project '%{project_name}' queued for deletion."
msgstr "專案 '%{project_name}' 已加入刪除佇列。"
@@ -942,12 +1092,6 @@ msgstr "專案的匯出連çµå·²å¤±æ•ˆã€‚請到專案設定中產生新的連çµ
msgid "Project export started. A download link will be sent by email."
msgstr "專案導出已開始。完æˆå¾Œä¸‹è¼‰é€£çµæœƒé€åˆ°æ‚¨çš„信箱。"
-msgid "Project home"
-msgstr "專案首é "
-
-msgid "Project overview"
-msgstr "專案總覽"
-
msgid "ProjectActivityRSS|Subscribe"
msgstr "訂閱"
@@ -972,25 +1116,28 @@ msgstr "階段"
msgid "ProjectNetworkGraph|Graph"
msgstr "分支圖"
-msgid "Push Rules"
+msgid "ProjectsDropdown|Frequently visited"
msgstr ""
msgid "ProjectsDropdown|Loading projects"
msgstr ""
-msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr ""
-
msgid "ProjectsDropdown|Projects you visit often will appear here"
msgstr ""
msgid "ProjectsDropdown|Search your projects"
-msgstr ""
+msgstr "æœå°‹æ‚¨çš„專案"
-msgid "ProjectsDropdown|Something went wrong on our end"
+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 "此功能需è¦ç€è¦½å™¨æ”¯æ´ localStorage"
+
+msgid "Push Rules"
msgstr ""
msgid "Push events"
@@ -1008,6 +1155,9 @@ msgstr "分支 (branch) "
msgid "RefSwitcher|Tags"
msgstr "標籤"
+msgid "Registry"
+msgstr ""
+
msgid "Related Commits"
msgstr "相關的更動記錄 (commit) "
@@ -1054,7 +1204,7 @@ msgid "Revert this merge request"
msgstr "還原此åˆä½µè«‹æ±‚ (merge request) "
msgid "SSH Keys"
-msgstr ""
+msgstr "SSH 金鑰"
msgid "Save pipeline schedule"
msgstr "儲存æµæ°´ç·š (pipeline) 排程"
@@ -1062,6 +1212,9 @@ msgstr "儲存æµæ°´ç·š (pipeline) 排程"
msgid "Schedule a new pipeline"
msgstr "建立æµæ°´ç·š (pipeline) 排程"
+msgid "Schedules"
+msgstr ""
+
msgid "Scheduling Pipelines"
msgstr "æµæ°´ç·š (pipeline) 排程"
@@ -1101,6 +1254,12 @@ msgstr "設定密碼"
msgid "Settings"
msgstr "設定"
+msgid "Show parent pages"
+msgstr ""
+
+msgid "Show parent subgroups"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "顯示 %d 個事件"
@@ -1108,6 +1267,102 @@ msgstr[0] "顯示 %d 個事件"
msgid "Snippets"
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 code"
msgstr "原始碼"
@@ -1120,6 +1375,9 @@ msgstr "åœ¨å®‰è£ Runner 時指定以下 URL:"
msgid "StarProject|Star"
msgstr "收è—"
+msgid "Starred projects"
+msgstr ""
+
msgid "Start a %{new_merge_request} with these changes"
msgstr "以這些改動建立一個新的 %{new_merge_request} "
@@ -1129,6 +1387,9 @@ msgstr "å•Ÿå‹• Runner!"
msgid "Switch branch/tag"
msgstr "切æ›åˆ†æ”¯ (branch) 或標籤"
+msgid "System Hooks"
+msgstr ""
+
msgid "Tag"
msgid_plural "Tags"
msgstr[0] "標籤"
@@ -1193,6 +1454,9 @@ msgstr "中ä½æ•¸æ˜¯ä¸€å€‹æ•¸åˆ—中最中間的值。例如在 3ã€5ã€9 之間ï
msgid "There are problems accessing Git storage: "
msgstr "å­˜å– Git 儲存空間時出ç¾å•é¡Œï¼š"
+msgid "This is the author's first Merge Request to this project. Handle with care."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "這代表在您建立一個空的檔案庫 (repository) 或是匯入一個ç¾å­˜çš„檔案庫之å‰ï¼Œæ‚¨å°‡ç„¡æ³•ä¸Šå‚³æ›´æ–° (push) 。"
@@ -1366,9 +1630,15 @@ msgstr "在安è£éŽç¨‹ä¸­ä½¿ç”¨æ­¤è¨»å†Šæ†‘è­‰ (registration token):"
msgid "Use your global notification setting"
msgstr "使用全域通知設定"
+msgid "View file @ "
+msgstr ""
+
msgid "View open merge request"
msgstr "查看此分支的åˆä½µè«‹æ±‚ (merge request)"
+msgid "View replaced file @ "
+msgstr ""
+
msgid "VisibilityLevel|Internal"
msgstr "內部"
@@ -1388,7 +1658,7 @@ msgid "We don't have enough data to show this stage."
msgstr "因該階段的資料ä¸è¶³è€Œç„¡æ³•é¡¯ç¤ºç›¸é—œè³‡è¨Š"
msgid "Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "Withdraw Access Request"
msgstr "å–消權é™ç”³è«‹"
@@ -1441,6 +1711,12 @@ msgstr "在個人帳號中 %{add_ssh_key_link} 之å‰ï¼Œ 將無法使用 SSH 上
msgid "Your name"
msgstr "您的åå­—"
+msgid "Your projects"
+msgstr ""
+
+msgid "commit"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] "天"
diff --git a/qa/Gemfile b/qa/Gemfile
index 5d089a45934..ff29824529f 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -1,5 +1,6 @@
source 'https://rubygems.org'
+gem 'pry-byebug', '~> 3.4.1', platform: :mri
gem 'capybara', '~> 2.12.1'
gem 'capybara-screenshot', '~> 1.0.14'
gem 'rake', '~> 12.0.0'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 4dd71aa5010..22d12b479cb 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -3,6 +3,7 @@ GEM
specs:
addressable (2.5.0)
public_suffix (~> 2.0, >= 2.0.2)
+ byebug (9.0.6)
capybara (2.12.1)
addressable
mime-types (>= 1.16)
@@ -13,22 +14,27 @@ GEM
capybara-screenshot (1.0.14)
capybara (>= 1.0, < 3)
launchy
- capybara-webkit (1.12.0)
- capybara (>= 2.3.0, < 2.13.0)
- json
childprocess (0.7.0)
ffi (~> 1.0, >= 1.0.11)
+ coderay (1.1.1)
diff-lcs (1.3)
ffi (1.9.18)
- json (2.0.3)
launchy (2.4.3)
addressable (~> 2.3)
+ method_source (0.8.2)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
- mini_portile2 (2.1.0)
- nokogiri (1.7.0.1)
- mini_portile2 (~> 2.1.0)
+ mini_portile2 (2.3.0)
+ nokogiri (1.8.1)
+ mini_portile2 (~> 2.3.0)
+ pry (0.10.4)
+ coderay (~> 1.1.0)
+ method_source (~> 0.8.1)
+ slop (~> 3.4)
+ pry-byebug (3.4.2)
+ byebug (~> 9.0)
+ pry (~> 0.10)
public_suffix (2.0.5)
rack (2.0.1)
rack-test (0.6.3)
@@ -52,6 +58,7 @@ GEM
childprocess (~> 0.5)
rubyzip (~> 1.0)
websocket (~> 1.0)
+ slop (3.6.0)
websocket (1.2.4)
xpath (2.0.0)
nokogiri (~> 1.3)
@@ -62,10 +69,10 @@ PLATFORMS
DEPENDENCIES
capybara (~> 2.12.1)
capybara-screenshot (~> 1.0.14)
- capybara-webkit (~> 1.12.0)
+ pry-byebug (~> 3.4.1)
rake (~> 12.0.0)
rspec (~> 3.5)
selenium-webdriver (~> 2.53)
BUNDLED WITH
- 1.14.6
+ 1.15.4
diff --git a/qa/README.md b/qa/README.md
index b6b5a76f1d3..e0ebb53a2e9 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -16,3 +16,22 @@ against any existing instance.
1. When we release a new version of GitLab, we build a Docker images for it.
1. Along with GitLab Docker Images we also build and publish GitLab QA images.
1. GitLab QA project uses these images to execute integration tests.
+
+## How can I use it?
+
+You can use GitLab QA to exercise tests on any live instance! For example, the
+follow call would login to the local GitLab instance and run all specs in
+`qa/specs/features`:
+
+```
+GITLAB_USERNAME='root' GITLAB_PASSWORD='5iveL!fe' bin/qa Test::Instance http://localhost
+```
+
+You can also supply a specific tests to run as another parameter. For example, to
+test the EE license specs, you can run:
+
+```
+EE_LICENSE="<YOUR LICENSE KEY>" GITLAB_USERNAME='root' GITLAB_PASSWORD='5iveL!fe' bin/qa Test::Instance http://localhost qa/ee
+```
+
+All [supported environment variables are here](https://gitlab.com/gitlab-org/gitlab-qa#supported-environment-variables).
diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb
index b01a4e10f93..baa06b1c75e 100644
--- a/qa/qa/page/admin/menu.rb
+++ b/qa/qa/page/admin/menu.rb
@@ -3,15 +3,8 @@ module QA
module Admin
class Menu < Page::Base
def go_to_license
- within_middle_menu { click_link 'License' }
- end
-
- private
-
- def within_middle_menu
- page.within('.nav-control') do
- yield
- end
+ link = find_link 'License'
+ link.click
end
end
end
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index 56a270d8fcc..68d9597c4d2 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -5,8 +5,8 @@ module QA
def choose_repository_clone_http
find('#clone-dropdown').click
- page.within('#clone-dropdown') do
- find('span', text: 'HTTP').click
+ page.within('.clone-options-dropdown') do
+ click_link('HTTP')
end
end
diff --git a/qa/qa/specs/config.rb b/qa/qa/specs/config.rb
index 4dfdd6cd93c..79c681168cc 100644
--- a/qa/qa/specs/config.rb
+++ b/qa/qa/specs/config.rb
@@ -43,8 +43,7 @@ module QA
Capybara.register_driver :chrome do |app|
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
'chromeOptions' => {
- 'binary' => '/usr/bin/google-chrome-stable',
- 'args' => %w[headless no-sandbox disable-gpu window-size=1280,1024]
+ 'args' => %w[headless no-sandbox disable-gpu window-size=1280,1680]
}
)
diff --git a/scripts/lint-changelog-yaml b/scripts/lint-changelog-yaml
new file mode 100755
index 00000000000..cce5f1c7667
--- /dev/null
+++ b/scripts/lint-changelog-yaml
@@ -0,0 +1,22 @@
+#!/usr/bin/env ruby
+
+require 'yaml'
+
+invalid_changelogs = Dir['changelogs/**/*'].reject do |changelog|
+ next true if changelog =~ /(archive\.md|unreleased(-ee)?)$/
+ next false unless changelog.end_with?('.yml')
+
+ begin
+ YAML.load_file(changelog)
+ rescue
+ end
+end
+
+if invalid_changelogs.any?
+ puts "Invalid changelogs found!\n"
+ puts invalid_changelogs.sort
+ exit 1
+else
+ puts "All changelogs are valid YAML.\n"
+ exit 0
+end
diff --git a/scripts/static-analysis b/scripts/static-analysis
index 295b6f132c1..aeefb2bc96f 100755
--- a/scripts/static-analysis
+++ b/scripts/static-analysis
@@ -13,7 +13,8 @@ tasks = [
%w[yarn run eslint],
%w[bundle exec rubocop --require rubocop-rspec],
%w[scripts/lint-conflicts.sh],
- %w[bundle exec rake gettext:lint]
+ %w[bundle exec rake gettext:lint],
+ %w[scripts/lint-changelog-yaml]
]
failed_tasks = tasks.reduce({}) do |failures, task|
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index b4a22a46b51..053bd73fee3 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -207,162 +207,6 @@ describe Projects::IssuesController do
end
end
- describe 'PUT #update' do
- before do
- sign_in(user)
- project.team << [user, :developer]
- end
-
- it_behaves_like 'update invalid issuable', Issue
-
- context 'changing the assignee' do
- it 'limits the attributes exposed on the assignee' do
- assignee = create(:user)
- project.add_developer(assignee)
-
- put :update,
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: issue.iid,
- issue: { assignee_ids: [assignee.id] },
- format: :json
- body = JSON.parse(response.body)
-
- expect(body['assignees'].first.keys)
- .to match_array(%w(id name username avatar_url state web_url))
- end
- end
-
- context 'Akismet is enabled' do
- let(:project) { create(:project_empty_repo, :public) }
-
- before do
- stub_application_setting(recaptcha_enabled: true)
- allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true)
- end
-
- context 'when an issue is not identified as spam' do
- before do
- allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
- allow_any_instance_of(AkismetService).to receive(:spam?).and_return(false)
- end
-
- it 'normally updates the issue' do
- expect { update_issue(title: 'Foo') }.to change { issue.reload.title }.to('Foo')
- end
- end
-
- context 'when an issue is identified as spam' do
- before do
- allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
- end
-
- context 'when captcha is not verified' do
- def update_spam_issue
- update_issue(title: 'Spam Title', description: 'Spam lives here')
- end
-
- before do
- allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
- end
-
- it 'rejects an issue recognized as a spam' do
- expect(Gitlab::Recaptcha).to receive(:load_configurations!).and_return(true)
- expect { update_spam_issue }.not_to change { issue.reload.title }
- end
-
- it 'rejects an issue recognized as a spam when recaptcha disabled' do
- stub_application_setting(recaptcha_enabled: false)
-
- expect { update_spam_issue }.not_to change { issue.reload.title }
- end
-
- it 'creates a spam log' do
- update_spam_issue
-
- spam_logs = SpamLog.all
-
- expect(spam_logs.count).to eq(1)
- expect(spam_logs.first.title).to eq('Spam Title')
- expect(spam_logs.first.recaptcha_verified).to be_falsey
- end
-
- context 'as HTML' do
- it 'renders verify template' do
- update_spam_issue
-
- expect(response).to render_template(:verify)
- end
- end
-
- context 'as JSON' do
- before do
- update_issue({ title: 'Spam Title', description: 'Spam lives here' }, format: :json)
- end
-
- it 'renders json errors' do
- expect(json_response)
- .to eql("errors" => ["Your issue has been recognized as spam. Please, change the content or solve the reCAPTCHA to proceed."])
- end
-
- it 'returns 422 status' do
- expect(response).to have_http_status(422)
- end
- end
- end
-
- context 'when captcha is verified' do
- let(:spammy_title) { 'Whatever' }
- let!(:spam_logs) { create_list(:spam_log, 2, user: user, title: spammy_title) }
-
- def update_verified_issue
- update_issue({ title: spammy_title },
- { spam_log_id: spam_logs.last.id,
- recaptcha_verification: true })
- end
-
- before do
- allow_any_instance_of(described_class).to receive(:verify_recaptcha)
- .and_return(true)
- end
-
- it 'redirect to issue page' do
- update_verified_issue
-
- expect(response)
- .to redirect_to(project_issue_path(project, issue))
- end
-
- it 'accepts an issue after recaptcha is verified' do
- expect { update_verified_issue }.to change { issue.reload.title }.to(spammy_title)
- end
-
- it 'marks spam log as recaptcha_verified' do
- expect { update_verified_issue }.to change { SpamLog.last.recaptcha_verified }.from(false).to(true)
- end
-
- it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do
- spam_log = create(:spam_log)
-
- expect { update_issue(spam_log_id: spam_log.id, recaptcha_verification: true) }
- .not_to change { SpamLog.last.recaptcha_verified }
- end
- end
- end
-
- def update_issue(issue_params = {}, additional_params = {})
- params = {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: issue.iid,
- issue: issue_params
- }.merge(additional_params)
-
- put :update, params
- end
- end
- end
-
describe 'POST #move' do
before do
sign_in(user)
@@ -533,6 +377,146 @@ describe Projects::IssuesController do
end
end
+ describe 'PUT #update' do
+ def update_issue(issue_params: {}, additional_params: {}, id: nil)
+ id ||= issue.iid
+ params = {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: id,
+ issue: { title: 'New title' }.merge(issue_params),
+ format: :json
+ }.merge(additional_params)
+
+ put :update, params
+ end
+
+ def go(id:)
+ update_issue(id: id)
+ end
+
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ end
+
+ it_behaves_like 'restricted action', success: 200
+ it_behaves_like 'update invalid issuable', Issue
+
+ context 'changing the assignee' do
+ it 'limits the attributes exposed on the assignee' do
+ assignee = create(:user)
+ project.add_developer(assignee)
+
+ update_issue(issue_params: { assignee_ids: [assignee.id] })
+
+ body = JSON.parse(response.body)
+
+ expect(body['assignees'].first.keys)
+ .to match_array(%w(id name username avatar_url state web_url))
+ end
+ end
+
+ context 'Akismet is enabled' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ stub_application_setting(recaptcha_enabled: true)
+ allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true)
+ end
+
+ context 'when an issue is not identified as spam' do
+ before do
+ allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
+ allow_any_instance_of(AkismetService).to receive(:spam?).and_return(false)
+ end
+
+ it 'normally updates the issue' do
+ expect { update_issue(issue_params: { title: 'Foo' }) }.to change { issue.reload.title }.to('Foo')
+ end
+ end
+
+ context 'when an issue is identified as spam' do
+ before do
+ allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
+ end
+
+ context 'when captcha is not verified' do
+ before do
+ allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
+ end
+
+ it 'rejects an issue recognized as a spam' do
+ expect { update_issue }.not_to change { issue.reload.title }
+ end
+
+ it 'rejects an issue recognized as a spam when recaptcha disabled' do
+ stub_application_setting(recaptcha_enabled: false)
+
+ expect { update_issue }.not_to change { issue.reload.title }
+ end
+
+ it 'creates a spam log' do
+ update_issue(issue_params: { title: 'Spam title' })
+
+ spam_logs = SpamLog.all
+
+ expect(spam_logs.count).to eq(1)
+ expect(spam_logs.first.title).to eq('Spam title')
+ expect(spam_logs.first.recaptcha_verified).to be_falsey
+ end
+
+ it 'renders json errors' do
+ update_issue
+
+ expect(json_response)
+ .to eql("errors" => ["Your issue has been recognized as spam. Please, change the content or solve the reCAPTCHA to proceed."])
+ end
+
+ it 'returns 422 status' do
+ update_issue
+
+ expect(response).to have_http_status(422)
+ end
+ end
+
+ context 'when captcha is verified' do
+ let(:spammy_title) { 'Whatever' }
+ let!(:spam_logs) { create_list(:spam_log, 2, user: user, title: spammy_title) }
+
+ def update_verified_issue
+ update_issue(
+ issue_params: { title: spammy_title },
+ additional_params: { spam_log_id: spam_logs.last.id, recaptcha_verification: true })
+ end
+
+ before do
+ allow_any_instance_of(described_class).to receive(:verify_recaptcha)
+ .and_return(true)
+ end
+
+ it 'returns 200 status' do
+ expect(response).to have_http_status(200)
+ end
+
+ it 'accepts an issue after recaptcha is verified' do
+ expect { update_verified_issue }.to change { issue.reload.title }.to(spammy_title)
+ end
+
+ it 'marks spam log as recaptcha_verified' do
+ expect { update_verified_issue }.to change { SpamLog.last.recaptcha_verified }.from(false).to(true)
+ end
+
+ it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do
+ spam_log = create(:spam_log)
+
+ expect { update_issue(issue_params: { spam_log_id: spam_log.id, recaptcha_verification: true }) }
+ .not_to change { SpamLog.last.recaptcha_verified }
+ end
+ end
+ end
+ end
+ end
+
describe 'GET #show' do
it_behaves_like 'restricted action', success: 200
@@ -573,29 +557,6 @@ describe Projects::IssuesController do
end
end
end
-
- describe 'GET #edit' do
- it_behaves_like 'restricted action', success: 200
-
- def go(id:)
- get :edit,
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: id
- end
- end
-
- describe 'PUT #update' do
- it_behaves_like 'restricted action', success: 302
-
- def go(id:)
- put :update,
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: id,
- issue: { title: 'New title' }
- end
- end
end
describe 'POST #create' do
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index fdd7e6f173f..d01339a0b88 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -216,7 +216,7 @@ describe Projects::JobsController do
expect(json_response['text']).to eq status.text
expect(json_response['label']).to eq status.label
expect(json_response['icon']).to eq status.icon
- expect(json_response['favicon']).to eq "/assets/ci_favicons/#{status.favicon}.ico"
+ expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.ico"
end
end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 6775012bab5..e46d1995498 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -96,18 +96,6 @@ describe Projects::MergeRequestsController do
expect(response).to match_response_schema('entities/merge_request')
end
end
-
- context 'number of queries', :request_store do
- it 'verifies number of queries' do
- # pre-create objects
- merge_request
-
- recorded = ActiveRecord::QueryRecorder.new { go(format: :json) }
-
- expect(recorded.count).to be_within(5).of(30)
- expect(recorded.cached_count).to eq(0)
- end
- end
end
describe "as diff" do
@@ -658,7 +646,7 @@ describe Projects::MergeRequestsController do
expect(json_response['text']).to eq status.text
expect(json_response['label']).to eq status.label
expect(json_response['icon']).to eq status.icon
- expect(json_response['favicon']).to eq "/assets/ci_favicons/#{status.favicon}.ico"
+ expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.ico"
end
end
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 6ffe41b8608..c0337f96fc6 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -120,6 +120,40 @@ describe Projects::NotesController do
expect(note_json[:diff_discussion_html]).to be_nil
end
end
+
+ context 'with cross-reference system note', :request_store do
+ let(:new_issue) { create(:issue) }
+ let(:cross_reference) { "mentioned in #{new_issue.to_reference(issue.project)}" }
+
+ before do
+ note
+ create(:discussion_note_on_issue, :system, noteable: issue, project: issue.project, note: cross_reference)
+ end
+
+ it 'filters notes that the user should not see' do
+ get :index, request_params
+
+ expect(parsed_response[:notes].count).to eq(1)
+ expect(note_json[:id]).to eq(note.id)
+ end
+
+ it 'does not result in N+1 queries' do
+ # Instantiate the controller variables to ensure QueryRecorder has an accurate base count
+ get :index, request_params
+
+ RequestStore.clear!
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ get :index, request_params
+ end.count
+
+ RequestStore.clear!
+
+ create_list(:discussion_note_on_issue, 2, :system, noteable: issue, project: issue.project, note: cross_reference)
+
+ expect { get :index, request_params }.not_to exceed_query_limit(control_count)
+ end
+ end
end
describe 'POST create' do
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index f9d77c7ad03..167e80ed9cd 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -142,7 +142,7 @@ describe Projects::PipelinesController do
expect(json_response['text']).to eq status.text
expect(json_response['label']).to eq status.label
expect(json_response['icon']).to eq status.icon
- expect(json_response['favicon']).to eq "/assets/ci_favicons/#{status.favicon}.ico"
+ expect(json_response['favicon']).to match_asset_path("/assets/ci_favicons/#{status.favicon}.ico")
end
end
diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb
index 2805968dcd9..5d9d5351687 100644
--- a/spec/controllers/projects/registry/repositories_controller_spec.rb
+++ b/spec/controllers/projects/registry/repositories_controller_spec.rb
@@ -42,6 +42,13 @@ describe Projects::Registry::RepositoriesController do
expect { go_to_index }.to change { ContainerRepository.all.count }.by(1)
expect(ContainerRepository.first).to be_root_repository
end
+
+ it 'json has a list of projects' do
+ go_to_index(format: :json)
+
+ expect(response).to have_http_status(:ok)
+ expect(response).to match_response_schema('registry/repositories')
+ end
end
context 'when there are no tags for this repository' do
@@ -58,6 +65,31 @@ describe Projects::Registry::RepositoriesController do
it 'does not ensure root container repository' do
expect { go_to_index }.not_to change { ContainerRepository.all.count }
end
+
+ it 'responds with json if asked' do
+ go_to_index(format: :json)
+
+ expect(response).to have_http_status(:ok)
+ expect(json_response).to be_kind_of(Array)
+ end
+ end
+ end
+ end
+
+ describe 'DELETE destroy' do
+ context 'when root container repository exists' do
+ let!(:repository) do
+ create(:container_repository, :root, project: project)
+ end
+
+ before do
+ stub_container_registry_tags(repository: :any, tags: [])
+ end
+
+ it 'deletes a repository' do
+ expect { delete_repository(repository) }.to change { ContainerRepository.all.count }.by(-1)
+
+ expect(response).to have_http_status(:no_content)
end
end
end
@@ -77,8 +109,16 @@ describe Projects::Registry::RepositoriesController do
end
end
- def go_to_index
+ def go_to_index(format: :html)
get :index, namespace_id: project.namespace,
- project_id: project
+ project_id: project,
+ format: format
+ end
+
+ def delete_repository(repository)
+ delete :destroy, namespace_id: project.namespace,
+ project_id: project,
+ id: repository,
+ format: :json
end
end
diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb
index f4af3587d23..bb702ebeb23 100644
--- a/spec/controllers/projects/registry/tags_controller_spec.rb
+++ b/spec/controllers/projects/registry/tags_controller_spec.rb
@@ -4,24 +4,83 @@ describe Projects::Registry::TagsController do
let(:user) { create(:user) }
let(:project) { create(:project, :private) }
+ let(:repository) do
+ create(:container_repository, name: 'image', project: project)
+ end
+
before do
sign_in(user)
stub_container_registry_config(enabled: true)
end
- context 'when user has access to registry' do
+ describe 'GET index' do
+ let(:tags) do
+ Array.new(40) { |i| "tag#{i}" }
+ end
+
before do
- project.add_developer(user)
+ stub_container_registry_tags(repository: /image/, tags: tags)
end
- describe 'POST destroy' do
+ context 'when user can control the registry' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'receive a list of tags' do
+ get_tags
+
+ expect(response).to have_http_status(:ok)
+ expect(response).to match_response_schema('registry/tags')
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ context 'when user can read the registry' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it 'receive a list of tags' do
+ get_tags
+
+ expect(response).to have_http_status(:ok)
+ expect(response).to match_response_schema('registry/tags')
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ context 'when user does not have access to registry' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'does not receive a list of tags' do
+ get_tags
+
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ private
+
+ def get_tags
+ get :index, namespace_id: project.namespace,
+ project_id: project,
+ repository_id: repository,
+ format: :json
+ end
+ end
+
+ describe 'POST destroy' do
+ context 'when user has access to registry' do
+ before do
+ project.add_developer(user)
+ end
+
context 'when there is matching tag present' do
before do
- stub_container_registry_tags(repository: /image/, tags: %w[rc1 test.])
- end
-
- let(:repository) do
- create(:container_repository, name: 'image', project: project)
+ stub_container_registry_tags(repository: repository.path, tags: %w[rc1 test.])
end
it 'makes it possible to delete regular tag' do
@@ -37,12 +96,15 @@ describe Projects::Registry::TagsController do
end
end
end
- end
- def destroy_tag(name)
- post :destroy, namespace_id: project.namespace,
- project_id: project,
- repository_id: repository,
- id: name
+ private
+
+ def destroy_tag(name)
+ post :destroy, namespace_id: project.namespace,
+ project_id: project,
+ repository_id: repository,
+ id: name,
+ format: :json
+ end
end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 4459e227fb3..2a91a6613e6 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -289,6 +289,24 @@ describe ProjectsController do
end
end
+ it 'updates Fast Forward Merge attributes' do
+ controller.instance_variable_set(:@project, project)
+
+ params = {
+ merge_method: :ff
+ }
+
+ put :update,
+ namespace_id: project.namespace,
+ id: project.id,
+ project: params
+
+ expect(response).to have_http_status(302)
+ params.each do |param, value|
+ expect(project.public_send(param)).to eq(value)
+ end
+ end
+
def update_project(**parameters)
put :update,
namespace_id: project.namespace.path,
diff --git a/spec/factories/deployments.rb b/spec/factories/deployments.rb
index e5abfd67d60..0dd1238d6e2 100644
--- a/spec/factories/deployments.rb
+++ b/spec/factories/deployments.rb
@@ -12,7 +12,7 @@ FactoryGirl.define do
deployment.project ||= deployment.environment.project
unless deployment.project.repository_exists?
- allow(deployment.project.repository).to receive(:fetch_ref)
+ allow(deployment.project.repository).to receive(:create_ref)
end
end
end
diff --git a/spec/factories/gitaly/commit.rb b/spec/factories/gitaly/commit.rb
new file mode 100644
index 00000000000..e7966cee77b
--- /dev/null
+++ b/spec/factories/gitaly/commit.rb
@@ -0,0 +1,17 @@
+FactoryGirl.define do
+ sequence(:gitaly_commit_id) { Digest::SHA1.hexdigest(Time.now.to_f.to_s) }
+
+ factory :gitaly_commit, class: Gitaly::GitCommit do
+ skip_create
+
+ id { generate(:gitaly_commit_id) }
+ parent_ids do
+ ids = [generate(:gitaly_commit_id), generate(:gitaly_commit_id)]
+ Google::Protobuf::RepeatedField.new(:string, ids)
+ end
+ subject { "My commit" }
+ body { subject + "\nMy body" }
+ author { build(:gitaly_commit_author) }
+ committer { build(:gitaly_commit_author) }
+ end
+end
diff --git a/spec/factories/gitaly/commit_author.rb b/spec/factories/gitaly/commit_author.rb
new file mode 100644
index 00000000000..341873a2002
--- /dev/null
+++ b/spec/factories/gitaly/commit_author.rb
@@ -0,0 +1,9 @@
+FactoryGirl.define do
+ factory :gitaly_commit_author, class: Gitaly::CommitAuthor do
+ skip_create
+
+ name { generate(:name) }
+ email { generate(:email) }
+ date { Google::Protobuf::Timestamp.new(seconds: Time.now.to_i) }
+ end
+end
diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb
index ae39ba4da6b..45213dc6995 100644
--- a/spec/features/container_registry_spec.rb
+++ b/spec/features/container_registry_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Container Registry" do
+describe "Container Registry", js: true do
let(:user) { create(:user) }
let(:project) { create(:project) }
@@ -41,16 +41,19 @@ describe "Container Registry" do
expect_any_instance_of(ContainerRepository)
.to receive(:delete_tags!).and_return(true)
- click_on 'Remove repository'
+ click_on(class: 'js-remove-repo')
end
scenario 'user removes a specific tag from container repository' do
visit_container_registry
+ find('.js-toggle-repo').trigger('click')
+ wait_for_requests
+
expect_any_instance_of(ContainerRegistry::Tag)
.to receive(:delete).and_return(true)
- click_on 'Remove tag'
+ click_on(class: 'js-delete-registry')
end
end
diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb
index dfeba722ac6..ebcd0ba0dcd 100644
--- a/spec/features/copy_as_gfm_spec.rb
+++ b/spec/features/copy_as_gfm_spec.rb
@@ -446,7 +446,7 @@ describe 'Copy as GFM', js: true do
def verify(label, *gfms)
aggregate_failures(label) do
gfms.each do |gfm|
- html = gfm_to_html(gfm)
+ html = gfm_to_html(gfm).gsub(/\A&#x000A;|&#x000A;\z/, '')
output_gfm = html_to_gfm(html)
expect(output_gfm.strip).to eq(gfm.strip)
end
@@ -463,42 +463,98 @@ describe 'Copy as GFM', js: true do
let(:project) { create(:project, :repository) }
context 'from a diff' do
- before do
- visit project_commit_path(project, sample_commit.id)
- end
+ shared_examples 'copying code from a diff' do
+ context 'selecting one word of text' do
+ it 'copies as inline code' do
+ verify(
+ '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"] .line .no',
- context 'selecting one word of text' do
- it 'copies as inline code' do
- verify(
- '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"] .line .no',
+ '`RuntimeError`',
- '`RuntimeError`'
- )
+ target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'
+ )
+ end
end
- end
- context 'selecting one line of text' do
- it 'copies as inline code' do
- verify(
- '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"] .line',
+ context 'selecting one line of text' do
+ it 'copies as inline code' do
+ verify(
+ '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]',
- '`raise RuntimeError, "System commands must be given as an array of strings"`'
- )
+ '`raise RuntimeError, "System commands must be given as an array of strings"`',
+
+ target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'
+ )
+ end
+ end
+
+ context 'selecting multiple lines of text' do
+ it 'copies as a code block' do
+ verify(
+ '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"]',
+
+ <<-GFM.strip_heredoc,
+ ```ruby
+ raise RuntimeError, "System commands must be given as an array of strings"
+ end
+ ```
+ GFM
+
+ target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'
+ )
+ end
end
end
- context 'selecting multiple lines of text' do
- it 'copies as a code block' do
- verify(
- '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"]',
+ context 'inline diff' do
+ before do
+ visit project_commit_path(project, sample_commit.id, view: 'inline')
+ end
- <<-GFM.strip_heredoc,
- ```ruby
- raise RuntimeError, "System commands must be given as an array of strings"
- end
- ```
- GFM
- )
+ it_behaves_like 'copying code from a diff'
+ end
+
+ context 'parallel diff' do
+ before do
+ visit project_commit_path(project, sample_commit.id, view: 'parallel')
+ end
+
+ it_behaves_like 'copying code from a diff'
+
+ context 'selecting code on the left' do
+ it 'copies as a code block' do
+ verify(
+ '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"]',
+
+ <<-GFM.strip_heredoc,
+ ```ruby
+ unless cmd.is_a?(Array)
+ raise "System commands must be given as an array of strings"
+ end
+ ```
+ GFM
+
+ target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"].left-side'
+ )
+ end
+ end
+
+ context 'selecting code on the right' do
+ it 'copies as a code block' do
+ verify(
+ '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"]',
+
+ <<-GFM.strip_heredoc,
+ ```ruby
+ unless cmd.is_a?(Array)
+ raise RuntimeError, "System commands must be given as an array of strings"
+ end
+ ```
+ GFM
+
+ target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"].right-side'
+ )
+ end
end
end
end
@@ -587,9 +643,9 @@ describe 'Copy as GFM', js: true do
end
end
- def verify(selector, gfm)
+ def verify(selector, gfm, target: nil)
html = html_for_selector(selector)
- output_gfm = html_to_gfm(html, 'transformCodeSelection')
+ output_gfm = html_to_gfm(html, 'transformCodeSelection', target: target)
expect(output_gfm.strip).to eq(gfm.strip)
end
end
@@ -605,15 +661,21 @@ describe 'Copy as GFM', js: true do
page.evaluate_script(js)
end
- def html_to_gfm(html, transformer = 'transformGFMSelection')
+ def html_to_gfm(html, transformer = 'transformGFMSelection', target: nil)
js = <<-JS.strip_heredoc
(function(html) {
var transformer = window.gl.CopyAsGFM[#{transformer.inspect}];
var node = document.createElement('div');
- node.innerHTML = html;
+ $(html).each(function() { node.appendChild(this) });
+
+ var targetSelector = #{target.to_json};
+ var target;
+ if (targetSelector) {
+ target = document.querySelector(targetSelector);
+ }
- node = transformer(node);
+ node = transformer(node, target);
if (!node) return null;
return window.gl.CopyAsGFM.nodeToGFM(node);
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 2db6f9a2982..8ce470fc288 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -218,54 +218,15 @@ describe 'New/edit issue', :js do
context 'edit issue' do
before do
- visit edit_project_issue_path(project, issue)
- end
-
- it 'allows user to update issue' do
- expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
- expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
-
- page.within '.js-user-search' do
- expect(page).to have_content user.name
- end
-
- page.within '.js-milestone-select' do
- expect(page).to have_content milestone.title
- end
-
- click_button 'Labels'
- page.within '.dropdown-menu-labels' do
- click_link label.title
- click_link label2.title
- end
- page.within '.js-label-select' do
- expect(page).to have_content label.title
- end
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
- expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
-
- click_button 'Save changes'
-
- page.within '.issuable-sidebar' do
- page.within '.assignee' do
- expect(page).to have_content user.name
- end
-
- page.within '.milestone' do
- expect(page).to have_content milestone.title
- end
-
- page.within '.labels' do
- expect(page).to have_content label.title
- expect(page).to have_content label2.title
- end
+ visit project_issue_path(project, issue)
+ page.within('.content .issuable-actions') do
+ click_on 'Edit'
end
end
it 'description has autocomplete' do
- find('#issue_description').native.send_keys('')
- fill_in 'issue_description', with: '@'
+ find_field('issue-description').native.send_keys('')
+ fill_in 'issue-description', with: '@'
expect(page).to have_selector('.atwho-view')
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index fb763c93c66..aa8cf3b013c 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Issues' do
+describe 'Issues', :js do
include DropzoneHelper
include IssueHelpers
include SortingHelper
@@ -24,113 +24,27 @@ describe 'Issues' do
end
before do
- visit edit_project_issue_path(project, issue)
- find('.js-zen-enter').click
+ visit project_issue_path(project, issue)
+ page.within('.content .issuable-actions') do
+ find('.issuable-edit').click
+ end
+ find('.issue-details .content-block .js-zen-enter').click
end
it 'opens new issue popup' do
- expect(page).to have_content("Issue ##{issue.iid}")
+ expect(page).to have_content(issue.description)
end
end
- describe 'Editing issue assignee' do
- let!(:issue) do
- create(:issue,
- author: user,
- assignees: [user],
- project: project)
- end
-
- it 'allows user to select unassigned', js: true do
- visit edit_project_issue_path(project, issue)
-
- expect(page).to have_content "Assignee #{user.name}"
-
- first('.js-user-search').click
- click_link 'Unassigned'
-
- click_button 'Save changes'
-
- page.within('.assignee') do
- expect(page).to have_content 'No assignee - assign yourself'
- end
-
- expect(issue.reload.assignees).to be_empty
- end
- end
-
- describe 'due date', js: true do
- context 'on new form' do
- before do
- visit new_project_issue_path(project)
- end
-
- it 'saves with due date' do
- date = Date.today.at_beginning_of_month
-
- fill_in 'issue_title', with: 'bug 345'
- fill_in 'issue_description', with: 'bug description'
- find('#issuable-due-date').click
-
- page.within '.pika-single' do
- click_button date.day
- end
-
- expect(find('#issuable-due-date').value).to eq date.to_s
-
- click_button 'Submit issue'
-
- page.within '.issuable-sidebar' do
- expect(page).to have_content date.to_s(:medium)
- end
- end
- end
-
- context 'on edit form' do
- let(:issue) { create(:issue, author: user, project: project, due_date: Date.today.at_beginning_of_month.to_s) }
-
- before do
- visit edit_project_issue_path(project, issue)
- end
-
- it 'saves with due date' do
- date = Date.today.at_beginning_of_month
-
- expect(find('#issuable-due-date').value).to eq date.to_s
-
- date = date.tomorrow
-
- fill_in 'issue_title', with: 'bug 345'
- fill_in 'issue_description', with: 'bug description'
- find('#issuable-due-date').click
-
- page.within '.pika-single' do
- click_button date.day
- end
-
- expect(find('#issuable-due-date').value).to eq date.to_s
-
- click_button 'Save changes'
-
- page.within '.issuable-sidebar' do
- expect(page).to have_content date.to_s(:medium)
- end
- end
-
- it 'warns about version conflict' do
- issue.update(title: "New title")
-
- fill_in 'issue_title', with: 'bug 345'
- fill_in 'issue_description', with: 'bug description'
+ describe 'Issue info' do
+ it 'links to current issue in breadcrubs' do
+ issue = create(:issue, project: project)
- click_button 'Save changes'
+ visit project_issue_path(project, issue)
- expect(page).to have_content 'Someone edited the issue the same time you did'
- end
+ expect(find('.breadcrumbs-sub-title a')[:href]).to end_with(issue_path(issue))
end
- end
- describe 'Issue info' do
it 'excludes award_emoji from comment count' do
issue = create(:issue, author: user, assignees: [user], project: project, title: 'foobar')
create(:award_emoji, awardable: issue)
diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb
index 9bcb78d5206..4766cdf716f 100644
--- a/spec/features/merge_requests/diff_notes_avatars_spec.rb
+++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb
@@ -84,7 +84,7 @@ feature 'Diff note avatars', js: true do
end
it 'shows note avatar' do
- page.within find("[id='#{position.line_code(project.repository)}']") do
+ page.within find_line(position.line_code(project.repository)) do
find('.diff-notes-collapse').click
expect(page).to have_selector('img.js-diff-comment-avatar', count: 1)
@@ -92,7 +92,7 @@ feature 'Diff note avatars', js: true do
end
it 'shows comment on note avatar' do
- page.within find("[id='#{position.line_code(project.repository)}']") do
+ page.within find_line(position.line_code(project.repository)) do
find('.diff-notes-collapse').click
expect(first('img.js-diff-comment-avatar')["data-original-title"]).to eq("#{note.author.name}: #{note.note.truncate(17)}")
@@ -100,13 +100,13 @@ feature 'Diff note avatars', js: true do
end
it 'toggles comments when clicking avatar' do
- page.within find("[id='#{position.line_code(project.repository)}']") do
+ page.within find_line(position.line_code(project.repository)) do
find('.diff-notes-collapse').click
end
expect(page).to have_selector('.notes_holder', visible: false)
- page.within find("[id='#{position.line_code(project.repository)}']") do
+ page.within find_line(position.line_code(project.repository)) do
first('img.js-diff-comment-avatar').click
end
@@ -122,7 +122,7 @@ feature 'Diff note avatars', js: true do
wait_for_requests
- page.within find("[id='#{position.line_code(project.repository)}']") do
+ page.within find_line(position.line_code(project.repository)) do
expect(page).not_to have_selector('img.js-diff-comment-avatar')
end
end
@@ -138,7 +138,7 @@ feature 'Diff note avatars', js: true do
wait_for_requests
end
- page.within find("[id='#{position.line_code(project.repository)}']") do
+ page.within find_line(position.line_code(project.repository)) do
find('.diff-notes-collapse').trigger('click')
expect(page).to have_selector('img.js-diff-comment-avatar', count: 2)
@@ -158,7 +158,7 @@ feature 'Diff note avatars', js: true do
end
end
- page.within find("[id='#{position.line_code(project.repository)}']") do
+ page.within find_line(position.line_code(project.repository)) do
find('.diff-notes-collapse').trigger('click')
expect(page).to have_selector('img.js-diff-comment-avatar', count: 3)
@@ -176,7 +176,7 @@ feature 'Diff note avatars', js: true do
end
it 'shows extra comment count' do
- page.within find("[id='#{position.line_code(project.repository)}']") do
+ page.within find_line(position.line_code(project.repository)) do
find('.diff-notes-collapse').click
expect(find('.diff-comments-more-count')).to have_content '+1'
@@ -185,4 +185,10 @@ feature 'Diff note avatars', js: true do
end
end
end
+
+ def find_line(line_code)
+ line = find("[id='#{line_code}']")
+ line = line.find(:xpath, 'preceding-sibling::*[1][self::td]') if line.tag_name == 'td'
+ line
+ end
end
diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb
index 443b596b3c6..791cfa308c3 100644
--- a/spec/features/merge_requests/widget_spec.rb
+++ b/spec/features/merge_requests/widget_spec.rb
@@ -202,6 +202,28 @@ describe 'Merge request', :js do
end
end
+ context 'view merge request where fast-forward merge is not possible' do
+ before do
+ project.update(merge_requests_ff_only_enabled: true)
+
+ merge_request.update(
+ merge_user: merge_request.author,
+ merge_status: :cannot_be_merged
+ )
+
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'shows information about the merge error' do
+ # Wait for the `ci_status` and `merge_check` requests
+ wait_for_requests
+
+ page.within('.mr-widget-body') do
+ expect(page).to have_content('Fast-forward merge is not possible')
+ end
+ end
+ end
+
context 'merge error' do
before do
allow_any_instance_of(Repository).to receive(:merge).and_return(false)
diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb
index ad06cee4e81..2f407b13c2f 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)
+ visit project_branches_path(project, 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 ad4527a0b74..d1f5623554d 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -5,12 +5,6 @@ describe 'Branches' do
let(:project) { create(:project, :public, :repository) }
let(:repository) { project.repository }
- def set_protected_branch_name(branch_name)
- find(".js-protected-branch-select").click
- find(".dropdown-input-field").set(branch_name)
- click_on("Create wildcard #{branch_name}")
- end
-
context 'logged in as developer' do
before do
sign_in(user)
@@ -18,12 +12,10 @@ describe 'Branches' do
end
describe 'Initial branches page' do
- it 'shows all the branches' do
+ it 'shows all the branches sorted by last updated by default' do
visit project_branches_path(project)
- repository.branches_sorted_by(:name).first(20).each do |branch|
- expect(page).to have_content("#{branch.name}")
- end
+ expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :updated_desc))
end
it 'sorts the branches by name' do
@@ -32,22 +24,7 @@ describe 'Branches' do
click_button "Last updated" # Open sorting dropdown
click_link "Name"
- sorted = repository.branches_sorted_by(:name).first(20).map do |branch|
- Regexp.escape(branch.name)
- end
- expect(page).to have_content(/#{sorted.join(".*")}/)
- end
-
- it 'sorts the branches by last updated' do
- visit project_branches_path(project)
-
- click_button "Last updated" # Open sorting dropdown
- click_link "Last updated"
-
- sorted = repository.branches_sorted_by(:updated_desc).first(20).map do |branch|
- Regexp.escape(branch.name)
- end
- expect(page).to have_content(/#{sorted.join(".*")}/)
+ expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :name))
end
it 'sorts the branches by oldest updated' do
@@ -56,10 +33,7 @@ describe 'Branches' do
click_button "Last updated" # Open sorting dropdown
click_link "Oldest updated"
- sorted = repository.branches_sorted_by(:updated_asc).first(20).map do |branch|
- Regexp.escape(branch.name)
- end
- expect(page).to have_content(/#{sorted.join(".*")}/)
+ expect(page).to have_content(sorted_branches(repository, count: 20, sort_by: :updated_asc))
end
it 'avoids a N+1 query in branches index' do
@@ -99,28 +73,6 @@ describe 'Branches' do
expect(find('.all-branches')).to have_selector('li', count: 0)
end
end
-
- describe 'Delete protected branch' do
- before do
- project.add_user(user, :master)
- visit project_protected_branches_path(project)
- set_protected_branch_name('fix')
- click_on "Protect"
-
- within(".protected-branches-list") { expect(page).to have_content('fix') }
- expect(ProtectedBranch.count).to eq(1)
- project.add_user(user, :developer)
- end
-
- it 'does not allow devleoper to removes protected branch', js: true do
- visit project_branches_path(project)
-
- fill_in 'branch-search', with: 'fix'
- find('#branch-search').native.send_keys(:enter)
-
- expect(page).to have_css('.btn-remove.disabled')
- end
- end
end
context 'logged in as master' do
@@ -136,37 +88,6 @@ describe 'Branches' do
expect(page).to have_content("Protected branches can be managed in project settings")
end
end
-
- describe 'Delete protected branch' do
- before do
- visit project_protected_branches_path(project)
- set_protected_branch_name('fix')
- click_on "Protect"
-
- within(".protected-branches-list") { expect(page).to have_content('fix') }
- expect(ProtectedBranch.count).to eq(1)
- end
-
- it 'removes branch after modal confirmation', js: true 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)
- page.find('[data-target="#modal-delete-branch"]').trigger(:click)
-
- expect(page).to have_css('.js-delete-branch[disabled]')
- fill_in 'delete_branch_input', with: 'fix'
- click_link 'Delete protected branch'
-
- fill_in 'branch-search', with: 'fix'
- find('#branch-search').native.send_keys(:enter)
-
- expect(page).to have_content('No branches to show')
- end
- end
end
context 'logged out' do
@@ -180,4 +101,13 @@ describe 'Branches' do
end
end
end
+
+ def sorted_branches(repository, count:, sort_by:)
+ sorted_branches =
+ repository.branches_sorted_by(sort_by).first(count).map do |branch|
+ Regexp.escape(branch.name)
+ end
+
+ Regexp.new(sorted_branches.join('.*'))
+ end
end
diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb
new file mode 100644
index 00000000000..e10d29e5eea
--- /dev/null
+++ b/spec/features/projects/fork_spec.rb
@@ -0,0 +1,57 @@
+require 'spec_helper'
+
+describe 'Project fork' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
+
+ before do
+ sign_in user
+ end
+
+ it 'allows user to fork project' do
+ visit project_path(project)
+
+ expect(page).not_to have_css('a.disabled', text: 'Fork')
+ end
+
+ it 'disables fork button when user has exceeded project limit' do
+ user.projects_limit = 0
+ user.save!
+
+ visit project_path(project)
+
+ expect(page).to have_css('a.disabled', text: 'Fork')
+ end
+
+ context 'master in group' do
+ before do
+ group = create(:group)
+ group.add_master(user)
+ end
+
+ it 'allows user to fork project to group or to user namespace' do
+ visit project_path(project)
+
+ expect(page).not_to have_css('a.disabled', text: 'Fork')
+
+ click_link 'Fork'
+
+ expect(page).to have_css('.fork-thumbnail', count: 2)
+ expect(page).not_to have_css('.fork-thumbnail.disabled')
+ end
+
+ it 'allows user to fork project to group and not user when exceeded project limit' do
+ user.projects_limit = 0
+ user.save!
+
+ visit project_path(project)
+
+ expect(page).not_to have_css('a.disabled', text: 'Fork')
+
+ click_link 'Fork'
+
+ expect(page).to have_css('.fork-thumbnail', count: 2)
+ expect(page).to have_css('.fork-thumbnail.disabled')
+ end
+ end
+end
diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb
index d2789d0aa52..1f9b52dd998 100644
--- a/spec/features/projects/issuable_templates_spec.rb
+++ b/spec/features/projects/issuable_templates_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper'
feature 'issuable templates', js: true do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
+ let(:issue_form_location) { '#content-body .issuable-details .detail-page-description' }
before do
project.team << [user, :master]
@@ -28,14 +29,17 @@ feature 'issuable templates', js: true do
longtemplate_content,
message: 'added issue template',
branch_name: 'master')
- visit edit_project_issue_path project, issue
- fill_in :'issue[title]', with: 'test issue title'
+ visit project_issue_path project, issue
+ page.within('.content .issuable-actions') do
+ click_on 'Edit'
+ end
+ fill_in :'issue-title', with: 'test issue title'
end
scenario 'user selects "bug" template' do
select_template 'bug'
wait_for_requests
- assert_template
+ assert_template(page_part: issue_form_location)
save_changes
end
@@ -43,30 +47,19 @@ feature 'issuable templates', js: true do
select_template 'bug'
wait_for_requests
select_option 'No template'
- assert_template('')
+ assert_template(expected_content: '', page_part: issue_form_location)
save_changes('')
end
scenario 'user selects "bug" template, edits description and then selects "reset template"' do
select_template 'bug'
wait_for_requests
- find_field('issue_description').send_keys(description_addition)
- assert_template(template_content + description_addition)
+ find_field('issue-description').send_keys(description_addition)
+ assert_template(expected_content: template_content + description_addition, page_part: issue_form_location)
select_option 'Reset template'
- assert_template
+ assert_template(page_part: issue_form_location)
save_changes
end
-
- it 'updates height of markdown textarea' do
- start_height = page.evaluate_script('$(".markdown-area").outerHeight()')
-
- select_template 'test'
- wait_for_requests
-
- end_height = page.evaluate_script('$(".markdown-area").outerHeight()')
-
- expect(end_height).not_to eq(start_height)
- end
end
context 'user creates an issue using templates, with a prior description' do
@@ -81,15 +74,18 @@ feature 'issuable templates', js: true do
template_content,
message: 'added issue template',
branch_name: 'master')
- visit edit_project_issue_path project, issue
- fill_in :'issue[title]', with: 'test issue title'
- fill_in :'issue[description]', with: prior_description
+ visit project_issue_path project, issue
+ page.within('.content .issuable-actions') do
+ click_on 'Edit'
+ end
+ fill_in :'issue-title', with: 'test issue title'
+ fill_in :'issue-description', with: prior_description
end
scenario 'user selects "bug" template' do
select_template 'bug'
wait_for_requests
- assert_template("#{template_content}")
+ assert_template(page_part: issue_form_location)
save_changes
end
end
@@ -154,8 +150,10 @@ feature 'issuable templates', js: true do
end
end
- def assert_template(expected_content = template_content)
- expect(find('textarea')['value']).to eq(expected_content)
+ def assert_template(expected_content: template_content, page_part: '#content-body')
+ page.within(page_part) do
+ expect(find('textarea')['value']).to eq(expected_content)
+ end
end
def save_changes(expected_content = template_content)
diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb
index 5d77cd1ccd5..06568817757 100644
--- a/spec/features/projects/project_settings_spec.rb
+++ b/spec/features/projects/project_settings_spec.rb
@@ -32,6 +32,32 @@ describe 'Edit Project Settings' do
end
end
+ describe 'Merge request settings section' do
+ it 'shows "Merge commit" strategy' do
+ visit edit_project_path(project)
+
+ page.within '.merge-requests-feature' do
+ expect(page).to have_content 'Merge commit'
+ end
+ end
+
+ it 'shows "Merge commit with semi-linear history " strategy' do
+ visit edit_project_path(project)
+
+ page.within '.merge-requests-feature' do
+ expect(page).to have_content 'Merge commit with semi-linear history'
+ end
+ end
+
+ it 'shows "Fast-forward merge" strategy' do
+ visit edit_project_path(project)
+
+ page.within '.merge-requests-feature' do
+ expect(page).to have_content 'Fast-forward merge'
+ end
+ end
+ end
+
describe 'Rename repository section' do
context 'with invalid characters' do
it 'shows errors for invalid project path/name' do
diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
index 1cf14204159..949d90a50ff 100644
--- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
@@ -40,7 +40,7 @@ describe 'User updates wiki page' do
expect(current_path).to include('one/two/three-test')
expect(find('.wiki-pages')).to have_content('Three')
- click_on('Three')
+ first(:link, text: 'Three').click
expect(find('.nav-text')).to have_content('Three')
diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb
index d201d4f6b98..470391dc66b 100644
--- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_views_wiki_page_spec.rb
@@ -34,7 +34,7 @@ describe 'User views a wiki page' do
it 'shows the history of a page that has a path', :js do
expect(current_path).to include('one/two/three-test')
- click_on('Three')
+ first(:link, text: 'Three').click
click_on('Page history')
expect(current_path).to include('one/two/three-test')
@@ -48,7 +48,7 @@ describe 'User views a wiki page' do
expect(current_path).to include('one/two/three-test')
expect(find('.wiki-pages')).to have_content('Three')
- click_on('Three')
+ first(:link, text: 'Three').click
expect(find('.nav-text')).to have_content('Three')
@@ -83,7 +83,7 @@ describe 'User views a wiki page' do
it 'shows a file stored in a page' do
file = Gollum::File.new(project.wiki)
- allow_any_instance_of(Gollum::Wiki).to receive(:file).with('image.jpg', 'master', true).and_return(file)
+ allow_any_instance_of(Gollum::Wiki).to receive(:file).with('image.jpg', 'master').and_return(file)
allow_any_instance_of(Gollum::File).to receive(:mime_type).and_return('image/jpeg')
expect(page).to have_xpath('//img[@data-src="image.jpg"]')
diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb
index 3677bf38724..bf9885f73bd 100644
--- a/spec/features/protected_branches_spec.rb
+++ b/spec/features/protected_branches_spec.rb
@@ -1,93 +1,153 @@
require 'spec_helper'
-feature 'Protected Branches', js: true do
- let(:user) { create(:user, :admin) }
+feature 'Protected Branches', :js do
+ let(:user) { create(:user) }
+ let(:admin) { create(:admin) }
let(:project) { create(:project, :repository) }
- before do
- sign_in(user)
- end
+ context 'logged in as developer' do
+ before do
+ project.add_developer(user)
+ sign_in(user)
+ end
- def set_protected_branch_name(branch_name)
- find(".js-protected-branch-select").trigger('click')
- find(".dropdown-input-field").set(branch_name)
- click_on("Create wildcard #{branch_name}")
- end
+ describe 'Delete protected branch' do
+ before do
+ create(:protected_branch, project: project, name: 'fix')
+ expect(ProtectedBranch.count).to eq(1)
+ end
+
+ it 'does not allow developer to removes protected branch' do
+ visit project_branches_path(project)
+
+ fill_in 'branch-search', with: 'fix'
+ find('#branch-search').native.send_keys(:enter)
- describe "explicit protected branches" do
- it "allows creating explicit protected branches" do
- visit project_protected_branches_path(project)
- set_protected_branch_name('some-branch')
- click_on "Protect"
+ expect(page).to have_css('.btn-remove.disabled')
+ end
+ end
+ end
- within(".protected-branches-list") { expect(page).to have_content('some-branch') }
- expect(ProtectedBranch.count).to eq(1)
- expect(ProtectedBranch.last.name).to eq('some-branch')
+ context 'logged in as master' do
+ before do
+ project.add_master(user)
+ sign_in(user)
end
- it "displays the last commit on the matching branch if it exists" do
- commit = create(:commit, project: project)
- project.repository.add_branch(user, 'some-branch', commit.id)
+ describe 'Delete protected branch' do
+ before do
+ create(:protected_branch, project: project, name: 'fix')
+ expect(ProtectedBranch.count).to eq(1)
+ end
- visit project_protected_branches_path(project)
- set_protected_branch_name('some-branch')
- click_on "Protect"
+ it 'removes branch after modal confirmation' do
+ visit project_branches_path(project)
- within(".protected-branches-list") { expect(page).to have_content(commit.id[0..7]) }
- end
+ fill_in 'branch-search', with: 'fix'
+ find('#branch-search').native.send_keys(:enter)
- it "displays an error message if the named branch does not exist" do
- visit project_protected_branches_path(project)
- set_protected_branch_name('some-branch')
- click_on "Protect"
+ expect(page).to have_content('fix')
+ expect(find('.all-branches')).to have_selector('li', count: 1)
+ page.find('[data-target="#modal-delete-branch"]').trigger(:click)
- within(".protected-branches-list") { expect(page).to have_content('branch was removed') }
+ expect(page).to have_css('.js-delete-branch[disabled]')
+ fill_in 'delete_branch_input', with: 'fix'
+ click_link 'Delete protected branch'
+
+ fill_in 'branch-search', with: 'fix'
+ find('#branch-search').native.send_keys(:enter)
+
+ expect(page).to have_content('No branches to show')
+ end
end
end
- describe "wildcard protected branches" do
- it "allows creating protected branches with a wildcard" do
- visit project_protected_branches_path(project)
- set_protected_branch_name('*-stable')
- click_on "Protect"
-
- within(".protected-branches-list") { expect(page).to have_content('*-stable') }
- expect(ProtectedBranch.count).to eq(1)
- expect(ProtectedBranch.last.name).to eq('*-stable')
+ context 'logged in as admin' do
+ before do
+ sign_in(admin)
end
- it "displays the number of matching branches" do
- project.repository.add_branch(user, 'production-stable', 'master')
- project.repository.add_branch(user, 'staging-stable', 'master')
+ describe "explicit protected branches" do
+ it "allows creating explicit protected branches" do
+ visit project_protected_branches_path(project)
+ set_protected_branch_name('some-branch')
+ click_on "Protect"
- visit project_protected_branches_path(project)
- set_protected_branch_name('*-stable')
- click_on "Protect"
+ within(".protected-branches-list") { expect(page).to have_content('some-branch') }
+ expect(ProtectedBranch.count).to eq(1)
+ expect(ProtectedBranch.last.name).to eq('some-branch')
+ end
- within(".protected-branches-list") { expect(page).to have_content("2 matching branches") }
+ it "displays the last commit on the matching branch if it exists" do
+ commit = create(:commit, project: project)
+ project.repository.add_branch(admin, 'some-branch', commit.id)
+
+ visit project_protected_branches_path(project)
+ set_protected_branch_name('some-branch')
+ click_on "Protect"
+
+ within(".protected-branches-list") { expect(page).to have_content(commit.id[0..7]) }
+ end
+
+ it "displays an error message if the named branch does not exist" do
+ visit project_protected_branches_path(project)
+ set_protected_branch_name('some-branch')
+ click_on "Protect"
+
+ within(".protected-branches-list") { expect(page).to have_content('branch was removed') }
+ end
end
- it "displays all the branches matching the wildcard" do
- project.repository.add_branch(user, 'production-stable', 'master')
- project.repository.add_branch(user, 'staging-stable', 'master')
- project.repository.add_branch(user, 'development', 'master')
+ describe "wildcard protected branches" do
+ it "allows creating protected branches with a wildcard" do
+ visit project_protected_branches_path(project)
+ set_protected_branch_name('*-stable')
+ click_on "Protect"
+
+ within(".protected-branches-list") { expect(page).to have_content('*-stable') }
+ expect(ProtectedBranch.count).to eq(1)
+ expect(ProtectedBranch.last.name).to eq('*-stable')
+ end
- visit project_protected_branches_path(project)
- set_protected_branch_name('*-stable')
- click_on "Protect"
+ it "displays the number of matching branches" do
+ project.repository.add_branch(admin, 'production-stable', 'master')
+ project.repository.add_branch(admin, 'staging-stable', 'master')
- visit project_protected_branches_path(project)
- click_on "2 matching branches"
+ visit project_protected_branches_path(project)
+ set_protected_branch_name('*-stable')
+ click_on "Protect"
- within(".protected-branches-list") do
- expect(page).to have_content("production-stable")
- expect(page).to have_content("staging-stable")
- expect(page).not_to have_content("development")
+ within(".protected-branches-list") { expect(page).to have_content("2 matching branches") }
end
+
+ it "displays all the branches matching the wildcard" do
+ project.repository.add_branch(admin, 'production-stable', 'master')
+ project.repository.add_branch(admin, 'staging-stable', 'master')
+ project.repository.add_branch(admin, 'development', 'master')
+
+ visit project_protected_branches_path(project)
+ set_protected_branch_name('*-stable')
+ click_on "Protect"
+
+ visit project_protected_branches_path(project)
+ click_on "2 matching branches"
+
+ within(".protected-branches-list") do
+ expect(page).to have_content("production-stable")
+ expect(page).to have_content("staging-stable")
+ expect(page).not_to have_content("development")
+ end
+ end
+ end
+
+ describe "access control" do
+ include_examples "protected branches > access control > CE"
end
end
- describe "access control" do
- include_examples "protected branches > access control > CE"
+ def set_protected_branch_name(branch_name)
+ find(".js-protected-branch-select").trigger('click')
+ find(".dropdown-input-field").set(branch_name)
+ click_on("Create wildcard #{branch_name}")
end
end
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index a7928857b7d..d70cf1527e7 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -181,21 +181,6 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) }
end
- describe "GET /:project_path/issues/:id/edit" do
- let(:issue) { create(:issue, project: project) }
- subject { edit_project_issue_path(project, issue) }
-
- it { is_expected.to be_allowed_for(:admin) }
- it { is_expected.to be_allowed_for(:owner).of(project) }
- it { is_expected.to be_allowed_for(:master).of(project) }
- it { is_expected.to be_allowed_for(:developer).of(project) }
- it { is_expected.to be_allowed_for(:reporter).of(project) }
- it { is_expected.to be_denied_for(:guest).of(project) }
- it { is_expected.to be_denied_for(:user) }
- it { is_expected.to be_denied_for(:external) }
- it { is_expected.to be_denied_for(:visitor) }
- end
-
describe "GET /:project_path/snippets" do
subject { project_snippets_path(project) }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index a4396b20afd..ea130606545 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -181,21 +181,6 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) }
end
- describe "GET /:project_path/issues/:id/edit" do
- let(:issue) { create(:issue, project: project) }
- subject { edit_project_issue_path(project, issue) }
-
- it { is_expected.to be_allowed_for(:admin) }
- it { is_expected.to be_allowed_for(:owner).of(project) }
- it { is_expected.to be_allowed_for(:master).of(project) }
- it { is_expected.to be_allowed_for(:developer).of(project) }
- it { is_expected.to be_allowed_for(:reporter).of(project) }
- it { is_expected.to be_denied_for(:guest).of(project) }
- it { is_expected.to be_denied_for(:user) }
- it { is_expected.to be_denied_for(:external) }
- it { is_expected.to be_denied_for(:visitor) }
- end
-
describe "GET /:project_path/snippets" do
subject { project_snippets_path(project) }
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index fccdeb0e5b7..d15f5af66c9 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -394,21 +394,6 @@ describe "Public Project Access" do
it { is_expected.to be_allowed_for(:visitor) }
end
- describe "GET /:project_path/issues/:id/edit" do
- let(:issue) { create(:issue, project: project) }
- subject { edit_project_issue_path(project, issue) }
-
- it { is_expected.to be_allowed_for(:admin) }
- it { is_expected.to be_allowed_for(:owner).of(project) }
- it { is_expected.to be_allowed_for(:master).of(project) }
- it { is_expected.to be_allowed_for(:developer).of(project) }
- it { is_expected.to be_allowed_for(:reporter).of(project) }
- it { is_expected.to be_denied_for(:guest).of(project) }
- it { is_expected.to be_denied_for(:user) }
- it { is_expected.to be_denied_for(:external) }
- it { is_expected.to be_denied_for(:visitor) }
- end
-
describe "GET /:project_path/snippets" do
subject { project_snippets_path(project) }
diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb
index b6367b88e17..917fad74ef1 100644
--- a/spec/features/signup_spec.rb
+++ b/spec/features/signup_spec.rb
@@ -24,6 +24,24 @@ feature 'Signup' do
end
end
+ context "when sigining up with different cased emails" do
+ it "creates the user successfully" do
+ user = build(:user)
+
+ visit root_path
+
+ fill_in 'new_user_name', with: user.name
+ fill_in 'new_user_username', with: user.username
+ fill_in 'new_user_email', with: user.email
+ fill_in 'new_user_email_confirmation', with: user.email.capitalize
+ fill_in 'new_user_password', with: user.password
+ click_button "Register"
+
+ expect(current_path).to eq dashboard_projects_path
+ expect(page).to have_content("Welcome! You have signed up successfully.")
+ end
+ end
+
context "when not sending confirmation email" do
before do
stub_application_setting(send_user_confirmation_email: false)
diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb
index d6a6b8fc7d5..80750c904b5 100644
--- a/spec/features/tags/master_deletes_tag_spec.rb
+++ b/spec/features/tags/master_deletes_tag_spec.rb
@@ -35,15 +35,30 @@ feature 'Master deletes tag' do
end
context 'when pre-receive hook fails', js: true do
- before do
- allow_any_instance_of(Gitlab::Git::HooksService).to receive(:execute)
- .and_raise(Gitlab::Git::HooksService::PreReceiveError, 'Do not delete tags')
+ context 'when Gitaly operation_user_delete_tag feature is enabled' do
+ before do
+ allow_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rm_tag)
+ .and_raise(Gitlab::Git::HooksService::PreReceiveError, 'Do not delete tags')
+ end
+
+ scenario 'shows the error message' do
+ delete_first_tag
+
+ expect(page).to have_content('Do not delete tags')
+ end
end
- scenario 'shows the error message' do
- delete_first_tag
+ context 'when Gitaly operation_user_delete_tag feature is disabled', skip_gitaly_mock: true do
+ before do
+ allow_any_instance_of(Gitlab::Git::HooksService).to receive(:execute)
+ .and_raise(Gitlab::Git::HooksService::PreReceiveError, 'Do not delete tags')
+ end
+
+ scenario 'shows the error message' do
+ delete_first_tag
- expect(page).to have_content('Do not delete tags')
+ expect(page).to have_content('Do not delete tags')
+ end
end
end
diff --git a/spec/fixtures/api/schemas/entities/merge_request.json b/spec/fixtures/api/schemas/entities/merge_request.json
index 1030f323a1f..30b4e56bc98 100644
--- a/spec/fixtures/api/schemas/entities/merge_request.json
+++ b/spec/fixtures/api/schemas/entities/merge_request.json
@@ -93,10 +93,12 @@
"merge_commit_message_with_description": { "type": "string" },
"diverged_commits_count": { "type": "integer" },
"commit_change_content_path": { "type": "string" },
- "remove_wip_path": { "type": "string" },
+ "remove_wip_path": { "type": ["string", "null"] },
"commits_count": { "type": "integer" },
"remove_source_branch": { "type": ["boolean", "null"] },
- "merge_ongoing": { "type": "boolean" }
+ "merge_ongoing": { "type": "boolean" },
+ "ff_only_enabled": { "type": ["boolean", false] },
+ "should_be_rebased": { "type": "boolean" }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/registry/repositories.json b/spec/fixtures/api/schemas/registry/repositories.json
new file mode 100644
index 00000000000..4978bd89cda
--- /dev/null
+++ b/spec/fixtures/api/schemas/registry/repositories.json
@@ -0,0 +1,6 @@
+{
+ "type": "array",
+ "items": {
+ "$ref": "repository.json"
+ }
+}
diff --git a/spec/fixtures/api/schemas/registry/repository.json b/spec/fixtures/api/schemas/registry/repository.json
new file mode 100644
index 00000000000..4175642eb00
--- /dev/null
+++ b/spec/fixtures/api/schemas/registry/repository.json
@@ -0,0 +1,27 @@
+{
+ "type": "object",
+ "required" : [
+ "id",
+ "path",
+ "location",
+ "tags_path"
+ ],
+ "properties" : {
+ "id": {
+ "type": "integer"
+ },
+ "path": {
+ "type": "string"
+ },
+ "location": {
+ "type": "string"
+ },
+ "tags_path": {
+ "type": "string"
+ },
+ "destroy_path": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/registry/tag.json b/spec/fixtures/api/schemas/registry/tag.json
new file mode 100644
index 00000000000..5bc307e0e64
--- /dev/null
+++ b/spec/fixtures/api/schemas/registry/tag.json
@@ -0,0 +1,28 @@
+{
+ "type": "object",
+ "required" : [
+ "name",
+ "location"
+ ],
+ "properties" : {
+ "name": {
+ "type": "string"
+ },
+ "location": {
+ "type": "string"
+ },
+ "revision": {
+ "type": "string"
+ },
+ "total_size": {
+ "type": "integer"
+ },
+ "created_at": {
+ "type": "date"
+ },
+ "destroy_path": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/registry/tags.json b/spec/fixtures/api/schemas/registry/tags.json
new file mode 100644
index 00000000000..c72f957459a
--- /dev/null
+++ b/spec/fixtures/api/schemas/registry/tags.json
@@ -0,0 +1,6 @@
+{
+ "type": "array",
+ "items": {
+ "$ref": "tag.json"
+ }
+}
diff --git a/spec/fixtures/config/kubeconfig.yml b/spec/fixtures/config/kubeconfig.yml
index c4e8e573c32..5152dae0104 100644
--- a/spec/fixtures/config/kubeconfig.yml
+++ b/spec/fixtures/config/kubeconfig.yml
@@ -4,7 +4,7 @@ clusters:
- name: gitlab-deploy
cluster:
server: https://kube.domain.com
- certificate-authority-data: "UEVN\n"
+ certificate-authority-data: "UEVN"
contexts:
- name: gitlab-deploy
context:
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 36031ac1a28..76e5964ccf7 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -17,7 +17,7 @@ describe GroupsHelper do
it 'gives default avatar_icon when no avatar is present' do
group = create(:group)
group.save!
- expect(group_icon(group.path)).to match('group_avatar.png')
+ expect(group_icon(group.path)).to match_asset_path('group_avatar.png')
end
end
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index 9aca3987657..baf927a9acc 100644
--- a/spec/helpers/page_layout_helper_spec.rb
+++ b/spec/helpers/page_layout_helper_spec.rb
@@ -54,7 +54,7 @@ describe PageLayoutHelper do
describe 'page_image' do
it 'defaults to the GitLab logo' do
- expect(helper.page_image).to end_with 'assets/gitlab_logo.png'
+ expect(helper.page_image).to match_asset_path 'assets/gitlab_logo.png'
end
%w(project user group).each do |type|
@@ -70,13 +70,13 @@ describe PageLayoutHelper do
object = double(avatar_url: nil)
assign(type, object)
- expect(helper.page_image).to end_with 'assets/gitlab_logo.png'
+ expect(helper.page_image).to match_asset_path 'assets/gitlab_logo.png'
end
end
context "with no assignments" do
it 'falls back to the default' do
- expect(helper.page_image).to end_with 'assets/gitlab_logo.png'
+ expect(helper.page_image).to match_asset_path 'assets/gitlab_logo.png'
end
end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 7ded95d01af..641971485de 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -200,13 +200,13 @@ describe ProjectsHelper do
end
it 'returns image tag for member avatar' do
- expect(helper).to receive(:image_tag).with(expected, { width: 16, class: ["avatar", "avatar-inline", "s16"], alt: "" })
+ expect(helper).to receive(:image_tag).with(expected, { width: 16, class: ["avatar", "avatar-inline", "s16"], alt: "", "data-src" => anything })
helper.link_to_member_avatar(user)
end
it 'returns image tag with avatar class' do
- expect(helper).to receive(:image_tag).with(expected, { width: 16, class: ["avatar", "avatar-inline", "s16", "any-avatar-class"], alt: "" })
+ expect(helper).to receive(:image_tag).with(expected, { width: 16, class: ["avatar", "avatar-inline", "s16", "any-avatar-class"], alt: "", "data-src" => anything })
helper.link_to_member_avatar(user, avatar_class: "any-avatar-class")
end
diff --git a/spec/javascripts/build_spec.js b/spec/javascripts/build_spec.js
index 35149611095..d5b0f23e7b7 100644
--- a/spec/javascripts/build_spec.js
+++ b/spec/javascripts/build_spec.js
@@ -289,4 +289,18 @@ describe('Build', () => {
});
});
});
+
+ describe('getBuildTrace', () => {
+ it('should request build trace with state parameter', (done) => {
+ spyOn(jQuery, 'ajax').and.callThrough();
+ new Build();
+
+ setTimeout(() => {
+ expect(jQuery.ajax).toHaveBeenCalledWith(
+ { url: `${BUILD_URL}/trace.json`, data: { state: '' } },
+ );
+ done();
+ }, 0);
+ });
+ });
});
diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb
index 4bc2205e642..3fd16d76f51 100644
--- a/spec/javascripts/fixtures/merge_requests.rb
+++ b/spec/javascripts/fixtures/merge_requests.rb
@@ -41,6 +41,12 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
remove_repository(project)
end
+ it 'merge_requests/merge_request_of_current_user.html.raw' do |example|
+ merge_request.update(author: admin)
+
+ render_merge_request(example.description, merge_request)
+ end
+
it 'merge_requests/merge_request_with_task_list.html.raw' do |example|
create(:ci_build, :pending, pipeline: pipeline)
diff --git a/spec/javascripts/notes/stores/helpers.js b/spec/javascripts/helpers/vuex_action_helper.js
index 2d386fe1da5..2d386fe1da5 100644
--- a/spec/javascripts/notes/stores/helpers.js
+++ b/spec/javascripts/helpers/vuex_action_helper.js
diff --git a/spec/javascripts/issuable_context_spec.js b/spec/javascripts/issuable_context_spec.js
new file mode 100644
index 00000000000..bcb2b7b24a0
--- /dev/null
+++ b/spec/javascripts/issuable_context_spec.js
@@ -0,0 +1,34 @@
+/* global IssuableContext */
+import '~/issuable_context';
+import $ from 'jquery';
+
+describe('IssuableContext', () => {
+ describe('toggleHiddenParticipants', () => {
+ const event = jasmine.createSpyObj('event', ['preventDefault']);
+
+ beforeEach(() => {
+ spyOn($.fn, 'data').and.returnValue('data');
+ spyOn($.fn, 'text').and.returnValue('data');
+ });
+
+ afterEach(() => {
+ gl.lazyLoader = undefined;
+ });
+
+ it('calls loadCheck if lazyLoader is set', () => {
+ gl.lazyLoader = jasmine.createSpyObj('lazyLoader', ['loadCheck']);
+
+ IssuableContext.prototype.toggleHiddenParticipants(event);
+
+ expect(gl.lazyLoader.loadCheck).toHaveBeenCalled();
+ });
+
+ it('does not throw if lazyLoader is not defined', () => {
+ gl.lazyLoader = undefined;
+
+ const toggle = IssuableContext.prototype.toggleHiddenParticipants.bind(null, event);
+
+ expect(toggle).not.toThrow();
+ });
+ });
+});
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index 787b405de47..f86f2f260c3 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -84,6 +84,62 @@ describe('common_utils', () => {
expectGetElementIdToHaveBeenCalledWith('definição');
expectGetElementIdToHaveBeenCalledWith('user-content-definição');
});
+
+ it('scrolls element into view', () => {
+ document.body.innerHTML += `
+ <div id="parent">
+ <div style="height: 2000px;"></div>
+ <div id="test" style="height: 2000px;"></div>
+ </div>
+ `;
+
+ window.history.pushState({}, null, '#test');
+ commonUtils.handleLocationHash();
+
+ expectGetElementIdToHaveBeenCalledWith('test');
+ expect(window.scrollY).toBe(document.getElementById('test').offsetTop);
+
+ document.getElementById('parent').remove();
+ });
+
+ it('scrolls user content element into view', () => {
+ document.body.innerHTML += `
+ <div id="parent">
+ <div style="height: 2000px;"></div>
+ <div id="user-content-test" style="height: 2000px;"></div>
+ </div>
+ `;
+
+ window.history.pushState({}, null, '#test');
+ commonUtils.handleLocationHash();
+
+ expectGetElementIdToHaveBeenCalledWith('test');
+ expectGetElementIdToHaveBeenCalledWith('user-content-test');
+ expect(window.scrollY).toBe(document.getElementById('user-content-test').offsetTop);
+
+ document.getElementById('parent').remove();
+ });
+
+ it('scrolls to element with offset from navbar', () => {
+ spyOn(window, 'scrollBy').and.callThrough();
+ document.body.innerHTML += `
+ <div id="parent">
+ <div class="navbar-gitlab" style="position: fixed; top: 0; height: 50px;"></div>
+ <div style="height: 2000px; margin-top: 50px;"></div>
+ <div id="user-content-test" style="height: 2000px;"></div>
+ </div>
+ `;
+
+ window.history.pushState({}, null, '#test');
+ commonUtils.handleLocationHash();
+
+ expectGetElementIdToHaveBeenCalledWith('test');
+ expectGetElementIdToHaveBeenCalledWith('user-content-test');
+ expect(window.scrollY).toBe(document.getElementById('user-content-test').offsetTop - 50);
+ expect(window.scrollBy).toHaveBeenCalledWith(0, -50);
+
+ document.getElementById('parent').remove();
+ });
});
describe('setParamInURL', () => {
diff --git a/spec/javascripts/locale/sprintf_spec.js b/spec/javascripts/locale/sprintf_spec.js
new file mode 100644
index 00000000000..52e903b819f
--- /dev/null
+++ b/spec/javascripts/locale/sprintf_spec.js
@@ -0,0 +1,74 @@
+import sprintf from '~/locale/sprintf';
+
+describe('locale', () => {
+ describe('sprintf', () => {
+ it('does not modify string without parameters', () => {
+ const input = 'No parameters';
+
+ const output = sprintf(input);
+
+ expect(output).toBe(input);
+ });
+
+ it('ignores extraneous parameters', () => {
+ const input = 'No parameters';
+
+ const output = sprintf(input, { ignore: 'this' });
+
+ expect(output).toBe(input);
+ });
+
+ it('ignores extraneous placeholders', () => {
+ const input = 'No %{parameters}';
+
+ const output = sprintf(input);
+
+ expect(output).toBe(input);
+ });
+
+ it('replaces parameters', () => {
+ const input = '%{name} has %{count} parameters';
+ const parameters = {
+ name: 'this',
+ count: 2,
+ };
+
+ const output = sprintf(input, parameters);
+
+ expect(output).toBe('this has 2 parameters');
+ });
+
+ it('replaces multiple occurrences', () => {
+ const input = 'to %{verb} or not to %{verb}';
+ const parameters = {
+ verb: 'be',
+ };
+
+ const output = sprintf(input, parameters);
+
+ expect(output).toBe('to be or not to be');
+ });
+
+ it('escapes parameters', () => {
+ const input = 'contains %{userContent}';
+ const parameters = {
+ userContent: '<script>alert("malicious!")</script>',
+ };
+
+ const output = sprintf(input, parameters);
+
+ expect(output).toBe('contains &lt;script&gt;alert(&quot;malicious!&quot;)&lt;/script&gt;');
+ });
+
+ it('does not escape parameters for escapeParameters = false', () => {
+ const input = 'contains %{safeContent}';
+ const parameters = {
+ safeContent: '<strong>bold attempt</strong>',
+ };
+
+ const output = sprintf(input, parameters, false);
+
+ expect(output).toBe('contains <strong>bold attempt</strong>');
+ });
+ });
+});
diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js
index 6ff42e2378d..3ab901da6b6 100644
--- a/spec/javascripts/merge_request_spec.js
+++ b/spec/javascripts/merge_request_spec.js
@@ -58,5 +58,44 @@ import IssuablesHelper from '~/helpers/issuables_helper';
expect(CloseReopenReportToggle.prototype.initDroplab).toHaveBeenCalled();
});
});
+
+ describe('hideCloseButton', () => {
+ describe('merge request of another user', () => {
+ beforeEach(() => {
+ loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
+ this.el = document.querySelector('.merge-request .issuable-actions');
+ const merge = new MergeRequest();
+ merge.hideCloseButton();
+ });
+
+ it('hides the dropdown close item and selects the next item', () => {
+ const closeItem = this.el.querySelector('li.close-item');
+ const smallCloseItem = this.el.querySelector('.js-close-item');
+ const reportItem = this.el.querySelector('li.report-item');
+
+ expect(closeItem).toHaveClass('hidden');
+ expect(smallCloseItem).toHaveClass('hidden');
+ expect(reportItem).toHaveClass('droplab-item-selected');
+ expect(reportItem).not.toHaveClass('hidden');
+ });
+ });
+
+ describe('merge request of current_user', () => {
+ beforeEach(() => {
+ loadFixtures('merge_requests/merge_request_of_current_user.html.raw');
+ this.el = document.querySelector('.merge-request .issuable-actions');
+ const merge = new MergeRequest();
+ merge.hideCloseButton();
+ });
+
+ it('hides the close button', () => {
+ const closeButton = this.el.querySelector('.btn-close');
+ const smallCloseItem = this.el.querySelector('.js-close-item');
+
+ expect(closeButton).toHaveClass('hidden');
+ expect(smallCloseItem).toHaveClass('hidden');
+ });
+ });
+ });
});
}).call(window);
diff --git a/spec/javascripts/monitoring/graph/flag_spec.js b/spec/javascripts/monitoring/graph/flag_spec.js
index 14794cbfd50..8ee1171419d 100644
--- a/spec/javascripts/monitoring/graph/flag_spec.js
+++ b/spec/javascripts/monitoring/graph/flag_spec.js
@@ -14,19 +14,22 @@ function getCoordinate(component, selector, coordinate) {
return parseInt(coordinateVal, 10);
}
+const defaultValuesComponent = {
+ currentXCoordinate: 200,
+ currentYCoordinate: 100,
+ currentFlagPosition: 100,
+ currentData: {
+ time: new Date('2017-06-04T18:17:33.501Z'),
+ value: '1.49609375',
+ },
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ showFlagContent: true,
+};
+
describe('GraphFlag', () => {
it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => {
- const component = createComponent({
- currentXCoordinate: 200,
- currentYCoordinate: 100,
- currentFlagPosition: 100,
- currentData: {
- time: new Date('2017-06-04T18:17:33.501Z'),
- value: '1.49609375',
- },
- graphHeight: 300,
- graphHeightOffset: 120,
- });
+ const component = createComponent(defaultValuesComponent);
expect(getCoordinate(component, '.selected-metric-line', 'x1'))
.toEqual(component.currentXCoordinate);
@@ -35,17 +38,7 @@ describe('GraphFlag', () => {
});
it('has a SVG with the class rect-text-metric at the currentFlagPosition', () => {
- const component = createComponent({
- currentXCoordinate: 200,
- currentYCoordinate: 100,
- currentFlagPosition: 100,
- currentData: {
- time: new Date('2017-06-04T18:17:33.501Z'),
- value: '1.49609375',
- },
- graphHeight: 300,
- graphHeightOffset: 120,
- });
+ const component = createComponent(defaultValuesComponent);
const svg = component.$el.querySelector('.rect-text-metric');
expect(svg.tagName).toEqual('svg');
@@ -54,17 +47,7 @@ describe('GraphFlag', () => {
describe('Computed props', () => {
it('calculatedHeight', () => {
- const component = createComponent({
- currentXCoordinate: 200,
- currentYCoordinate: 100,
- currentFlagPosition: 100,
- currentData: {
- time: new Date('2017-06-04T18:17:33.501Z'),
- value: '1.49609375',
- },
- graphHeight: 300,
- graphHeightOffset: 120,
- });
+ const component = createComponent(defaultValuesComponent);
expect(component.calculatedHeight).toEqual(180);
});
diff --git a/spec/javascripts/monitoring/graph_spec.js b/spec/javascripts/monitoring/graph_spec.js
index 7d8b0744af1..7213b3bfa30 100644
--- a/spec/javascripts/monitoring/graph_spec.js
+++ b/spec/javascripts/monitoring/graph_spec.js
@@ -86,4 +86,22 @@ describe('Graph', () => {
expect(component.yAxisLabel).toEqual(component.graphData.y_label);
expect(component.legendTitle).toEqual(component.graphData.queries[0].label);
});
+
+ it('sets the currentData object based on the hovered data index', () => {
+ const component = createComponent({
+ graphData: convertedMetrics[1],
+ classType: 'col-md-6',
+ updateAspectRatio: false,
+ deploymentData,
+ graphIdentifier: 0,
+ hoverData: {
+ hoveredDate: new Date('Sun Aug 27 2017 06:11:51 GMT-0500 (CDT)'),
+ currentDeployXPos: null,
+ },
+ });
+
+ component.positionFlag();
+ expect(component.currentData).toBe(component.timeSeries[0].values[10]);
+ expect(component.currentDataIndex).toEqual(10);
+ });
});
diff --git a/spec/javascripts/notes/components/issue_comment_form_spec.js b/spec/javascripts/notes/components/issue_comment_form_spec.js
index 1c8b1b98242..3f659af5c3b 100644
--- a/spec/javascripts/notes/components/issue_comment_form_spec.js
+++ b/spec/javascripts/notes/components/issue_comment_form_spec.js
@@ -33,6 +33,30 @@ describe('issue_comment_form component', () => {
expect(vm.$el.querySelector('.timeline-icon .user-avatar-link').getAttribute('href')).toEqual(userDataMock.path);
});
+ describe('handleSave', () => {
+ it('should request to save note when note is entered', () => {
+ vm.note = 'hello world';
+ spyOn(vm, 'saveNote').and.returnValue(new Promise(() => {}));
+ spyOn(vm, 'resizeTextarea');
+ spyOn(vm, 'stopPolling');
+
+ vm.handleSave();
+ expect(vm.isSubmitting).toEqual(true);
+ expect(vm.note).toEqual('');
+ expect(vm.saveNote).toHaveBeenCalled();
+ expect(vm.stopPolling).toHaveBeenCalled();
+ expect(vm.resizeTextarea).toHaveBeenCalled();
+ });
+
+ it('should toggle issue state when no note', () => {
+ spyOn(vm, 'toggleIssueState');
+
+ vm.handleSave();
+
+ expect(vm.toggleIssueState).toHaveBeenCalled();
+ });
+ });
+
describe('textarea', () => {
it('should render textarea with placeholder', () => {
expect(
@@ -40,6 +64,22 @@ describe('issue_comment_form component', () => {
).toEqual('Write a comment or drag your files here...');
});
+ it('should make textarea disabled while requesting', (done) => {
+ const $submitButton = $(vm.$el.querySelector('.js-comment-submit-button'));
+ vm.note = 'hello world';
+ spyOn(vm, 'stopPolling');
+ spyOn(vm, 'saveNote').and.returnValue(new Promise(() => {}));
+
+ vm.$nextTick(() => { // Wait for vm.note change triggered. It should enable $submitButton.
+ $submitButton.trigger('click');
+
+ vm.$nextTick(() => { // Wait for vm.isSubmitting triggered. It should disable textarea.
+ expect(vm.$el.querySelector('.js-main-target-form textarea').disabled).toBeTruthy();
+ done();
+ });
+ });
+ });
+
it('should support quick actions', () => {
expect(
vm.$el.querySelector('.js-main-target-form textarea').getAttribute('data-supports-quick-actions'),
diff --git a/spec/javascripts/notes/stores/actions_spec.js b/spec/javascripts/notes/stores/actions_spec.js
index 2b2219dcf0c..3d1ca870ca4 100644
--- a/spec/javascripts/notes/stores/actions_spec.js
+++ b/spec/javascripts/notes/stores/actions_spec.js
@@ -1,5 +1,5 @@
import * as actions from '~/notes/stores/actions';
-import testAction from './helpers';
+import testAction from '../../helpers/vuex_action_helper';
import { discussionMock, notesDataMock, userDataMock, issueDataMock, individualNote } from '../mock_data';
describe('Actions Notes Store', () => {
diff --git a/spec/javascripts/projects_dropdown/service/projects_service_spec.js b/spec/javascripts/projects_dropdown/service/projects_service_spec.js
index d5dd8b3449a..cfd1bb7d24f 100644
--- a/spec/javascripts/projects_dropdown/service/projects_service_spec.js
+++ b/spec/javascripts/projects_dropdown/service/projects_service_spec.js
@@ -34,7 +34,7 @@ describe('ProjectsService', () => {
const searchQuery = 'lab';
const queryParams = {
- simple: false,
+ simple: true,
per_page: 20,
membership: true,
order_by: 'last_activity_at',
diff --git a/spec/javascripts/registry/components/app_spec.js b/spec/javascripts/registry/components/app_spec.js
new file mode 100644
index 00000000000..43e7d9e1224
--- /dev/null
+++ b/spec/javascripts/registry/components/app_spec.js
@@ -0,0 +1,122 @@
+import Vue from 'vue';
+import registry from '~/registry/components/app.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+import { reposServerResponse } from '../mock_data';
+
+describe('Registry List', () => {
+ let vm;
+ let Component;
+
+ beforeEach(() => {
+ Component = Vue.extend(registry);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('with data', () => {
+ const interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify(reposServerResponse), {
+ status: 200,
+ }));
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ vm = mountComponent(Component, { endpoint: 'foo' });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ it('should render a list of repos', (done) => {
+ setTimeout(() => {
+ expect(vm.$store.state.repos.length).toEqual(reposServerResponse.length);
+
+ Vue.nextTick(() => {
+ expect(
+ vm.$el.querySelectorAll('.container-image').length,
+ ).toEqual(reposServerResponse.length);
+ done();
+ });
+ }, 0);
+ });
+
+ describe('delete repository', () => {
+ it('should be possible to delete a repo', (done) => {
+ setTimeout(() => {
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.container-image-head .js-remove-repo')).toBeDefined();
+ done();
+ });
+ }, 0);
+ });
+ });
+
+ describe('toggle repository', () => {
+ it('should open the container', (done) => {
+ setTimeout(() => {
+ Vue.nextTick(() => {
+ vm.$el.querySelector('.js-toggle-repo').click();
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.js-toggle-repo i').className).toEqual('fa fa-chevron-up');
+ done();
+ });
+ });
+ }, 0);
+ });
+ });
+ });
+
+ describe('without data', () => {
+ const interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify([]), {
+ status: 200,
+ }));
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ vm = mountComponent(Component, { endpoint: 'foo' });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ it('should render empty message', (done) => {
+ setTimeout(() => {
+ expect(
+ vm.$el.querySelector('p').textContent.trim(),
+ ).toEqual('No container images stored for this project. Add one by following the instructions above.');
+ done();
+ }, 0);
+ });
+ });
+
+ describe('while loading data', () => {
+ const interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify(reposServerResponse), {
+ status: 200,
+ }));
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ vm = mountComponent(Component, { endpoint: 'foo' });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ it('should render a loading spinner', (done) => {
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.fa-spinner')).not.toBe(null);
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/registry/components/collapsible_container_spec.js b/spec/javascripts/registry/components/collapsible_container_spec.js
new file mode 100644
index 00000000000..5891921318a
--- /dev/null
+++ b/spec/javascripts/registry/components/collapsible_container_spec.js
@@ -0,0 +1,58 @@
+import Vue from 'vue';
+import collapsibleComponent from '~/registry/components/collapsible_container.vue';
+import store from '~/registry/stores';
+import { repoPropsData } from '../mock_data';
+
+describe('collapsible registry container', () => {
+ let vm;
+ let Component;
+
+ beforeEach(() => {
+ Component = Vue.extend(collapsibleComponent);
+ vm = new Component({
+ store,
+ propsData: {
+ repo: repoPropsData,
+ },
+ }).$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('toggle', () => {
+ it('should be closed by default', () => {
+ expect(vm.$el.querySelector('.container-image-tags')).toBe(null);
+ expect(vm.$el.querySelector('.container-image-head i').className).toEqual('fa fa-chevron-right');
+ });
+
+ it('should be open when user clicks on closed repo', (done) => {
+ vm.$el.querySelector('.js-toggle-repo').click();
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.container-image-tags')).toBeDefined();
+ expect(vm.$el.querySelector('.container-image-head i').className).toEqual('fa fa-chevron-up');
+ done();
+ });
+ });
+
+ it('should be closed when the user clicks on an opened repo', (done) => {
+ vm.$el.querySelector('.js-toggle-repo').click();
+
+ Vue.nextTick(() => {
+ vm.$el.querySelector('.js-toggle-repo').click();
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.container-image-tags')).toBe(null);
+ expect(vm.$el.querySelector('.container-image-head i').className).toEqual('fa fa-chevron-right');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('delete repo', () => {
+ it('should be possible to delete a repo', () => {
+ expect(vm.$el.querySelector('.js-remove-repo')).toBeDefined();
+ });
+ });
+});
diff --git a/spec/javascripts/registry/components/table_registry_spec.js b/spec/javascripts/registry/components/table_registry_spec.js
new file mode 100644
index 00000000000..6aa61afc445
--- /dev/null
+++ b/spec/javascripts/registry/components/table_registry_spec.js
@@ -0,0 +1,49 @@
+import Vue from 'vue';
+import tableRegistry from '~/registry/components/table_registry.vue';
+import store from '~/registry/stores';
+import { repoPropsData } from '../mock_data';
+
+describe('table registry', () => {
+ let vm;
+ let Component;
+
+ beforeEach(() => {
+ Component = Vue.extend(tableRegistry);
+ vm = new Component({
+ store,
+ propsData: {
+ repo: repoPropsData,
+ },
+ }).$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should render a table with the registry list', () => {
+ expect(
+ vm.$el.querySelectorAll('table tbody tr').length,
+ ).toEqual(repoPropsData.list.length);
+ });
+
+ it('should render registry tag', () => {
+ const textRendered = vm.$el.querySelector('.table tbody tr').textContent.trim().replace(/\s\s+/g, ' ');
+ expect(textRendered).toContain(repoPropsData.list[0].tag);
+ expect(textRendered).toContain(repoPropsData.list[0].shortRevision);
+ expect(textRendered).toContain(repoPropsData.list[0].layers);
+ expect(textRendered).toContain(repoPropsData.list[0].size);
+ });
+
+ it('should be possible to delete a registry', () => {
+ expect(
+ vm.$el.querySelector('.table tbody tr .js-delete-registry'),
+ ).toBeDefined();
+ });
+
+ describe('pagination', () => {
+ it('should be possible to change the page', () => {
+ expect(vm.$el.querySelector('.gl-pagination')).toBeDefined();
+ });
+ });
+});
diff --git a/spec/javascripts/registry/getters_spec.js b/spec/javascripts/registry/getters_spec.js
new file mode 100644
index 00000000000..3d989541881
--- /dev/null
+++ b/spec/javascripts/registry/getters_spec.js
@@ -0,0 +1,43 @@
+import * as getters from '~/registry/stores/getters';
+
+describe('Getters Registry Store', () => {
+ let state;
+
+ beforeEach(() => {
+ state = {
+ isLoading: false,
+ endpoint: '/root/empty-project/container_registry.json',
+ repos: [{
+ canDelete: true,
+ destroyPath: 'bar',
+ id: '134',
+ isLoading: false,
+ list: [],
+ location: 'foo',
+ name: 'gitlab-org/omnibus-gitlab/foo',
+ tagsPath: 'foo',
+ }, {
+ canDelete: true,
+ destroyPath: 'bar',
+ id: '123',
+ isLoading: false,
+ list: [],
+ location: 'foo',
+ name: 'gitlab-org/omnibus-gitlab',
+ tagsPath: 'foo',
+ }],
+ };
+ });
+
+ describe('isLoading', () => {
+ it('should return the isLoading property', () => {
+ expect(getters.isLoading(state)).toEqual(state.isLoading);
+ });
+ });
+
+ describe('repos', () => {
+ it('should return the repos', () => {
+ expect(getters.repos(state)).toEqual(state.repos);
+ });
+ });
+});
diff --git a/spec/javascripts/registry/mock_data.js b/spec/javascripts/registry/mock_data.js
new file mode 100644
index 00000000000..18600d00bff
--- /dev/null
+++ b/spec/javascripts/registry/mock_data.js
@@ -0,0 +1,122 @@
+export const defaultState = {
+ isLoading: false,
+ endpoint: '',
+ repos: [],
+};
+
+export const reposServerResponse = [
+ {
+ destroy_path: 'path',
+ id: '123',
+ location: 'location',
+ path: 'foo',
+ tags_path: 'tags_path',
+ },
+ {
+ destroy_path: 'path_',
+ id: '456',
+ location: 'location_',
+ path: 'bar',
+ tags_path: 'tags_path_',
+ },
+];
+
+export const registryServerResponse = [
+ {
+ name: 'centos7',
+ short_revision: 'b118ab5b0',
+ revision: 'b118ab5b0e90b7cb5127db31d5321ac14961d097516a8e0e72084b6cdc783b43',
+ size: 679,
+ layers: 19,
+ location: 'location',
+ created_at: 1505828744434,
+ destroy_path: 'path_',
+ },
+ {
+ name: 'centos6',
+ short_revision: 'b118ab5b0',
+ revision: 'b118ab5b0e90b7cb5127db31d5321ac14961d097516a8e0e72084b6cdc783b43',
+ size: 679,
+ layers: 19,
+ location: 'location',
+ created_at: 1505828744434,
+ }];
+
+export const parsedReposServerResponse = [
+ {
+ canDelete: true,
+ destroyPath: reposServerResponse[0].destroy_path,
+ id: reposServerResponse[0].id,
+ isLoading: false,
+ list: [],
+ location: reposServerResponse[0].location,
+ name: reposServerResponse[0].path,
+ tagsPath: reposServerResponse[0].tags_path,
+ },
+ {
+ canDelete: true,
+ destroyPath: reposServerResponse[1].destroy_path,
+ id: reposServerResponse[1].id,
+ isLoading: false,
+ list: [],
+ location: reposServerResponse[1].location,
+ name: reposServerResponse[1].path,
+ tagsPath: reposServerResponse[1].tags_path,
+ },
+];
+
+export const parsedRegistryServerResponse = [
+ {
+ tag: registryServerResponse[0].name,
+ revision: registryServerResponse[0].revision,
+ shortRevision: registryServerResponse[0].short_revision,
+ size: registryServerResponse[0].size,
+ layers: registryServerResponse[0].layers,
+ location: registryServerResponse[0].location,
+ createdAt: registryServerResponse[0].created_at,
+ destroyPath: registryServerResponse[0].destroy_path,
+ canDelete: true,
+ },
+ {
+ tag: registryServerResponse[1].name,
+ revision: registryServerResponse[1].revision,
+ shortRevision: registryServerResponse[1].short_revision,
+ size: registryServerResponse[1].size,
+ layers: registryServerResponse[1].layers,
+ location: registryServerResponse[1].location,
+ createdAt: registryServerResponse[1].created_at,
+ destroyPath: registryServerResponse[1].destroy_path,
+ canDelete: false,
+ },
+];
+
+export const repoPropsData = {
+ canDelete: true,
+ destroyPath: 'path',
+ id: '123',
+ isLoading: false,
+ list: [
+ {
+ tag: 'centos6',
+ revision: 'b118ab5b0e90b7cb5127db31d5321ac14961d097516a8e0e72084b6cdc783b43',
+ shortRevision: 'b118ab5b0',
+ size: 19,
+ layers: 10,
+ location: 'location',
+ createdAt: 1505828744434,
+ destroyPath: 'path',
+ canDelete: true,
+ },
+ ],
+ location: 'location',
+ name: 'foo',
+ tagsPath: 'path',
+ pagination: {
+ perPage: 5,
+ page: 1,
+ total: 13,
+ totalPages: 1,
+ nextPage: null,
+ previousPage: null,
+ },
+};
diff --git a/spec/javascripts/registry/stores/actions_spec.js b/spec/javascripts/registry/stores/actions_spec.js
new file mode 100644
index 00000000000..3c9da4f107b
--- /dev/null
+++ b/spec/javascripts/registry/stores/actions_spec.js
@@ -0,0 +1,85 @@
+import Vue from 'vue';
+import VueResource from 'vue-resource';
+import _ from 'underscore';
+import * as actions from '~/registry/stores/actions';
+import * as types from '~/registry/stores/mutation_types';
+import testAction from '../../helpers/vuex_action_helper';
+import {
+ defaultState,
+ reposServerResponse,
+ registryServerResponse,
+ parsedReposServerResponse,
+} from '../mock_data';
+
+Vue.use(VueResource);
+
+describe('Actions Registry Store', () => {
+ let interceptor;
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = defaultState;
+ });
+
+ describe('server requests', () => {
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ describe('fetchRepos', () => {
+ beforeEach(() => {
+ interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify(reposServerResponse), {
+ status: 200,
+ }));
+ };
+
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ it('should set receveived repos', (done) => {
+ testAction(actions.fetchRepos, null, mockedState, [
+ { type: types.TOGGLE_MAIN_LOADING },
+ { type: types.SET_REPOS_LIST, payload: reposServerResponse },
+ ], done);
+ });
+ });
+
+ describe('fetchList', () => {
+ beforeEach(() => {
+ interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify(registryServerResponse), {
+ status: 200,
+ }));
+ };
+
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ it('should set received list', (done) => {
+ mockedState.repos = parsedReposServerResponse;
+
+ testAction(actions.fetchList, { repo: mockedState.repos[1] }, mockedState, [
+ { type: types.TOGGLE_REGISTRY_LIST_LOADING },
+ { type: types.SET_REGISTRY_LIST, payload: registryServerResponse },
+ ], done);
+ });
+ });
+ });
+
+ describe('setMainEndpoint', () => {
+ it('should commit set main endpoint', (done) => {
+ testAction(actions.setMainEndpoint, 'endpoint', mockedState, [
+ { type: types.SET_MAIN_ENDPOINT, payload: 'endpoint' },
+ ], done);
+ });
+ });
+
+ describe('toggleLoading', () => {
+ it('should commit toggle main loading', (done) => {
+ testAction(actions.toggleLoading, null, mockedState, [
+ { type: types.TOGGLE_MAIN_LOADING },
+ ], done);
+ });
+ });
+});
diff --git a/spec/javascripts/registry/stores/mutations_spec.js b/spec/javascripts/registry/stores/mutations_spec.js
new file mode 100644
index 00000000000..2e4c0659daa
--- /dev/null
+++ b/spec/javascripts/registry/stores/mutations_spec.js
@@ -0,0 +1,81 @@
+import mutations from '~/registry/stores/mutations';
+import * as types from '~/registry/stores/mutation_types';
+import {
+ defaultState,
+ reposServerResponse,
+ registryServerResponse,
+ parsedReposServerResponse,
+ parsedRegistryServerResponse,
+} from '../mock_data';
+
+describe('Mutations Registry Store', () => {
+ let mockState;
+ beforeEach(() => {
+ mockState = defaultState;
+ });
+
+ describe('SET_MAIN_ENDPOINT', () => {
+ it('should set the main endpoint', () => {
+ const expectedState = Object.assign({}, mockState, { endpoint: 'foo' });
+ mutations[types.SET_MAIN_ENDPOINT](mockState, 'foo');
+ expect(mockState).toEqual(expectedState);
+ });
+ });
+
+ describe('SET_REPOS_LIST', () => {
+ it('should set a parsed repository list', () => {
+ mutations[types.SET_REPOS_LIST](mockState, reposServerResponse);
+ expect(mockState.repos).toEqual(parsedReposServerResponse);
+ });
+ });
+
+ describe('TOGGLE_MAIN_LOADING', () => {
+ it('should set a parsed repository list', () => {
+ mutations[types.TOGGLE_MAIN_LOADING](mockState);
+ expect(mockState.isLoading).toEqual(true);
+ });
+ });
+
+ describe('SET_REGISTRY_LIST', () => {
+ it('should set a list of registries in a specific repository', () => {
+ mutations[types.SET_REPOS_LIST](mockState, reposServerResponse);
+ mutations[types.SET_REGISTRY_LIST](mockState, {
+ repo: mockState.repos[0],
+ resp: registryServerResponse,
+ headers: {
+ 'x-per-page': 2,
+ 'x-page': 1,
+ 'x-total': 10,
+ },
+ });
+
+ expect(mockState.repos[0].list).toEqual(parsedRegistryServerResponse);
+ expect(mockState.repos[0].pagination).toEqual({
+ perPage: 2,
+ page: 1,
+ total: 10,
+ totalPages: NaN,
+ nextPage: NaN,
+ previousPage: NaN,
+ });
+ });
+ });
+
+ describe('TOGGLE_REGISTRY_LIST_LOADING', () => {
+ it('should toggle isLoading property for a specific repository', () => {
+ mutations[types.SET_REPOS_LIST](mockState, reposServerResponse);
+ mutations[types.SET_REGISTRY_LIST](mockState, {
+ repo: mockState.repos[0],
+ resp: registryServerResponse,
+ headers: {
+ 'x-per-page': 2,
+ 'x-page': 1,
+ 'x-total': 10,
+ },
+ });
+
+ mutations[types.TOGGLE_REGISTRY_LIST_LOADING](mockState, mockState.repos[0]);
+ expect(mockState.repos[0].isLoading).toEqual(true);
+ });
+ });
+});
diff --git a/spec/javascripts/repo/components/repo_edit_button_spec.js b/spec/javascripts/repo/components/repo_edit_button_spec.js
index 29dc2d21e4b..411514009dc 100644
--- a/spec/javascripts/repo/components/repo_edit_button_spec.js
+++ b/spec/javascripts/repo/components/repo_edit_button_spec.js
@@ -21,13 +21,11 @@ describe('RepoEditButton', () => {
expect(vm.$el.textContent).toMatch('Edit');
spyOn(vm, 'editCancelClicked').and.callThrough();
- spyOn(vm, 'toggleProjectRefsForm');
vm.$el.click();
Vue.nextTick(() => {
expect(vm.editCancelClicked).toHaveBeenCalled();
- expect(vm.toggleProjectRefsForm).toHaveBeenCalled();
expect(vm.$el.textContent).toMatch('Cancel edit');
done();
});
diff --git a/spec/javascripts/repo/components/repo_file_spec.js b/spec/javascripts/repo/components/repo_file_spec.js
index 518a2d25ecf..f15633bd8b9 100644
--- a/spec/javascripts/repo/components/repo_file_spec.js
+++ b/spec/javascripts/repo/components/repo_file_spec.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import repoFile from '~/repo/components/repo_file.vue';
+import RepoStore from '~/repo/stores/repo_store';
describe('RepoFile', () => {
const updated = 'updated';
@@ -12,8 +13,13 @@ describe('RepoFile', () => {
level: 10,
};
const activeFile = {
+ pageTitle: 'pageTitle',
url: 'url',
};
+ const otherFile = {
+ html: '<p class="file-content">html</p>',
+ pageTitle: 'otherpageTitle',
+ };
function createComponent(propsData) {
const RepoFile = Vue.extend(repoFile);
@@ -60,6 +66,12 @@ describe('RepoFile', () => {
expect(vm.$el.querySelector('.fa-spin.fa-spinner')).toBeFalsy();
});
+ it('sets the document title correctly', () => {
+ RepoStore.setActiveFiles(otherFile);
+
+ expect(document.title.trim()).toEqual(otherFile.pageTitle);
+ });
+
it('renders a spinner if the file is loading', () => {
file.loading = true;
const vm = createComponent({
diff --git a/spec/javascripts/repo/components/repo_sidebar_spec.js b/spec/javascripts/repo/components/repo_sidebar_spec.js
index db9911c7a2c..23c10ea022e 100644
--- a/spec/javascripts/repo/components/repo_sidebar_spec.js
+++ b/spec/javascripts/repo/components/repo_sidebar_spec.js
@@ -23,8 +23,8 @@ describe('RepoSidebar', () => {
expect(vm.$el.id).toEqual('sidebar');
expect(vm.$el.classList.contains('sidebar-mini')).toBeFalsy();
expect(thead.querySelector('.name').textContent).toEqual('Name');
- expect(thead.querySelector('.last-commit').textContent).toEqual('Last Commit');
- expect(thead.querySelector('.last-update').textContent).toEqual('Last Update');
+ expect(thead.querySelector('.last-commit').textContent).toEqual('Last commit');
+ expect(thead.querySelector('.last-update').textContent).toEqual('Last update');
expect(tbody.querySelector('.repo-file-options')).toBeFalsy();
expect(tbody.querySelector('.prev-directory')).toBeFalsy();
expect(tbody.querySelector('.loading-file')).toBeFalsy();
diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js
index f2072a6f350..5505f983d71 100644
--- a/spec/javascripts/right_sidebar_spec.js
+++ b/spec/javascripts/right_sidebar_spec.js
@@ -32,56 +32,86 @@ import '~/right_sidebar';
};
describe('RightSidebar', function() {
- var fixtureName = 'issues/open-issue.html.raw';
- preloadFixtures(fixtureName);
- loadJSONFixtures('todos/todos.json');
-
- beforeEach(function() {
- loadFixtures(fixtureName);
- this.sidebar = new Sidebar;
- $aside = $('.right-sidebar');
- $page = $('.page-with-sidebar');
- $icon = $aside.find('i');
- $toggle = $aside.find('.js-sidebar-toggle');
- return $labelsIcon = $aside.find('.sidebar-collapsed-icon');
- });
- it('should expand/collapse the sidebar when arrow is clicked', function() {
- assertSidebarState('expanded');
- $toggle.click();
- assertSidebarState('collapsed');
- $toggle.click();
- assertSidebarState('expanded');
- });
- it('should float over the page and when sidebar icons clicked', function() {
- $labelsIcon.click();
- return assertSidebarState('expanded');
- });
- it('should collapse when the icon arrow clicked while it is floating on page', function() {
- $labelsIcon.click();
- assertSidebarState('expanded');
- $toggle.click();
- return assertSidebarState('collapsed');
+ describe('fixture tests', () => {
+ var fixtureName = 'issues/open-issue.html.raw';
+ preloadFixtures(fixtureName);
+ loadJSONFixtures('todos/todos.json');
+
+ beforeEach(function() {
+ loadFixtures(fixtureName);
+ this.sidebar = new Sidebar;
+ $aside = $('.right-sidebar');
+ $page = $('.page-with-sidebar');
+ $icon = $aside.find('i');
+ $toggle = $aside.find('.js-sidebar-toggle');
+ return $labelsIcon = $aside.find('.sidebar-collapsed-icon');
+ });
+ it('should expand/collapse the sidebar when arrow is clicked', function() {
+ assertSidebarState('expanded');
+ $toggle.click();
+ assertSidebarState('collapsed');
+ $toggle.click();
+ assertSidebarState('expanded');
+ });
+ it('should float over the page and when sidebar icons clicked', function() {
+ $labelsIcon.click();
+ return assertSidebarState('expanded');
+ });
+ it('should collapse when the icon arrow clicked while it is floating on page', function() {
+ $labelsIcon.click();
+ assertSidebarState('expanded');
+ $toggle.click();
+ return assertSidebarState('collapsed');
+ });
+
+ it('should broadcast todo:toggle event when add todo clicked', function() {
+ var todos = getJSONFixture('todos/todos.json');
+ spyOn(jQuery, 'ajax').and.callFake(function() {
+ var d = $.Deferred();
+ var response = todos;
+ d.resolve(response);
+ return d.promise();
+ });
+
+ var todoToggleSpy = spyOnEvent(document, 'todo:toggle');
+
+ $('.issuable-sidebar-header .js-issuable-todo').click();
+
+ expect(todoToggleSpy.calls.count()).toEqual(1);
+ });
+
+ it('should not hide collapsed icons', () => {
+ [].forEach.call(document.querySelectorAll('.sidebar-collapsed-icon'), (el) => {
+ expect(el.querySelector('.fa, svg').classList.contains('hidden')).toBeFalsy();
+ });
+ });
});
- it('should broadcast todo:toggle event when add todo clicked', function() {
- var todos = getJSONFixture('todos/todos.json');
- spyOn(jQuery, 'ajax').and.callFake(function() {
- var d = $.Deferred();
- var response = todos;
- d.resolve(response);
- return d.promise();
+ describe('sidebarToggleClicked', () => {
+ const event = jasmine.createSpyObj('event', ['preventDefault']);
+
+ beforeEach(() => {
+ spyOn($.fn, 'hasClass').and.returnValue(false);
+ });
+
+ afterEach(() => {
+ gl.lazyLoader = undefined;
});
- var todoToggleSpy = spyOnEvent(document, 'todo:toggle');
+ it('calls loadCheck if lazyLoader is set', () => {
+ gl.lazyLoader = jasmine.createSpyObj('lazyLoader', ['loadCheck']);
- $('.issuable-sidebar-header .js-issuable-todo').click();
+ Sidebar.prototype.sidebarToggleClicked(event);
- expect(todoToggleSpy.calls.count()).toEqual(1);
- });
+ expect(gl.lazyLoader.loadCheck).toHaveBeenCalled();
+ });
+
+ it('does not throw if lazyLoader is not defined', () => {
+ gl.lazyLoader = undefined;
+
+ const toggle = Sidebar.prototype.sidebarToggleClicked.bind(null, event);
- it('should not hide collapsed icons', () => {
- [].forEach.call(document.querySelectorAll('.sidebar-collapsed-icon'), (el) => {
- expect(el.querySelector('.fa, svg').classList.contains('hidden')).toBeFalsy();
+ expect(toggle).not.toThrow();
});
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js
index 47303d1e80f..d23b558f4ea 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js
@@ -4,11 +4,15 @@ import closedComponent from '~/vue_merge_request_widget/components/states/mr_wid
const mr = {
targetBranch: 'good-branch',
targetBranchPath: '/good-branch',
- closedBy: {
- name: 'Fatih Acet',
- username: 'fatihacet',
+ closedEvent: {
+ author: {
+ name: 'Fatih Acet',
+ username: 'fatihacet',
+ },
+ updatedAt: 'closedEventUpdatedAt',
+ formattedUpdatedAt: '',
},
- updatedAt: '2017-03-23T20:08:08.845Z',
+ updatedAt: 'mrUpdatedAt',
closedAt: '1 day ago',
};
@@ -18,7 +22,7 @@ const createComponent = () => {
return new Component({
el: document.createElement('div'),
propsData: { mr },
- }).$el;
+ });
};
describe('MRWidgetClosed', () => {
@@ -38,14 +42,30 @@ describe('MRWidgetClosed', () => {
});
describe('template', () => {
- it('should have correct elements', () => {
- const el = createComponent();
+ let vm;
+ let el;
+ beforeEach(() => {
+ vm = createComponent();
+ el = vm.$el;
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should have correct elements', () => {
expect(el.querySelector('h4').textContent).toContain('Closed by');
- expect(el.querySelector('h4').textContent).toContain(mr.closedBy.name);
+ expect(el.querySelector('h4').textContent).toContain(mr.closedEvent.author.name);
expect(el.textContent).toContain('The changes were not merged into');
expect(el.querySelector('.label-branch').getAttribute('href')).toEqual(mr.targetBranchPath);
expect(el.querySelector('.label-branch').textContent).toContain(mr.targetBranch);
});
+
+ it('should use closedEvent updatedAt as tooltip title', () => {
+ expect(
+ el.querySelector('time').getAttribute('title'),
+ ).toBe('closedEventUpdatedAt');
+ });
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
index 3b7b7d93662..5d4c7ec09dc 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
@@ -1,20 +1,9 @@
import Vue from 'vue';
import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
+const ConflictsComponent = Vue.extend(conflictsComponent);
const path = '/conflicts';
-const createComponent = () => {
- const Component = Vue.extend(conflictsComponent);
-
- return new Component({
- el: document.createElement('div'),
- propsData: {
- mr: {
- canMerge: true,
- conflictResolutionPath: path,
- },
- },
- });
-};
describe('MRWidgetConflicts', () => {
describe('props', () => {
@@ -27,44 +16,90 @@ describe('MRWidgetConflicts', () => {
});
describe('template', () => {
- it('should have correct elements', () => {
- const el = createComponent().$el;
- const resolveButton = el.querySelector('.js-resolve-conflicts-button');
- const mergeButton = el.querySelector('.mr-widget-body .btn');
- const mergeLocallyButton = el.querySelector('.js-merge-locally-button');
-
- expect(el.textContent).toContain('There are merge conflicts');
- expect(el.textContent).not.toContain('ask someone with write access');
- expect(el.querySelector('.btn-success').disabled).toBeTruthy();
- expect(resolveButton.textContent).toContain('Resolve conflicts');
- expect(resolveButton.getAttribute('href')).toEqual(path);
- expect(mergeButton.textContent).toContain('Merge');
- expect(mergeLocallyButton.textContent).toContain('Merge locally');
+ describe('when allowed to merge', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = mountComponent(ConflictsComponent, {
+ mr: {
+ canMerge: true,
+ conflictResolutionPath: path,
+ },
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should tell you about conflicts without bothering other people', () => {
+ expect(vm.$el.textContent).toContain('There are merge conflicts');
+ expect(vm.$el.textContent).not.toContain('ask someone with write access');
+ });
+
+ it('should allow you to resolve the conflicts', () => {
+ const resolveButton = vm.$el.querySelector('.js-resolve-conflicts-button');
+
+ expect(resolveButton.textContent).toContain('Resolve conflicts');
+ expect(resolveButton.getAttribute('href')).toEqual(path);
+ });
+
+ it('should have merge buttons', () => {
+ const mergeButton = vm.$el.querySelector('.js-disabled-merge-button');
+ const mergeLocallyButton = vm.$el.querySelector('.js-merge-locally-button');
+
+ expect(mergeButton.textContent).toContain('Merge');
+ expect(mergeButton.disabled).toBeTruthy();
+ expect(mergeButton.classList.contains('btn-success')).toEqual(true);
+ expect(mergeLocallyButton.textContent).toContain('Merge locally');
+ });
});
describe('when user does not have permission to merge', () => {
let vm;
beforeEach(() => {
- vm = createComponent();
- vm.mr.canMerge = false;
+ vm = mountComponent(ConflictsComponent, {
+ mr: {
+ canMerge: false,
+ },
+ });
});
- it('should show proper message', (done) => {
- Vue.nextTick(() => {
- expect(vm.$el.textContent).toContain('ask someone with write access');
- done();
- });
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should show proper message', () => {
+ expect(vm.$el.textContent).toContain('ask someone with write access');
+ });
+
+ it('should not have action buttons', () => {
+ expect(vm.$el.querySelector('.js-disabled-merge-button')).toBeDefined();
+ expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toBeNull();
+ expect(vm.$el.querySelector('.js-merge-locally-button')).toBeNull();
});
+ });
- it('should not have action buttons', (done) => {
- Vue.nextTick(() => {
- expect(vm.$el.querySelectorAll('.btn').length).toBe(1);
- expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toEqual(null);
- expect(vm.$el.querySelector('.js-merge-locally-button')).toEqual(null);
- done();
+ describe('when fast-forward or semi-linear merge enabled', () => {
+ let vm;
+
+ beforeEach(() => {
+ vm = mountComponent(ConflictsComponent, {
+ mr: {
+ shouldBeRebased: true,
+ },
});
});
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should tell you to rebase locally', () => {
+ expect(vm.$el.textContent).toContain('Fast-forward merge is not possible.');
+ expect(vm.$el.textContent).toContain('To merge this request, first rebase locally');
+ });
});
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
index afaa750199a..2714e8294fa 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
@@ -14,9 +14,12 @@ const createComponent = () => {
canRevertInCurrentMR: true,
canRemoveSourceBranch: true,
sourceBranchRemoved: true,
- mergedBy: {},
- mergedAt: '',
- updatedAt: '',
+ mergedEvent: {
+ author: {},
+ updatedAt: 'mergedUpdatedAt',
+ formattedUpdatedAt: '',
+ },
+ updatedAt: 'mrUpdatedAt',
targetBranch,
};
@@ -170,5 +173,11 @@ describe('MRWidgetMerged', () => {
done();
});
});
+
+ it('should use mergedEvent updatedAt as tooltip title', () => {
+ expect(
+ el.querySelector('time').getAttribute('title'),
+ ).toBe('mergedUpdatedAt');
+ });
});
});
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 03a52f1f91c..c83b947579b 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
@@ -95,35 +95,84 @@ describe('MRWidgetReadyToMerge', () => {
});
});
+ describe('status', () => {
+ it('defaults to success', () => {
+ vm.mr.pipeline = true;
+ expect(vm.status).toEqual('success');
+ });
+
+ it('returns failed when MR has CI but also has an unknown status', () => {
+ vm.mr.hasCI = true;
+ expect(vm.status).toEqual('failed');
+ });
+
+ it('returns default when MR has no pipeline', () => {
+ expect(vm.status).toEqual('success');
+ });
+
+ it('returns pending when pipeline is active', () => {
+ vm.mr.pipeline = {};
+ vm.mr.isPipelineActive = true;
+ expect(vm.status).toEqual('pending');
+ });
+
+ it('returns failed when pipeline is failed', () => {
+ vm.mr.pipeline = {};
+ vm.mr.isPipelineFailed = true;
+ expect(vm.status).toEqual('failed');
+ });
+ });
+
describe('mergeButtonClass', () => {
const defaultClass = 'btn btn-sm btn-success accept-merge-request';
const failedClass = `${defaultClass} btn-danger`;
const inActionClass = `${defaultClass} btn-info`;
- it('should return default class', () => {
+ it('defaults to success class', () => {
+ expect(vm.mergeButtonClass).toEqual(defaultClass);
+ });
+
+ it('returns success class for success status', () => {
vm.mr.pipeline = true;
expect(vm.mergeButtonClass).toEqual(defaultClass);
});
- it('should return failed class when MR has CI but also has an unknown status', () => {
+ it('returns info class for pending status', () => {
+ vm.mr.pipeline = {};
+ vm.mr.isPipelineActive = true;
+ expect(vm.mergeButtonClass).toEqual(inActionClass);
+ });
+
+ it('returns failed class for failed status', () => {
vm.mr.hasCI = true;
expect(vm.mergeButtonClass).toEqual(failedClass);
});
+ });
- it('should return default class when MR has no pipeline', () => {
- expect(vm.mergeButtonClass).toEqual(defaultClass);
+ describe('status icon', () => {
+ it('defaults to tick icon', () => {
+ expect(vm.iconClass).toEqual('success');
+ });
+
+ it('shows tick for success status', () => {
+ vm.mr.pipeline = true;
+ expect(vm.iconClass).toEqual('success');
});
- it('should return in action class when pipeline is active', () => {
+ it('shows tick for pending status', () => {
vm.mr.pipeline = {};
vm.mr.isPipelineActive = true;
- expect(vm.mergeButtonClass).toEqual(inActionClass);
+ expect(vm.iconClass).toEqual('success');
});
- it('should return failed class when pipeline is failed', () => {
- vm.mr.pipeline = {};
- vm.mr.isPipelineFailed = true;
- expect(vm.mergeButtonClass).toEqual(failedClass);
+ it('shows x for failed status', () => {
+ vm.mr.hasCI = true;
+ expect(vm.iconClass).toEqual('failed');
+ });
+
+ it('shows x for merge not allowed', () => {
+ vm.mr.hasCI = true;
+ expect(vm.iconClass).toEqual('failed');
});
});
@@ -177,41 +226,11 @@ describe('MRWidgetReadyToMerge', () => {
expect(vm.isMergeButtonDisabled).toBeTruthy();
});
- it('should return true when there vm instance is making request', () => {
+ it('should return true when the vm instance is making request', () => {
vm.isMakingRequest = true;
expect(vm.isMergeButtonDisabled).toBeTruthy();
});
});
-
- 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');
- });
- });
-
- describe('when user can merge and can delete branch', () => {
- beforeEach(() => {
- this.customVm = createComponent({
- mr: { canRemoveSourceBranch: true },
- });
- });
-
- it('isRemoveSourceBranchButtonDisabled should be false', () => {
- expect(this.customVm.isRemoveSourceBranchButtonDisabled).toBe(false);
- });
-
- it('should be enabled in rendered output', () => {
- const checkboxElement = this.customVm.$el.querySelector('#remove-source-branch-input');
- expect(checkboxElement.getAttribute('disabled')).toBeNull();
- });
- });
- });
});
describe('methods', () => {
@@ -467,4 +486,54 @@ 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');
+ });
+ });
+
+ describe('when user can merge and can delete branch', () => {
+ beforeEach(() => {
+ this.customVm = createComponent({
+ mr: { canRemoveSourceBranch: true },
+ });
+ });
+
+ it('isRemoveSourceBranchButtonDisabled should be false', () => {
+ expect(this.customVm.isRemoveSourceBranchButtonDisabled).toBe(false);
+ });
+
+ it('should be enabled in rendered output', () => {
+ const checkboxElement = this.customVm.$el.querySelector('#remove-source-branch-input');
+ expect(checkboxElement.getAttribute('disabled')).toBeNull();
+ });
+ });
+ });
+
+ describe('Commit message area', () => {
+ it('when using merge commits, should show "Modify commit message" button', () => {
+ const customVm = createComponent({
+ mr: { ffOnlyEnabled: false },
+ });
+
+ expect(customVm.$el.querySelector('.js-fast-forward-message')).toBeNull();
+ expect(customVm.$el.querySelector('.js-modify-commit-message-button')).toBeDefined();
+ });
+
+ it('when fast-forward merge is enabled, only show fast-forward message', () => {
+ const customVm = createComponent({
+ mr: { ffOnlyEnabled: true },
+ });
+
+ expect(customVm.$el.querySelector('.js-fast-forward-message')).toBeDefined();
+ expect(customVm.$el.querySelector('.js-modify-commit-message-button')).toBeNull();
+ });
+ });
});
diff --git a/spec/lib/github/import/legacy_diff_note_spec.rb b/spec/lib/github/import/legacy_diff_note_spec.rb
new file mode 100644
index 00000000000..8c50b46cacb
--- /dev/null
+++ b/spec/lib/github/import/legacy_diff_note_spec.rb
@@ -0,0 +1,9 @@
+require 'spec_helper'
+
+describe Github::Import::LegacyDiffNote do
+ describe '#type' do
+ it 'returns the original note type' do
+ expect(described_class.new.type).to eq('LegacyDiffNote')
+ end
+ end
+end
diff --git a/spec/lib/github/import/note_spec.rb b/spec/lib/github/import/note_spec.rb
new file mode 100644
index 00000000000..fcdccd9e097
--- /dev/null
+++ b/spec/lib/github/import/note_spec.rb
@@ -0,0 +1,9 @@
+require 'spec_helper'
+
+describe Github::Import::Note do
+ describe '#type' do
+ it 'returns the original note type' do
+ expect(described_class.new.type).to eq('Note')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
index c0427639746..d2e7243ee05 100644
--- a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
+++ b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do
+describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :truncate do
describe '#perform' do
- set(:merge_request) { create(:merge_request) }
- set(:merge_request_diff) { merge_request.merge_request_diff }
+ let(:merge_request) { create(:merge_request) }
+ let(:merge_request_diff) { merge_request.merge_request_diff }
let(:updated_merge_request_diff) { MergeRequestDiff.find(merge_request_diff.id) }
def diffs_to_hashes(diffs)
@@ -70,8 +70,8 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do
before do
merge_request.reload_diff(true)
- convert_to_yaml(start_id, merge_request_diff.commits, merge_request_diff.diffs)
- convert_to_yaml(stop_id, updated_merge_request_diff.commits, updated_merge_request_diff.diffs)
+ convert_to_yaml(start_id, merge_request_diff.commits, diffs_to_hashes(merge_request_diff.merge_request_diff_files))
+ convert_to_yaml(stop_id, updated_merge_request_diff.commits, diffs_to_hashes(updated_merge_request_diff.merge_request_diff_files))
MergeRequestDiffCommit.delete_all
MergeRequestDiffFile.delete_all
@@ -80,10 +80,32 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do
context 'when BUFFER_ROWS is exceeded' do
before do
stub_const("#{described_class}::BUFFER_ROWS", 1)
+
+ allow(Gitlab::Database).to receive(:bulk_insert).and_call_original
+ end
+
+ it 'inserts commit rows in chunks of BUFFER_ROWS' do
+ # There are 29 commits in each diff, so we should have slices of 20 + 9 + 20 + 9.
+ stub_const("#{described_class}::BUFFER_ROWS", 20)
+
+ expect(Gitlab::Database).to receive(:bulk_insert)
+ .with('merge_request_diff_commits', anything)
+ .exactly(4)
+ .times
+ .and_call_original
+
+ subject.perform(start_id, stop_id)
end
- it 'updates and continues' do
- expect(described_class::MergeRequestDiff).to receive(:transaction).twice
+ it 'inserts diff rows in chunks of DIFF_FILE_BUFFER_ROWS' do
+ # There are 20 files in each diff, so we should have slices of 20 + 20.
+ stub_const("#{described_class}::DIFF_FILE_BUFFER_ROWS", 20)
+
+ expect(Gitlab::Database).to receive(:bulk_insert)
+ .with('merge_request_diff_files', anything)
+ .exactly(2)
+ .times
+ .and_call_original
subject.perform(start_id, stop_id)
end
@@ -91,27 +113,87 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do
context 'when BUFFER_ROWS is not exceeded' do
it 'only updates once' do
- expect(described_class::MergeRequestDiff).to receive(:transaction).once
+ expect(Gitlab::Database).to receive(:bulk_insert)
+ .with('merge_request_diff_commits', anything)
+ .once
+ .and_call_original
+
+ expect(Gitlab::Database).to receive(:bulk_insert)
+ .with('merge_request_diff_files', anything)
+ .once
+ .and_call_original
subject.perform(start_id, stop_id)
end
end
- end
- context 'when the merge request diff update fails' do
- before do
- allow(described_class::MergeRequestDiff)
- .to receive(:update_all).and_raise(ActiveRecord::Rollback)
- end
+ context 'when some rows were already inserted due to a previous failure' do
+ before do
+ subject.perform(start_id, stop_id)
- it 'does not add any diff commits' do
- expect { subject.perform(merge_request_diff.id, merge_request_diff.id) }
- .not_to change { MergeRequestDiffCommit.count }
+ convert_to_yaml(start_id, merge_request_diff.commits, diffs_to_hashes(merge_request_diff.merge_request_diff_files))
+ convert_to_yaml(stop_id, updated_merge_request_diff.commits, diffs_to_hashes(updated_merge_request_diff.merge_request_diff_files))
+ end
+
+ it 'does not raise' do
+ expect { subject.perform(start_id, stop_id) }.not_to raise_exception
+ end
+
+ it 'logs a message' do
+ expect(Rails.logger).to receive(:info)
+ .with(
+ a_string_matching(described_class.name).and(matching([start_id, stop_id].inspect))
+ )
+ .twice
+
+ subject.perform(start_id, stop_id)
+ end
+
+ it 'ends up with the correct rows' do
+ expect(updated_merge_request_diff.commits.count).to eq(29)
+ expect(updated_merge_request_diff.raw_diffs.count).to eq(20)
+ end
end
- it 'does not add any diff files' do
- expect { subject.perform(merge_request_diff.id, merge_request_diff.id) }
- .not_to change { MergeRequestDiffFile.count }
+ context 'when the merge request diff update fails' do
+ let(:exception) { ActiveRecord::RecordNotFound }
+
+ let(:perform_ignoring_exceptions) do
+ begin
+ subject.perform(start_id, stop_id)
+ rescue described_class::Error
+ end
+ end
+
+ before do
+ allow_any_instance_of(described_class::MergeRequestDiff::ActiveRecord_Relation)
+ .to receive(:update_all).and_raise(exception)
+ end
+
+ it 'raises an error' do
+ expect { subject.perform(start_id, stop_id) }
+ .to raise_exception(described_class::Error)
+ end
+
+ it 'logs the error' do
+ expect(Rails.logger).to receive(:info).with(
+ a_string_matching(described_class.name)
+ .and(matching([start_id, stop_id].inspect))
+ .and(matching(exception.name))
+ )
+
+ perform_ignoring_exceptions
+ end
+
+ it 'still adds diff commits' do
+ expect { perform_ignoring_exceptions }
+ .to change { MergeRequestDiffCommit.count }
+ end
+
+ it 'still adds diff files' do
+ expect { perform_ignoring_exceptions }
+ .to change { MergeRequestDiffFile.count }
+ end
end
end
diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb
index e6645985ba4..33540eab5d6 100644
--- a/spec/lib/gitlab/ci/ansi2html_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2html_spec.rb
@@ -195,6 +195,32 @@ describe Gitlab::Ci::Ansi2html do
end
end
+ context "with section markers" do
+ let(:section_name) { 'test_section' }
+ let(:section_start_time) { Time.new(2017, 9, 20).utc }
+ let(:section_duration) { 3.seconds }
+ let(:section_end_time) { section_start_time + section_duration }
+ let(:section_start) { "section_start:#{section_start_time.to_i}:#{section_name}\r\033[0K"}
+ let(:section_end) { "section_end:#{section_end_time.to_i}:#{section_name}\r\033[0K"}
+ let(:section_start_html) do
+ '<div class="hidden" data-action="start"'\
+ " data-timestamp=\"#{section_start_time.to_i}\" data-section=\"#{section_name}\">"\
+ "#{section_start[0...-5]}</div>"
+ end
+ let(:section_end_html) do
+ '<div class="hidden" data-action="end"'\
+ " data-timestamp=\"#{section_end_time.to_i}\" data-section=\"#{section_name}\">"\
+ "#{section_end[0...-5]}</div>"
+ end
+
+ it "prints light red" do
+ text = "#{section_start}\e[91mHello\e[0m\n#{section_end}"
+ html = %{#{section_start_html}<span class="term-fg-l-red">Hello</span><br>#{section_end_html}}
+
+ expect(convert_html(text)).to eq(html)
+ end
+ end
+
describe "truncates" do
let(:text) { "Hello World" }
let(:stream) { StringIO.new(text) }
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 9e528392756..ef7d766a13d 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -254,6 +254,46 @@ describe Gitlab::ClosingIssueExtractor do
expect(subject.closed_by_message(message)).to eq([issue])
end
+ it do
+ message = "Implement: #{reference}"
+ expect(subject.closed_by_message(message)).to eq([issue])
+ end
+
+ it do
+ message = "Implements: #{reference}"
+ expect(subject.closed_by_message(message)).to eq([issue])
+ end
+
+ it do
+ message = "Implemented: #{reference}"
+ expect(subject.closed_by_message(message)).to eq([issue])
+ end
+
+ it do
+ message = "Implementing: #{reference}"
+ expect(subject.closed_by_message(message)).to eq([issue])
+ end
+
+ it do
+ message = "implement: #{reference}"
+ expect(subject.closed_by_message(message)).to eq([issue])
+ end
+
+ it do
+ message = "implements: #{reference}"
+ expect(subject.closed_by_message(message)).to eq([issue])
+ end
+
+ it do
+ message = "implemented: #{reference}"
+ expect(subject.closed_by_message(message)).to eq([issue])
+ end
+
+ it do
+ message = "implementing: #{reference}"
+ expect(subject.closed_by_message(message)).to eq([issue])
+ end
+
context 'with an external issue tracker reference' do
it 'extracts the referenced issue' do
jira_project = create(:jira_project, name: 'JIRA_EXT1')
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index a3dff6d0d4b..3815055139a 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -65,34 +65,12 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
describe "Commit info from gitaly commit" do
- let(:id) { 'f00' }
- let(:parent_ids) { %w(b45 b46) }
let(:subject) { "My commit".force_encoding('ASCII-8BIT') }
let(:body) { subject + "My body".force_encoding('ASCII-8BIT') }
- let(:committer) do
- Gitaly::CommitAuthor.new(
- name: generate(:name),
- email: generate(:email),
- date: Google::Protobuf::Timestamp.new(seconds: 123)
- )
- end
- let(:author) do
- Gitaly::CommitAuthor.new(
- name: generate(:name),
- email: generate(:email),
- date: Google::Protobuf::Timestamp.new(seconds: 456)
- )
- end
- let(:gitaly_commit) do
- Gitaly::GitCommit.new(
- id: id,
- subject: subject,
- body: body,
- author: author,
- committer: committer,
- parent_ids: parent_ids
- )
- end
+ let(:gitaly_commit) { build(:gitaly_commit, subject: subject, body: body) }
+ let(:id) { gitaly_commit.id }
+ let(:committer) { gitaly_commit.committer }
+ let(:author) { gitaly_commit.author }
let(:commit) { described_class.new(repository, gitaly_commit) }
it { expect(commit.short_id).to eq(id[0..10]) }
@@ -104,7 +82,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
it { expect(commit.author_name).to eq(author.name) }
it { expect(commit.committer_name).to eq(committer.name) }
it { expect(commit.committer_email).to eq(committer.email) }
- it { expect(commit.parent_ids).to eq(parent_ids) }
+ it { expect(commit.parent_ids).to eq(gitaly_commit.parent_ids) }
context 'no body' do
let(:body) { "".force_encoding('ASCII-8BIT') }
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index 3494f0cc98d..ee657101f4c 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -341,8 +341,7 @@ describe Gitlab::Git::DiffCollection, seed_helper: true do
end
context 'when diff is quite large will collapse by default' do
- let(:iterator) { [{ diff: 'a' * (Gitlab::Git::Diff.collapse_limit + 1) }] }
- let(:max_files) { 100 }
+ let(:iterator) { [{ diff: 'a' * 20480 }] }
context 'when no collapse is set' do
let(:expanded) { true }
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index d39b33a0c05..4a7b06003fc 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -31,36 +31,6 @@ EOT
[".gitmodules"]).patches.first
end
- describe 'size limit feature toggles' do
- context 'when the feature gitlab_git_diff_size_limit_increase is enabled' do
- before do
- stub_feature_flags(gitlab_git_diff_size_limit_increase: true)
- end
-
- it 'returns 200 KB for size_limit' do
- expect(described_class.size_limit).to eq(200.kilobytes)
- end
-
- it 'returns 100 KB for collapse_limit' do
- expect(described_class.collapse_limit).to eq(100.kilobytes)
- end
- end
-
- context 'when the feature gitlab_git_diff_size_limit_increase is disabled' do
- before do
- stub_feature_flags(gitlab_git_diff_size_limit_increase: false)
- end
-
- it 'returns 100 KB for size_limit' do
- expect(described_class.size_limit).to eq(100.kilobytes)
- end
-
- it 'returns 10 KB for collapse_limit' do
- expect(described_class.collapse_limit).to eq(10.kilobytes)
- end
- end
- end
-
describe '.new' do
context 'using a Hash' do
context 'with a small diff' do
@@ -77,7 +47,7 @@ EOT
context 'using a diff that is too large' do
it 'prunes the diff' do
- diff = described_class.new(diff: 'a' * (described_class.size_limit + 1))
+ diff = described_class.new(diff: 'a' * 204800)
expect(diff.diff).to be_empty
expect(diff).to be_too_large
@@ -115,8 +85,8 @@ EOT
# The patch total size is 200, with lines between 21 and 54.
# This is a quick-and-dirty way to test this. Ideally, a new patch is
# added to the test repo with a size that falls between the real limits.
- allow(Gitlab::Git::Diff).to receive(:size_limit).and_return(150)
- allow(Gitlab::Git::Diff).to receive(:collapse_limit).and_return(100)
+ stub_const("#{described_class}::SIZE_LIMIT", 150)
+ stub_const("#{described_class}::COLLAPSE_LIMIT", 100)
end
it 'prunes the diff as a large diff instead of as a collapsed diff' do
@@ -356,7 +326,7 @@ EOT
describe '#collapsed?' do
it 'returns true for a diff that is quite large' do
- diff = described_class.new({ diff: 'a' * (described_class.collapse_limit + 1) }, expanded: false)
+ diff = described_class.new({ diff: 'a' * 20480 }, expanded: false)
expect(diff).to be_collapsed
end
diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb
index 0ff4f3bd105..2fe1f5603ce 100644
--- a/spec/lib/gitlab/git/hook_spec.rb
+++ b/spec/lib/gitlab/git/hook_spec.rb
@@ -14,6 +14,7 @@ describe Gitlab::Git::Hook do
let(:repo_path) { repository.path }
let(:user) { create(:user) }
let(:gl_id) { Gitlab::GlId.gl_id(user) }
+ let(:gl_username) { user.username }
def create_hook(name)
FileUtils.mkdir_p(File.join(repo_path, 'hooks'))
@@ -42,6 +43,7 @@ describe Gitlab::Git::Hook do
let(:env) do
{
'GL_ID' => gl_id,
+ 'GL_USERNAME' => gl_username,
'PWD' => repo_path,
'GL_PROTOCOL' => 'web',
'GL_REPOSITORY' => gl_repository
@@ -59,7 +61,7 @@ describe Gitlab::Git::Hook do
.with(env, hook_path, chdir: repo_path).and_call_original
end
- status, errors = hook.trigger(gl_id, blank, blank, ref)
+ status, errors = hook.trigger(gl_id, gl_username, blank, blank, ref)
expect(status).to be true
expect(errors).to be_blank
end
@@ -72,7 +74,7 @@ describe Gitlab::Git::Hook do
blank = Gitlab::Git::BLANK_SHA
ref = Gitlab::Git::BRANCH_REF_PREFIX + 'new_branch'
- status, errors = hook.trigger(gl_id, blank, blank, ref)
+ status, errors = hook.trigger(gl_id, gl_username, blank, blank, ref)
expect(status).to be false
expect(errors).to eq("error message from the hook<br>error message from the hook line 2<br>")
end
@@ -86,7 +88,7 @@ describe Gitlab::Git::Hook do
blank = Gitlab::Git::BLANK_SHA
ref = Gitlab::Git::BRANCH_REF_PREFIX + 'new_branch'
- status, errors = hook.trigger(gl_id, blank, blank, ref)
+ status, errors = hook.trigger(gl_id, gl_username, blank, blank, ref)
expect(status).to be true
expect(errors).to be_nil
end
diff --git a/spec/lib/gitlab/git/hooks_service_spec.rb b/spec/lib/gitlab/git/hooks_service_spec.rb
index d4d75b66659..51e4e3fdad1 100644
--- a/spec/lib/gitlab/git/hooks_service_spec.rb
+++ b/spec/lib/gitlab/git/hooks_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Git::HooksService, seed_helper: true do
- let(:user) { Gitlab::Git::User.new('Jane Doe', 'janedoe@example.com', 'user-456') }
+ let(:user) { Gitlab::Git::User.new('janedoe', 'Jane Doe', 'janedoe@example.com', 'user-456') }
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, 'project-123') }
let(:service) { described_class.new }
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 5effaf2b043..5f12125beb2 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -389,6 +389,40 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe '#has_local_branches?' do
+ shared_examples 'check for local branches' do
+ it { expect(repository.has_local_branches?).to eq(true) }
+
+ context 'mutable' do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') }
+
+ after do
+ ensure_seeds
+ end
+
+ it 'returns false when there are no branches' do
+ # Sanity check
+ expect(repository.has_local_branches?).to eq(true)
+
+ FileUtils.rm_rf(File.join(repository.path, 'packed-refs'))
+ heads_dir = File.join(repository.path, 'refs/heads')
+ FileUtils.rm_rf(heads_dir)
+ FileUtils.mkdir_p(heads_dir)
+
+ expect(repository.has_local_branches?).to eq(false)
+ end
+ end
+ end
+
+ context 'with gitaly' do
+ it_behaves_like 'check for local branches'
+ end
+
+ context 'without gitaly', skip_gitaly_mock: true do
+ it_behaves_like 'check for local branches'
+ end
+ end
+
describe "#delete_branch" do
shared_examples "deleting a branch" do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') }
@@ -1410,6 +1444,51 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe '#rm_branch' do
+ shared_examples "user deleting a branch" do
+ let(:project) { create(:project, :repository) }
+ let(:repository) { project.repository.raw }
+ let(:user) { create(:user) }
+ let(:branch_name) { "to-be-deleted-soon" }
+
+ before do
+ project.team << [user, :developer]
+ repository.create_branch(branch_name)
+ end
+
+ it "removes the branch from the repo" do
+ repository.rm_branch(branch_name, user: user)
+
+ expect(repository.rugged.branches[branch_name]).to be_nil
+ end
+ end
+
+ context "when Gitaly user_delete_branch is enabled" do
+ it_behaves_like "user deleting a branch"
+ end
+
+ context "when Gitaly user_delete_branch is disabled", skip_gitaly_mock: true do
+ it_behaves_like "user deleting a branch"
+ end
+ end
+
+ describe '#write_ref' do
+ context 'validations' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:ref_path, :ref) do
+ 'foo bar' | '123'
+ 'foobar' | "12\x003"
+ end
+
+ with_them do
+ it 'raises ArgumentError' do
+ expect { repository.write_ref(ref_path, ref) }.to raise_error(ArgumentError)
+ end
+ end
+ end
+ end
+
def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
source_branch = repository.branches.find { |branch| branch.name == source_branch_name }
rugged = repository.rugged
diff --git a/spec/lib/gitlab/git/user_spec.rb b/spec/lib/gitlab/git/user_spec.rb
index 0ebcecb26c0..31d5f59a562 100644
--- a/spec/lib/gitlab/git/user_spec.rb
+++ b/spec/lib/gitlab/git/user_spec.rb
@@ -1,22 +1,38 @@
require 'spec_helper'
describe Gitlab::Git::User do
+ let(:username) { 'janedo' }
let(:name) { 'Jane Doe' }
let(:email) { 'janedoe@example.com' }
let(:gl_id) { 'user-123' }
- subject { described_class.new(name, email, gl_id) }
+ subject { described_class.new(username, name, email, gl_id) }
+
+ describe '.from_gitaly' do
+ let(:gitaly_user) { Gitaly::User.new(name: name, email: email, gl_id: gl_id) }
+ subject { described_class.from_gitaly(gitaly_user) }
+
+ it { expect(subject).to eq(described_class.new('', name, email, gl_id)) }
+ end
+
+ describe '.from_gitlab' do
+ let(:user) { build(:user) }
+ subject { described_class.from_gitlab(user) }
+
+ it { expect(subject).to eq(described_class.new(user.username, user.name, user.email, 'user-')) }
+ end
describe '#==' do
- def eq_other(name, email, gl_id)
- eq(described_class.new(name, email, gl_id))
+ def eq_other(username, name, email, gl_id)
+ eq(described_class.new(username, name, email, gl_id))
end
- it { expect(subject).to eq_other(name, email, gl_id) }
+ it { expect(subject).to eq_other(username, name, email, gl_id) }
- it { expect(subject).not_to eq_other(nil, nil, nil) }
- it { expect(subject).not_to eq_other(name + 'x', email, gl_id) }
- it { expect(subject).not_to eq_other(name, email + 'x', gl_id) }
- it { expect(subject).not_to eq_other(name, email, gl_id + 'x') }
+ it { expect(subject).not_to eq_other(nil, nil, nil, nil) }
+ it { expect(subject).not_to eq_other(username + 'x', name, email, gl_id) }
+ it { expect(subject).not_to eq_other(username, name + 'x', email, gl_id) }
+ it { expect(subject).not_to eq_other(username, name, email + 'x', gl_id) }
+ it { expect(subject).not_to eq_other(username, name, email, gl_id + 'x') }
end
end
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index 1ef3e2e3a5d..b2275119a04 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -53,7 +53,7 @@ describe Gitlab::GitalyClient::CommitService do
end
it 'encodes paths correctly' do
- expect { client.diff_from_parent(commit, paths: ['encoding/test.txt', 'encoding/テスト.txt']) }.not_to raise_error
+ expect { client.diff_from_parent(commit, paths: ['encoding/test.txt', 'encoding/テスト.txt', nil]) }.not_to raise_error
end
end
diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
new file mode 100644
index 00000000000..7bd6a7fa842
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
@@ -0,0 +1,92 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::OperationService do
+ let(:project) { create(:project) }
+ let(:repository) { project.repository.raw }
+ let(:client) { described_class.new(repository) }
+ let(:user) { create(:user) }
+ let(:gitaly_user) { Gitlab::GitalyClient::Util.gitaly_user(user) }
+
+ describe '#user_create_branch' do
+ let(:branch_name) { 'new' }
+ let(:start_point) { 'master' }
+ let(:request) do
+ Gitaly::UserCreateBranchRequest.new(
+ repository: repository.gitaly_repository,
+ branch_name: branch_name,
+ start_point: start_point,
+ user: gitaly_user
+ )
+ end
+ let(:gitaly_commit) { build(:gitaly_commit) }
+ let(:commit_id) { gitaly_commit.id }
+ let(:gitaly_branch) do
+ Gitaly::Branch.new(name: branch_name, target_commit: gitaly_commit)
+ end
+ let(:response) { Gitaly::UserCreateBranchResponse.new(branch: gitaly_branch) }
+ let(:commit) { Gitlab::Git::Commit.new(repository, gitaly_commit) }
+
+ subject { client.user_create_branch(branch_name, user, start_point) }
+
+ it 'sends a user_create_branch message and returns a Gitlab::git::Branch' do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_create_branch).with(request, kind_of(Hash))
+ .and_return(response)
+
+ expect(subject.name).to eq(branch_name)
+ expect(subject.dereferenced_target).to eq(commit)
+ end
+
+ context "when pre_receive_error is present" do
+ let(:response) do
+ Gitaly::UserCreateBranchResponse.new(pre_receive_error: "something failed")
+ end
+
+ it "throws a PreReceive exception" do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_create_branch).with(request, kind_of(Hash))
+ .and_return(response)
+
+ expect { subject }.to raise_error(
+ Gitlab::Git::HooksService::PreReceiveError, "something failed")
+ end
+ end
+ end
+
+ describe '#user_delete_branch' do
+ let(:branch_name) { 'my-branch' }
+ let(:request) do
+ Gitaly::UserDeleteBranchRequest.new(
+ repository: repository.gitaly_repository,
+ branch_name: branch_name,
+ user: gitaly_user
+ )
+ end
+ let(:response) { Gitaly::UserDeleteBranchResponse.new }
+
+ subject { client.user_delete_branch(branch_name, user) }
+
+ it 'sends a user_delete_branch message' do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_delete_branch).with(request, kind_of(Hash))
+ .and_return(response)
+
+ subject
+ end
+
+ context "when pre_receive_error is present" do
+ let(:response) do
+ Gitaly::UserDeleteBranchResponse.new(pre_receive_error: "something failed")
+ end
+
+ it "throws a PreReceive exception" do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_delete_branch).with(request, kind_of(Hash))
+ .and_return(response)
+
+ expect { subject }.to raise_error(
+ Gitlab::Git::HooksService::PreReceiveError, "something failed")
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client/util_spec.rb b/spec/lib/gitlab/gitaly_client/util_spec.rb
new file mode 100644
index 00000000000..498f6886bee
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/util_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::Util do
+ describe '.repository' do
+ let(:repository_storage) { 'default' }
+ let(:relative_path) { 'my/repo.git' }
+ let(:gl_repository) { 'project-1' }
+ let(:git_object_directory) { '.git/objects' }
+ let(:git_alternate_object_directory) { '/dir/one:/dir/two' }
+
+ subject do
+ described_class.repository(repository_storage, relative_path, gl_repository)
+ end
+
+ it 'creates a Gitaly::Repository with the given data' do
+ expect(Gitlab::Git::Env).to receive(:[]).with('GIT_OBJECT_DIRECTORY')
+ .and_return(git_object_directory)
+ expect(Gitlab::Git::Env).to receive(:[]).with('GIT_ALTERNATE_OBJECT_DIRECTORIES')
+ .and_return(git_alternate_object_directory)
+
+ expect(subject).to be_a(Gitaly::Repository)
+ expect(subject.storage_name).to eq(repository_storage)
+ expect(subject.relative_path).to eq(relative_path)
+ expect(subject.gl_repository).to eq(gl_repository)
+ expect(subject.git_object_directory).to eq(git_object_directory)
+ expect(subject.git_alternate_object_directories).to eq([git_alternate_object_directory])
+ end
+ end
+
+ describe '.gitaly_user' do
+ let(:user) { create(:user) }
+ let(:gl_id) { Gitlab::GlId.gl_id(user) }
+
+ subject { described_class.gitaly_user(user) }
+
+ it 'creates a Gitaly::User from a GitLab user' do
+ expect(subject).to be_a(Gitaly::User)
+ expect(subject.name).to eq(user.name)
+ expect(subject.email).to eq(user.email)
+ expect(subject.gl_id).to eq(gl_id)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 9a84d6e6a67..a1f4e65b8d4 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -38,6 +38,20 @@ describe Gitlab::GitalyClient, skip_gitaly_mock: true do
end
end
+ describe 'encode' do
+ [
+ [nil, ""],
+ ["", ""],
+ [" ", " "],
+ %w(a1 a1),
+ ["ç¼–ç ", "\xE7\xBC\x96\xE7\xA0\x81".b]
+ ].each do |input, result|
+ it "encodes #{input.inspect} to #{result.inspect}" do
+ expect(described_class.encode(input)).to eq result
+ end
+ end
+ end
+
describe 'allow_n_plus_1_calls' do
context 'when RequestStore is enabled', :request_store do
it 'returns the result of the allow_n_plus_1_calls block' do
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 899d17d97c2..7268226112c 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -412,6 +412,8 @@ Project:
- last_repository_updated_at
- ci_config_path
- delete_error
+- merge_requests_ff_only_enabled
+- merge_requests_rebase_enabled
Author:
- name
ProjectFeature:
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 8aaf320cbf5..db26e16e3b2 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -4,6 +4,7 @@ describe Gitlab::OAuth::User do
let(:oauth_user) { described_class.new(auth_hash) }
let(:gl_user) { oauth_user.gl_user }
let(:uid) { 'my-uid' }
+ let(:dn) { 'uid=user1,ou=People,dc=example' }
let(:provider) { 'my-provider' }
let(:auth_hash) { OmniAuth::AuthHash.new(uid: uid, provider: provider, info: info_hash) }
let(:info_hash) do
@@ -197,7 +198,7 @@ describe Gitlab::OAuth::User do
allow(ldap_user).to receive(:uid) { uid }
allow(ldap_user).to receive(:username) { uid }
allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] }
- allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' }
+ allow(ldap_user).to receive(:dn) { dn }
end
context "and no account for the LDAP user" do
@@ -213,7 +214,7 @@ describe Gitlab::OAuth::User do
identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
expect(identities_as_hash).to match_array(
[
- { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ { provider: 'ldapmain', extern_uid: dn },
{ provider: 'twitter', extern_uid: uid }
]
)
@@ -221,7 +222,7 @@ describe Gitlab::OAuth::User do
end
context "and LDAP user has an account already" do
- let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'ldapmain', username: 'john') }
+ let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: dn, provider: 'ldapmain', username: 'john') }
it "adds the omniauth identity to the LDAP account" do
allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
@@ -234,7 +235,7 @@ describe Gitlab::OAuth::User do
identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
expect(identities_as_hash).to match_array(
[
- { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ { provider: 'ldapmain', extern_uid: dn },
{ provider: 'twitter', extern_uid: uid }
]
)
@@ -252,7 +253,7 @@ describe Gitlab::OAuth::User do
expect(identities_as_hash)
.to match_array(
[
- { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ { provider: 'ldapmain', extern_uid: dn },
{ provider: 'twitter', extern_uid: uid }
]
)
@@ -310,8 +311,8 @@ describe Gitlab::OAuth::User do
allow(ldap_user).to receive(:uid) { uid }
allow(ldap_user).to receive(:username) { uid }
allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] }
- allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' }
- allow(oauth_user).to receive(:ldap_person).and_return(ldap_user)
+ allow(ldap_user).to receive(:dn) { dn }
+ allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
end
context "and no account for the LDAP user" do
@@ -341,7 +342,7 @@ describe Gitlab::OAuth::User do
end
context 'and LDAP user has an account already' do
- let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'ldapmain', username: 'john') }
+ let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: dn, provider: 'ldapmain', username: 'john') }
context 'dont block on create (LDAP)' do
before do
diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb
index 2f989397f7e..1f1c48ee9b5 100644
--- a/spec/lib/gitlab/path_regex_spec.rb
+++ b/spec/lib/gitlab/path_regex_spec.rb
@@ -84,9 +84,9 @@ describe Gitlab::PathRegex do
let(:top_level_words) do
words = routes_not_starting_in_wildcard.map do |route|
route.split('/')[1]
- end.compact.uniq
+ end.compact
- words + ee_top_level_words + files_in_public + Array(API::API.prefix.to_s)
+ (words + ee_top_level_words + files_in_public + Array(API::API.prefix.to_s)).uniq
end
let(:ee_top_level_words) do
@@ -95,10 +95,11 @@ describe Gitlab::PathRegex do
let(:files_in_public) do
git = Gitlab.config.git.bin_path
- `cd #{Rails.root} && #{git} ls-files public`
+ tracked = `cd #{Rails.root} && #{git} ls-files public`
.split("\n")
.map { |entry| entry.gsub('public/', '') }
.uniq
+ tracked + %w(assets uploads)
end
# All routes that start with a namespaced path, that have 1 or more
diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb
index 4567f220c11..b145ca36f26 100644
--- a/spec/lib/gitlab/popen_spec.rb
+++ b/spec/lib/gitlab/popen_spec.rb
@@ -14,7 +14,7 @@ describe 'Gitlab::Popen' do
end
it { expect(@status).to be_zero }
- it { expect(@output).to include('cache') }
+ it { expect(@output).to include('tests') }
end
context 'non-zero status' do
diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb
index 19710029224..59923bfb14d 100644
--- a/spec/lib/gitlab/saml/user_spec.rb
+++ b/spec/lib/gitlab/saml/user_spec.rb
@@ -1,9 +1,12 @@
require 'spec_helper'
describe Gitlab::Saml::User do
+ include LdapHelpers
+
let(:saml_user) { described_class.new(auth_hash) }
let(:gl_user) { saml_user.gl_user }
let(:uid) { 'my-uid' }
+ let(:dn) { 'uid=user1,ou=People,dc=example' }
let(:provider) { 'saml' }
let(:auth_hash) { OmniAuth::AuthHash.new(uid: uid, provider: provider, info: info_hash, extra: { raw_info: OneLogin::RubySaml::Attributes.new({ 'groups' => %w(Developers Freelancers Designers) }) }) }
let(:info_hash) do
@@ -163,13 +166,17 @@ describe Gitlab::Saml::User do
end
context 'and a corresponding LDAP person' do
+ let(:adapter) { ldap_adapter('ldapmain') }
+
before do
allow(ldap_user).to receive(:uid) { uid }
allow(ldap_user).to receive(:username) { uid }
allow(ldap_user).to receive(:email) { %w(john@mail.com john2@example.com) }
- allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' }
- allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
- allow(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(ldap_user)
+ allow(ldap_user).to receive(:dn) { dn }
+ allow(Gitlab::LDAP::Adapter).to receive(:new).and_return(adapter)
+ allow(Gitlab::LDAP::Person).to receive(:find_by_uid).with(uid, adapter).and_return(ldap_user)
+ allow(Gitlab::LDAP::Person).to receive(:find_by_dn).with(dn, adapter).and_return(ldap_user)
+ allow(Gitlab::LDAP::Person).to receive(:find_by_email).with('john@mail.com', adapter).and_return(ldap_user)
end
context 'and no account for the LDAP user' do
@@ -181,20 +188,86 @@ describe Gitlab::Saml::User do
expect(gl_user.email).to eql 'john@mail.com'
expect(gl_user.identities.length).to be 2
identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
- expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: dn },
{ provider: 'saml', extern_uid: uid }])
end
end
context 'and LDAP user has an account already' do
+ let(:auth_hash_base_attributes) do
+ {
+ uid: uid,
+ provider: provider,
+ info: info_hash,
+ extra: {
+ raw_info: OneLogin::RubySaml::Attributes.new(
+ { 'groups' => %w(Developers Freelancers Designers) }
+ )
+ }
+ }
+ end
+ let(:auth_hash) { OmniAuth::AuthHash.new(auth_hash_base_attributes) }
+ let(:uid_types) { %w(uid dn email) }
+
before do
create(:omniauth_user,
email: 'john@mail.com',
- extern_uid: 'uid=user1,ou=People,dc=example',
+ extern_uid: dn,
provider: 'ldapmain',
username: 'john')
end
+ shared_examples 'find LDAP person' do |uid_type, uid|
+ let(:auth_hash) { OmniAuth::AuthHash.new(auth_hash_base_attributes.merge(uid: extern_uid)) }
+
+ before do
+ nil_types = uid_types - [uid_type]
+
+ nil_types.each do |type|
+ allow(Gitlab::LDAP::Person).to receive(:"find_by_#{type}").and_return(nil)
+ end
+
+ allow(Gitlab::LDAP::Person).to receive(:"find_by_#{uid_type}").and_return(ldap_user)
+ end
+
+ it 'adds the omniauth identity to the LDAP account' do
+ identities = [
+ { provider: 'ldapmain', extern_uid: dn },
+ { provider: 'saml', extern_uid: extern_uid }
+ ]
+
+ identities_as_hash = gl_user.identities.map do |id|
+ { provider: id.provider, extern_uid: id.extern_uid }
+ end
+
+ saml_user.save
+
+ expect(gl_user).to be_valid
+ expect(gl_user.username).to eql 'john'
+ expect(gl_user.email).to eql 'john@mail.com'
+ expect(gl_user.identities.length).to be 2
+ expect(identities_as_hash).to match_array(identities)
+ end
+ end
+
+ context 'when uid is an uid' do
+ it_behaves_like 'find LDAP person', 'uid' do
+ let(:extern_uid) { uid }
+ end
+ end
+
+ context 'when uid is a dn' do
+ it_behaves_like 'find LDAP person', 'dn' do
+ let(:extern_uid) { dn }
+ end
+ end
+
+ context 'when uid is an email' do
+ it_behaves_like 'find LDAP person', 'email' do
+ let(:extern_uid) { 'john@mail.com' }
+ end
+ end
+
it 'adds the omniauth identity to the LDAP account' do
saml_user.save
@@ -203,7 +276,7 @@ describe Gitlab::Saml::User do
expect(gl_user.email).to eql 'john@mail.com'
expect(gl_user.identities.length).to be 2
identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
- expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: dn },
{ provider: 'saml', extern_uid: uid }])
end
@@ -219,17 +292,21 @@ describe Gitlab::Saml::User do
context 'user has SAML user, and wants to add their LDAP identity' do
it 'adds the LDAP identity to the existing SAML user' do
- create(:omniauth_user, email: 'john@mail.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'saml', username: 'john')
- local_hash = OmniAuth::AuthHash.new(uid: 'uid=user1,ou=People,dc=example', provider: provider, info: info_hash)
+ create(:omniauth_user, email: 'john@mail.com', extern_uid: dn, provider: 'saml', username: 'john')
+
+ allow(Gitlab::LDAP::Person).to receive(:find_by_uid).with(dn, adapter).and_return(ldap_user)
+
+ local_hash = OmniAuth::AuthHash.new(uid: dn, provider: provider, info: info_hash)
local_saml_user = described_class.new(local_hash)
+
local_saml_user.save
local_gl_user = local_saml_user.gl_user
expect(local_gl_user).to be_valid
expect(local_gl_user.identities.length).to be 2
identities_as_hash = local_gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
- expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
- { provider: 'saml', extern_uid: 'uid=user1,ou=People,dc=example' }])
+ expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: dn },
+ { provider: 'saml', extern_uid: dn }])
end
end
end
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 8edf83864da..9efdd7940ca 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -126,30 +126,42 @@ describe Gitlab::Shell do
end
describe '#add_repository' do
- it 'creates a repository' do
- created_path = File.join(TestEnv.repos_path, 'project', 'path.git')
- hooks_path = File.join(created_path, 'hooks')
+ shared_examples '#add_repository' do
+ let(:repository_storage) { 'default' }
+ let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
+ let(:repo_name) { 'project/path' }
+ let(:created_path) { File.join(repository_storage_path, repo_name + '.git') }
- begin
- result = gitlab_shell.add_repository(TestEnv.repos_path, 'project/path')
-
- repo_stat = File.stat(created_path) rescue nil
- hooks_stat = File.lstat(hooks_path) rescue nil
- hooks_dir = File.realpath(hooks_path)
- ensure
+ after do
FileUtils.rm_rf(created_path)
end
- expect(result).to be_truthy
- expect(repo_stat.mode & 0o777).to eq(0o770)
- expect(hooks_stat.symlink?).to be_truthy
- expect(hooks_dir).to eq(gitlab_shell_hooks_path)
+ it 'creates a repository' do
+ expect(gitlab_shell.add_repository(repository_storage, repo_name)).to be_truthy
+
+ expect(File.stat(created_path).mode & 0o777).to eq(0o770)
+
+ hooks_path = File.join(created_path, 'hooks')
+ expect(File.lstat(hooks_path)).to be_symlink
+ expect(File.realpath(hooks_path)).to eq(gitlab_shell_hooks_path)
+ end
+
+ it 'returns false when the command fails' do
+ FileUtils.mkdir_p(File.dirname(created_path))
+ # This file will block the creation of the repo's .git directory. That
+ # should cause #add_repository to fail.
+ FileUtils.touch(created_path)
+
+ expect(gitlab_shell.add_repository(repository_storage, repo_name)).to be_falsy
+ end
end
- it 'returns false when the command fails' do
- expect(FileUtils).to receive(:mkdir_p).and_raise(Errno::EEXIST)
+ context 'with gitaly' do
+ it_behaves_like '#add_repository'
+ end
- expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be_falsy
+ context 'without gitaly', skip_gitaly_mock: true do
+ it_behaves_like '#add_repository'
end
end
diff --git a/spec/lib/gitlab/sql/union_spec.rb b/spec/lib/gitlab/sql/union_spec.rb
index baf8f6644bf..8026fba9f0a 100644
--- a/spec/lib/gitlab/sql/union_spec.rb
+++ b/spec/lib/gitlab/sql/union_spec.rb
@@ -22,5 +22,12 @@ describe Gitlab::SQL::Union do
expect {User.where("users.id IN (#{union.to_sql})").to_a}.not_to raise_error
expect(union.to_sql).to eq("#{to_sql(relation_1)}\nUNION\n#{to_sql(relation_2)}")
end
+
+ it 'uses UNION ALL when removing duplicates is disabled' do
+ union = described_class
+ .new([relation_1, relation_2], remove_duplicates: false)
+
+ expect(union.to_sql).to include('UNION ALL')
+ end
end
end
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
index 59c28431e1e..fc8991fd31f 100644
--- a/spec/lib/gitlab/url_sanitizer_spec.rb
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -39,7 +39,8 @@ describe Gitlab::UrlSanitizer do
false | nil
false | ''
false | '123://invalid:url'
- true | 'valid@project:url.git'
+ false | 'valid@project:url.git'
+ false | 'valid:pass@project:url.git'
true | 'ssh://example.com'
true | 'ssh://:@example.com'
true | 'ssh://foo@example.com'
@@ -81,24 +82,6 @@ describe Gitlab::UrlSanitizer do
describe '#credentials' do
context 'credentials in hash' do
- where(:input, :output) do
- { user: 'foo', password: 'bar' } | { user: 'foo', password: 'bar' }
- { user: 'foo', password: '' } | { user: 'foo', password: nil }
- { user: 'foo', password: nil } | { user: 'foo', password: nil }
- { user: '', password: 'bar' } | { user: nil, password: 'bar' }
- { user: '', password: '' } | { user: nil, password: nil }
- { user: '', password: nil } | { user: nil, password: nil }
- { user: nil, password: 'bar' } | { user: nil, password: 'bar' }
- { user: nil, password: '' } | { user: nil, password: nil }
- { user: nil, password: nil } | { user: nil, password: nil }
- end
-
- with_them do
- subject { described_class.new('user@example.com:path.git', credentials: input).credentials }
-
- it { is_expected.to eq(output) }
- end
-
it 'overrides URL-provided credentials' do
sanitizer = described_class.new('http://a:b@example.com', credentials: { user: 'c', password: 'd' })
@@ -116,10 +99,6 @@ describe Gitlab::UrlSanitizer do
'http://@example.com' | { user: nil, password: nil }
'http://example.com' | { user: nil, password: nil }
- # Credentials from SCP-style URLs are not supported at present
- 'foo@example.com:path' | { user: nil, password: nil }
- 'foo:bar@example.com:path' | { user: nil, password: nil }
-
# Other invalid URLs
nil | { user: nil, password: nil }
'' | { user: nil, password: nil }
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 699184ad9fe..4dffe2bd82f 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -13,13 +13,51 @@ describe Gitlab::Workhorse do
end
describe ".send_git_archive" do
+ let(:ref) { 'master' }
+ let(:format) { 'zip' }
+ let(:storage_path) { Gitlab.config.gitlab.repository_downloads_path }
+ let(:base_params) { repository.archive_metadata(ref, storage_path, format) }
+ let(:gitaly_params) do
+ base_params.merge(
+ 'GitalyServer' => {
+ 'address' => Gitlab::GitalyClient.address(project.repository_storage),
+ 'token' => Gitlab::GitalyClient.token(project.repository_storage)
+ },
+ 'GitalyRepository' => repository.gitaly_repository.to_h.deep_stringify_keys
+ )
+ end
+
+ subject do
+ described_class.send_git_archive(repository, ref: ref, format: format)
+ end
+
+ context 'when Gitaly workhorse_archive feature is enabled' do
+ it 'sets the header correctly' do
+ key, command, params = decode_workhorse_header(subject)
+
+ expect(key).to eq('Gitlab-Workhorse-Send-Data')
+ expect(command).to eq('git-archive')
+ expect(params).to include(gitaly_params)
+ end
+ end
+
+ context 'when Gitaly workhorse_archive feature is disabled', skip_gitaly_mock: true do
+ it 'sets the header correctly' do
+ key, command, params = decode_workhorse_header(subject)
+
+ expect(key).to eq('Gitlab-Workhorse-Send-Data')
+ expect(command).to eq('git-archive')
+ expect(params).to eq(base_params)
+ end
+ end
+
context "when the repository doesn't have an archive file path" do
before do
allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
end
it "raises an error" do
- expect { described_class.send_git_archive(project.repository, ref: "master", format: "zip") }.to raise_error(RuntimeError)
+ expect { subject }.to raise_error(RuntimeError)
end
end
end
@@ -182,7 +220,12 @@ describe Gitlab::Workhorse do
let(:repo_path) { repository.path_to_repo }
let(:action) { 'info_refs' }
let(:params) do
- { GL_ID: "user-#{user.id}", GL_REPOSITORY: "project-#{project.id}", RepoPath: repo_path }
+ {
+ GL_ID: "user-#{user.id}",
+ GL_USERNAME: user.username,
+ GL_REPOSITORY: "project-#{project.id}",
+ RepoPath: repo_path
+ }
end
subject { described_class.git_http_ok(repository, false, user, action) }
@@ -191,7 +234,12 @@ describe Gitlab::Workhorse do
context 'when is_wiki' do
let(:params) do
- { GL_ID: "user-#{user.id}", GL_REPOSITORY: "wiki-#{project.id}", RepoPath: repo_path }
+ {
+ GL_ID: "user-#{user.id}",
+ GL_USERNAME: user.username,
+ GL_REPOSITORY: "wiki-#{project.id}",
+ RepoPath: repo_path
+ }
end
subject { described_class.git_http_ok(repository, true, user, action) }
@@ -214,14 +262,13 @@ describe Gitlab::Workhorse do
end
it 'includes a Repository param' do
- repo_param = { Repository: {
+ repo_param = {
storage_name: 'default',
relative_path: project.full_path + '.git',
- git_object_directory: '',
- git_alternate_object_directories: []
- } }
+ gl_repository: "project-#{project.id}"
+ }
- expect(subject).to include(repo_param)
+ expect(subject[:Repository]).to include(repo_param)
end
context "when git_upload_pack action is passed" do
diff --git a/spec/lib/system_check/app/git_user_default_ssh_config_check_spec.rb b/spec/lib/system_check/app/git_user_default_ssh_config_check_spec.rb
index 7125bfcab59..a0fb86345f3 100644
--- a/spec/lib/system_check/app/git_user_default_ssh_config_check_spec.rb
+++ b/spec/lib/system_check/app/git_user_default_ssh_config_check_spec.rb
@@ -16,7 +16,12 @@ describe SystemCheck::App::GitUserDefaultSSHConfigCheck do
end
it 'only whitelists safe files' do
- expect(described_class::WHITELIST).to contain_exactly('authorized_keys', 'authorized_keys2', 'known_hosts')
+ expect(described_class::WHITELIST).to contain_exactly(
+ 'authorized_keys',
+ 'authorized_keys2',
+ 'authorized_keys.lock',
+ 'known_hosts'
+ )
end
describe '#skip?' do
diff --git a/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb b/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb
new file mode 100644
index 00000000000..4ab1bb67058
--- /dev/null
+++ b/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb
@@ -0,0 +1,59 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170926150348_schedule_merge_request_diff_migrations_take_two')
+
+describe ScheduleMergeRequestDiffMigrationsTakeTwo, :migration, :sidekiq do
+ matcher :be_scheduled_migration do |time, *expected|
+ match do |migration|
+ BackgroundMigrationWorker.jobs.any? do |job|
+ job['args'] == [migration, expected] &&
+ job['at'].to_i == time.to_i
+ end
+ end
+
+ failure_message do |migration|
+ "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!"
+ end
+ end
+
+ let(:merge_request_diffs) { table(:merge_request_diffs) }
+ let(:merge_requests) { table(:merge_requests) }
+ let(:projects) { table(:projects) }
+
+ before do
+ stub_const("#{described_class.name}::BATCH_SIZE", 1)
+
+ projects.create!(id: 1, name: 'gitlab', path: 'gitlab')
+
+ merge_requests.create!(id: 1, target_project_id: 1, source_project_id: 1, target_branch: 'feature', source_branch: 'master')
+
+ merge_request_diffs.create!(id: 1, merge_request_id: 1, st_commits: YAML.dump([]), st_diffs: nil)
+ merge_request_diffs.create!(id: 2, merge_request_id: 1, st_commits: nil, st_diffs: YAML.dump([]))
+ merge_request_diffs.create!(id: 3, merge_request_id: 1, st_commits: nil, st_diffs: nil)
+ merge_request_diffs.create!(id: 4, merge_request_id: 1, st_commits: YAML.dump([]), st_diffs: YAML.dump([]))
+ end
+
+ it 'correctly schedules background migrations' do
+ Sidekiq::Testing.fake! do
+ Timecop.freeze do
+ migrate!
+
+ expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes.from_now, 1, 1)
+ expect(described_class::MIGRATION).to be_scheduled_migration(20.minutes.from_now, 2, 2)
+ expect(described_class::MIGRATION).to be_scheduled_migration(30.minutes.from_now, 4, 4)
+ expect(BackgroundMigrationWorker.jobs.size).to eq 3
+ end
+ end
+ end
+
+ it 'migrates the data' do
+ Sidekiq::Testing.inline! do
+ non_empty = 'st_commits IS NOT NULL OR st_diffs IS NOT NULL'
+
+ expect(merge_request_diffs.where(non_empty).count).to eq 3
+
+ migrate!
+
+ expect(merge_request_diffs.where(non_empty).count).to eq 0
+ end
+ end
+end
diff --git a/spec/migrations/update_legacy_diff_notes_type_for_import_spec.rb b/spec/migrations/update_legacy_diff_notes_type_for_import_spec.rb
new file mode 100644
index 00000000000..d625b60ff50
--- /dev/null
+++ b/spec/migrations/update_legacy_diff_notes_type_for_import_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170927112318_update_legacy_diff_notes_type_for_import.rb')
+
+describe UpdateLegacyDiffNotesTypeForImport, :migration do
+ let(:notes) { table(:notes) }
+
+ before do
+ notes.inheritance_column = nil
+
+ notes.create(type: 'Note')
+ notes.create(type: 'LegacyDiffNote')
+ notes.create(type: 'Github::Import::Note')
+ notes.create(type: 'Github::Import::LegacyDiffNote')
+ end
+
+ it 'updates the notes type' do
+ migrate!
+
+ expect(notes.pluck(:type))
+ .to contain_exactly('Note', 'Github::Import::Note', 'LegacyDiffNote', 'LegacyDiffNote')
+ end
+end
diff --git a/spec/migrations/update_notes_type_for_import_spec.rb b/spec/migrations/update_notes_type_for_import_spec.rb
new file mode 100644
index 00000000000..06195d970d8
--- /dev/null
+++ b/spec/migrations/update_notes_type_for_import_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170927112319_update_notes_type_for_import.rb')
+
+describe UpdateNotesTypeForImport, :migration do
+ let(:notes) { table(:notes) }
+
+ before do
+ notes.inheritance_column = nil
+
+ notes.create(type: 'Note')
+ notes.create(type: 'LegacyDiffNote')
+ notes.create(type: 'Github::Import::Note')
+ notes.create(type: 'Github::Import::LegacyDiffNote')
+ end
+
+ it 'updates the notes type' do
+ migrate!
+
+ expect(notes.pluck(:type))
+ .to contain_exactly('Note', 'Note', 'LegacyDiffNote', 'Github::Import::LegacyDiffNote')
+ end
+end
diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb
index fadc8bfeb61..4a4d079b721 100644
--- a/spec/models/gpg_key_spec.rb
+++ b/spec/models/gpg_key_spec.rb
@@ -138,6 +138,14 @@ describe GpgKey do
expect(gpg_key.verified?).to be_truthy
expect(gpg_key.verified_and_belongs_to_email?('bette.cartwright@example.com')).to be_truthy
end
+
+ it 'returns true if one of the email addresses in the key belongs to the user and case-insensitively matches the provided email' do
+ user = create :user, email: 'bette.cartwright@example.com'
+ gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user
+
+ expect(gpg_key.verified?).to be_truthy
+ expect(gpg_key.verified_and_belongs_to_email?('Bette.Cartwright@example.com')).to be_truthy
+ end
end
describe '#revoke' do
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index 8eabc4ca72f..81c2057e175 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -155,5 +155,15 @@ describe Key, :mailer do
it 'strips white spaces' do
expect(described_class.new(key: " #{valid_key} ").key).to eq(valid_key)
end
+
+ it 'invalidates the public_key attribute' do
+ key = build(:key)
+
+ original = key.public_key
+ key.key = valid_key
+
+ expect(original.key_text).not_to be_nil
+ expect(key.public_key.key_text).to eq(valid_key)
+ end
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index d80d5657c42..188a0a98ec3 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -791,6 +791,49 @@ describe MergeRequest do
end
end
+ describe '#has_ci?' do
+ let(:merge_request) { build_stubbed(:merge_request) }
+
+ context 'has ci' do
+ it 'returns true if MR has head_pipeline_id and commits' do
+ allow(merge_request).to receive_message_chain(:source_project, :ci_service) { nil }
+ allow(merge_request).to receive(:head_pipeline_id) { double }
+ allow(merge_request).to receive(:has_no_commits?) { false }
+
+ expect(merge_request.has_ci?).to be(true)
+ end
+
+ it 'returns true if MR has any pipeline and commits' do
+ allow(merge_request).to receive_message_chain(:source_project, :ci_service) { nil }
+ allow(merge_request).to receive(:head_pipeline_id) { nil }
+ allow(merge_request).to receive(:has_no_commits?) { false }
+ allow(merge_request).to receive(:all_pipelines) { [double] }
+
+ expect(merge_request.has_ci?).to be(true)
+ end
+
+ it 'returns true if MR has CI service and commits' do
+ allow(merge_request).to receive_message_chain(:source_project, :ci_service) { double }
+ allow(merge_request).to receive(:head_pipeline_id) { nil }
+ allow(merge_request).to receive(:has_no_commits?) { false }
+ allow(merge_request).to receive(:all_pipelines) { [] }
+
+ expect(merge_request.has_ci?).to be(true)
+ end
+ end
+
+ context 'has no ci' do
+ it 'returns false if MR has no CI service nor pipeline, and no commits' do
+ allow(merge_request).to receive_message_chain(:source_project, :ci_service) { nil }
+ allow(merge_request).to receive(:head_pipeline_id) { nil }
+ allow(merge_request).to receive(:all_pipelines) { [] }
+ allow(merge_request).to receive(:has_no_commits?) { true }
+
+ expect(merge_request.has_ci?).to be(false)
+ end
+ end
+ end
+
describe '#all_pipelines' do
shared_examples 'returning pipelines with proper ordering' do
let!(:all_pipelines) do
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index 537cdadd528..2298dcab55f 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -208,7 +208,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
config.dig('users', 0, 'user')['token'] = 'token'
config.dig('contexts', 0, 'context')['namespace'] = namespace
config.dig('clusters', 0, 'cluster')['certificate-authority-data'] =
- Base64.encode64('CA PEM DATA')
+ Base64.strict_encode64('CA PEM DATA')
YAML.dump(config)
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 3ca88071ced..176bb568cbe 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -408,6 +408,18 @@ describe Project do
end
end
+ describe '#merge_method' do
+ it 'returns "ff" merge_method when ff is enabled' do
+ project = build(:project, merge_requests_ff_only_enabled: true)
+ expect(project.merge_method).to be :ff
+ end
+
+ it 'returns "merge" merge_method when ff is disabled' do
+ project = build(:project, merge_requests_ff_only_enabled: false)
+ expect(project.merge_method).to be :merge
+ end
+ end
+
describe '#repository_storage_path' do
let(:project) { create(:project, repository_storage: 'custom') }
@@ -1303,7 +1315,7 @@ describe Project do
context 'using a regular repository' do
it 'creates the repository' do
expect(shell).to receive(:add_repository)
- .with(project.repository_storage_path, project.disk_path)
+ .with(project.repository_storage, project.disk_path)
.and_return(true)
expect(project.repository).to receive(:after_create)
@@ -1313,7 +1325,7 @@ describe Project do
it 'adds an error if the repository could not be created' do
expect(shell).to receive(:add_repository)
- .with(project.repository_storage_path, project.disk_path)
+ .with(project.repository_storage, project.disk_path)
.and_return(false)
expect(project.repository).not_to receive(:after_create)
@@ -1370,7 +1382,7 @@ describe Project do
.and_return(false)
expect(shell).to receive(:add_repository)
- .with(project.repository_storage_path, project.disk_path)
+ .with(project.repository_storage, project.disk_path)
.and_return(true)
project.ensure_repository
@@ -2793,6 +2805,17 @@ describe Project do
end
end
+ describe '#check_repository_path_availability' do
+ let(:project) { build(:project) }
+
+ it 'skips gitlab-shell exists?' do
+ project.skip_disk_validation = true
+
+ expect(project.gitlab_shell).not_to receive(:exists?)
+ expect(project.check_repository_path_availability).to be_truthy
+ end
+ end
+
describe '#latest_successful_pipeline_for_default_branch' do
let(:project) { build(:project) }
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 953df7746eb..78fb2df884a 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -6,13 +6,10 @@ describe ProjectWiki do
let(:user) { project.owner }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project_wiki) { described_class.new(project, user) }
+ let(:raw_repository) { Gitlab::Git::Repository.new(project.repository_storage, subject.disk_path + '.git', 'foo') }
subject { project_wiki }
- before do
- project_wiki.wiki
- end
-
describe "#path_with_namespace" do
it "returns the project path with namespace with the .wiki extension" do
expect(subject.path_with_namespace).to eq(project.full_path + '.wiki')
@@ -61,8 +58,8 @@ describe ProjectWiki do
end
describe "#wiki" do
- it "contains a Gollum::Wiki instance" do
- expect(subject.wiki).to be_a Gollum::Wiki
+ it "contains a Gitlab::Git::Wiki instance" do
+ expect(subject.wiki).to be_a Gitlab::Git::Wiki
end
it "creates a new wiki repo if one does not yet exist" do
@@ -70,20 +67,18 @@ describe ProjectWiki do
end
it "raises CouldNotCreateWikiError if it can't create the wiki repository" do
- allow(project_wiki).to receive(:init_repo).and_return(false)
- expect { project_wiki.send(:create_repo!) }.to raise_exception(ProjectWiki::CouldNotCreateWikiError)
+ # Create a fresh project which will not have a wiki
+ project_wiki = described_class.new(create(:project), user)
+ gitlab_shell = double(:gitlab_shell)
+ allow(gitlab_shell).to receive(:add_repository)
+ allow(project_wiki).to receive(:gitlab_shell).and_return(gitlab_shell)
+
+ expect { project_wiki.send(:wiki) }.to raise_exception(ProjectWiki::CouldNotCreateWikiError)
end
end
describe "#empty?" do
context "when the wiki repository is empty" do
- before do
- allow_any_instance_of(Gitlab::Shell).to receive(:add_repository) do
- create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git")
- end
- allow(project).to receive(:full_path).and_return("non-existant")
- end
-
describe '#empty?' do
subject { super().empty? }
it { is_expected.to be_truthy }
@@ -154,13 +149,13 @@ describe ProjectWiki do
before do
file = Gollum::File.new(subject.wiki)
allow_any_instance_of(Gollum::Wiki)
- .to receive(:file).with('image.jpg', 'master', true)
+ .to receive(:file).with('image.jpg', 'master')
.and_return(file)
allow_any_instance_of(Gollum::File)
.to receive(:mime_type)
.and_return('image/jpeg')
allow_any_instance_of(Gollum::Wiki)
- .to receive(:file).with('non-existant', 'master', true)
+ .to receive(:file).with('non-existant', 'master')
.and_return(nil)
end
@@ -178,9 +173,9 @@ describe ProjectWiki do
expect(subject.find_file('non-existant')).to eq(nil)
end
- it 'returns a Gollum::File instance' do
+ it 'returns a Gitlab::Git::WikiFile instance' do
file = subject.find_file('image.jpg')
- expect(file).to be_a Gollum::File
+ expect(file).to be_a Gitlab::Git::WikiFile
end
end
@@ -222,9 +217,9 @@ describe ProjectWiki do
describe "#update_page" do
before do
create_page("update-page", "some content")
- @gollum_page = subject.wiki.paged("update-page")
+ @gitlab_git_wiki_page = subject.wiki.page(title: "update-page")
subject.update_page(
- @gollum_page,
+ @gitlab_git_wiki_page,
content: "some other content",
format: :markdown,
message: "updated page"
@@ -246,7 +241,7 @@ describe ProjectWiki do
it 'updates project activity' do
subject.update_page(
- @gollum_page,
+ @gitlab_git_wiki_page,
content: 'Yet more content',
format: :markdown,
message: 'Updated page again'
@@ -262,7 +257,7 @@ describe ProjectWiki do
describe "#delete_page" do
before do
create_page("index", "some content")
- @page = subject.wiki.paged("index")
+ @page = subject.wiki.page(title: "index")
end
it "deletes the page" do
@@ -282,27 +277,28 @@ describe ProjectWiki do
describe '#create_repo!' do
it 'creates a repository' do
- expect(subject).to receive(:init_repo)
- .with(subject.full_path)
- .and_return(true)
-
+ expect(raw_repository.exists?).to eq(false)
expect(subject.repository).to receive(:after_create)
- expect(subject.create_repo!).to be_an_instance_of(Gollum::Wiki)
+ subject.send(:create_repo!, raw_repository)
+
+ expect(raw_repository.exists?).to eq(true)
end
end
describe '#ensure_repository' do
it 'creates the repository if it not exist' do
- allow(subject).to receive(:repository_exists?).and_return(false)
-
- expect(subject).to receive(:create_repo!)
+ expect(raw_repository.exists?).to eq(false)
+ expect(subject).to receive(:create_repo!).and_call_original
subject.ensure_repository
+
+ expect(raw_repository.exists?).to eq(true)
end
it 'does not create the repository if it exists' do
- allow(subject).to receive(:repository_exists?).and_return(true)
+ subject.wiki
+ expect(raw_repository.exists?).to eq(true)
expect(subject).not_to receive(:create_repo!)
@@ -329,7 +325,7 @@ describe ProjectWiki do
end
def commit_details
- { name: user.name, email: user.email, message: "test commit" }
+ Gitlab::Git::Wiki::CommitDetails.new(user.name, user.email, "test commit")
end
def create_page(name, content)
@@ -337,6 +333,6 @@ describe ProjectWiki do
end
def destroy_page(page)
- subject.wiki.delete_page(page, commit_details)
+ subject.delete_page(page, commit_details)
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 07d9b66060e..7156c1b7aa8 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -636,18 +636,18 @@ describe Repository do
describe '#fetch_ref' do
describe 'when storage is broken', broken_storage: true do
it 'should raise a storage error' do
- path = broken_repository.path_to_repo
-
- expect_to_raise_storage_error { broken_repository.fetch_ref(path, '1', '2') }
+ expect_to_raise_storage_error do
+ broken_repository.fetch_ref(broken_repository, source_ref: '1', target_ref: '2')
+ end
end
end
end
describe '#create_ref' do
- it 'redirects the call to fetch_ref' do
+ it 'redirects the call to write_ref' do
ref, ref_path = '1', '2'
- expect(repository).to receive(:fetch_ref).with(repository.path_to_repo, ref, ref_path)
+ expect(repository.raw_repository).to receive(:write_ref).with(ref_path, ref)
repository.create_ref(ref, ref_path)
end
@@ -815,45 +815,70 @@ describe Repository do
end
describe '#add_branch' do
- context 'when pre hooks were successful' do
- it 'runs without errors' do
- hook = double(trigger: [true, nil])
- expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
+ let(:branch_name) { 'new_feature' }
+ let(:target) { 'master' }
- expect { repository.add_branch(user, 'new_feature', 'master') }.not_to raise_error
- end
+ subject { repository.add_branch(user, branch_name, target) }
- it 'creates the branch' do
- allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
+ context 'with Gitaly enabled' do
+ it "calls Gitaly's OperationService" do
+ expect_any_instance_of(Gitlab::GitalyClient::OperationService)
+ .to receive(:user_create_branch).with(branch_name, user, target)
+ .and_return(nil)
- branch = repository.add_branch(user, 'new_feature', 'master')
+ subject
+ end
- expect(branch.name).to eq('new_feature')
+ it 'creates_the_branch' do
+ expect(subject.name).to eq(branch_name)
+ expect(repository.find_branch(branch_name)).not_to be_nil
end
- it 'calls the after_create_branch hook' do
- expect(repository).to receive(:after_create_branch)
+ context 'with a non-existing target' do
+ let(:target) { 'fake-target' }
- repository.add_branch(user, 'new_feature', 'master')
+ it "returns false and doesn't create the branch" do
+ expect(subject).to be(false)
+ expect(repository.find_branch(branch_name)).to be_nil
+ end
end
end
- context 'when pre hooks failed' do
- it 'gets an error' do
- allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
+ context 'with Gitaly disabled', skip_gitaly_mock: true do
+ context 'when pre hooks were successful' do
+ it 'runs without errors' do
+ hook = double(trigger: [true, nil])
+ expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
- expect do
- repository.add_branch(user, 'new_feature', 'master')
- end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
+ expect { subject }.not_to raise_error
+ end
+
+ it 'creates the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
+
+ expect(subject.name).to eq(branch_name)
+ end
+
+ it 'calls the after_create_branch hook' do
+ expect(repository).to receive(:after_create_branch)
+
+ subject
+ end
end
- it 'does not create the branch' do
- allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
+ context 'when pre hooks failed' do
+ it 'gets an error' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
- expect do
- repository.add_branch(user, 'new_feature', 'master')
- end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
- expect(repository.find_branch('new_feature')).to be_nil
+ expect { subject }.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
+ end
+
+ it 'does not create the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
+
+ expect { subject }.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
+ expect(repository.find_branch(branch_name)).to be_nil
+ end
end
end
end
@@ -876,47 +901,6 @@ describe Repository do
end
end
- describe '#rm_branch' do
- let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
- let(:blank_sha) { '0000000000000000000000000000000000000000' }
-
- context 'when pre hooks were successful' do
- it 'runs without errors' do
- expect_any_instance_of(Gitlab::Git::HooksService).to receive(:execute)
- .with(git_user, repository.raw_repository, old_rev, blank_sha, 'refs/heads/feature')
-
- expect { repository.rm_branch(user, 'feature') }.not_to raise_error
- end
-
- it 'deletes the branch' do
- allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
-
- expect { repository.rm_branch(user, 'feature') }.not_to raise_error
-
- expect(repository.find_branch('feature')).to be_nil
- end
- end
-
- context 'when pre hooks failed' do
- it 'gets an error' do
- allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
-
- expect do
- repository.rm_branch(user, 'feature')
- end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
- end
-
- it 'does not delete the branch' do
- allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
-
- expect do
- repository.rm_branch(user, 'feature')
- end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
- expect(repository.find_branch('feature')).not_to be_nil
- end
- end
- end
-
describe '#update_branch_with_hooks' do
let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
let(:new_rev) { 'a74ae73c1ccde9b974a70e82b901588071dc142a' } # commit whose parent is old_rev
@@ -1131,21 +1115,31 @@ describe Repository do
end
describe '#has_visible_content?' do
- subject { repository.has_visible_content? }
+ before do
+ # If raw_repository.has_visible_content? gets called more than once then
+ # caching is broken. We don't want that.
+ expect(repository.raw_repository).to receive(:has_visible_content?)
+ .once
+ .and_return(result)
+ end
- describe 'when there are no branches' do
- before do
- allow(repository.raw_repository).to receive(:branch_count).and_return(0)
- end
+ context 'when true' do
+ let(:result) { true }
- it { is_expected.to eq(false) }
+ it 'returns true and caches it' do
+ expect(repository.has_visible_content?).to eq(true)
+ # Second call hits the cache
+ expect(repository.has_visible_content?).to eq(true)
+ end
end
- describe 'when there are branches' do
- it 'returns true' do
- expect(repository.raw_repository).to receive(:branch_count).and_return(3)
+ context 'when false' do
+ let(:result) { false }
- expect(subject).to eq(true)
+ it 'returns false and caches it' do
+ expect(repository.has_visible_content?).to eq(false)
+ # Second call hits the cache
+ expect(repository.has_visible_content?).to eq(false)
end
end
end
@@ -1262,6 +1256,7 @@ describe 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
end
@@ -1270,6 +1265,7 @@ describe 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
end
@@ -1308,6 +1304,34 @@ describe Repository do
end
end
+ describe '#ff_merge' do
+ before do
+ repository.add_branch(user, 'ff-target', 'feature~5')
+ end
+
+ it 'merges the code and return the commit id' do
+ merge_request = create(:merge_request, source_branch: 'feature', target_branch: 'ff-target', source_project: project)
+ merge_commit_id = repository.ff_merge(user,
+ merge_request.diff_head_sha,
+ merge_request.target_branch,
+ merge_request: merge_request)
+ merge_commit = repository.commit(merge_commit_id)
+
+ expect(merge_commit).to be_present
+ expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present
+ end
+
+ it 'sets the `in_progress_merge_commit_sha` flag for the given merge request' do
+ merge_request = create(:merge_request, source_branch: 'feature', target_branch: 'ff-target', source_project: project)
+ merge_commit_id = repository.ff_merge(user,
+ merge_request.diff_head_sha,
+ merge_request.target_branch,
+ merge_request: merge_request)
+
+ expect(merge_request.in_progress_merge_commit_sha).to eq(merge_commit_id)
+ end
+ end
+
describe '#revert' do
let(:new_image_commit) { repository.commit('33f3729a45c02fc67d00adb1b8bca394b0e761d9') }
let(:update_image_commit) { repository.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
@@ -1599,7 +1623,7 @@ describe Repository do
describe '#expire_branches_cache' do
it 'expires the cache' do
expect(repository).to receive(:expire_method_caches)
- .with(%i(branch_names branch_count))
+ .with(%i(branch_names branch_count has_visible_content?))
.and_call_original
repository.expire_branches_cache
@@ -1617,27 +1641,41 @@ describe Repository do
end
describe '#add_tag' do
- context 'with a valid target' do
- let(:user) { build_stubbed(:user) }
+ let(:user) { build_stubbed(:user) }
- it 'creates the tag using rugged' do
- expect(repository.rugged.tags).to receive(:create)
- .with('8.5', repository.commit('master').id,
- hash_including(message: 'foo',
- tagger: hash_including(name: user.name, email: user.email)))
- .and_call_original
+ shared_examples 'adding tag' do
+ context 'with a valid target' do
+ it 'creates the tag' do
+ repository.add_tag(user, '8.5', 'master', 'foo')
- repository.add_tag(user, '8.5', 'master', 'foo')
- end
+ tag = repository.find_tag('8.5')
+ expect(tag).to be_present
+ expect(tag.message).to eq('foo')
+ expect(tag.dereferenced_target.id).to eq(repository.commit('master').id)
+ end
- it 'returns a Gitlab::Git::Tag object' do
- tag = repository.add_tag(user, '8.5', 'master', 'foo')
+ it 'returns a Gitlab::Git::Tag object' do
+ tag = repository.add_tag(user, '8.5', 'master', 'foo')
+
+ expect(tag).to be_a(Gitlab::Git::Tag)
+ end
+ end
- expect(tag).to be_a(Gitlab::Git::Tag)
+ context 'with an invalid target' do
+ it 'returns false' do
+ expect(repository.add_tag(user, '8.5', 'bar', 'foo')).to be false
+ end
end
+ end
+
+ context 'when Gitaly operation_user_add_tag feature is enabled' do
+ it_behaves_like 'adding tag'
+ end
+
+ context 'when Gitaly operation_user_add_tag feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'adding tag'
- it 'passes commit SHA to pre-receive and update hooks,\
- and tag SHA to post-receive hook' do
+ it 'passes commit SHA to pre-receive and update hooks and tag SHA to post-receive hook' do
pre_receive_hook = Gitlab::Git::Hook.new('pre-receive', project)
update_hook = Gitlab::Git::Hook.new('update', project)
post_receive_hook = Gitlab::Git::Hook.new('post-receive', project)
@@ -1655,39 +1693,105 @@ describe Repository do
tag_sha = tag.target
expect(pre_receive_hook).to have_received(:trigger)
- .with(anything, anything, commit_sha, anything)
+ .with(anything, anything, anything, commit_sha, anything)
expect(update_hook).to have_received(:trigger)
- .with(anything, anything, commit_sha, anything)
+ .with(anything, anything, anything, commit_sha, anything)
expect(post_receive_hook).to have_received(:trigger)
- .with(anything, anything, tag_sha, anything)
+ .with(anything, anything, anything, tag_sha, anything)
end
end
+ end
- context 'with an invalid target' do
- it 'returns false' do
- expect(repository.add_tag(user, '8.5', 'bar', 'foo')).to be false
+ describe '#rm_branch' do
+ shared_examples "user deleting a branch" do
+ it 'removes a branch' do
+ expect(repository).to receive(:before_remove_branch)
+ expect(repository).to receive(:after_remove_branch)
+
+ repository.rm_branch(user, 'feature')
end
end
- end
- describe '#rm_branch' do
- let(:user) { create(:user) }
+ context 'with gitaly enabled' do
+ it_behaves_like "user deleting a branch"
- it 'removes a branch' do
- expect(repository).to receive(:before_remove_branch)
- expect(repository).to receive(:after_remove_branch)
+ context 'when pre hooks failed' do
+ before do
+ allow_any_instance_of(Gitlab::GitalyClient::OperationService)
+ .to receive(:user_delete_branch).and_raise(Gitlab::Git::HooksService::PreReceiveError)
+ end
- repository.rm_branch(user, 'feature')
+ it 'gets an error and does not delete the branch' do
+ expect do
+ repository.rm_branch(user, 'feature')
+ end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
+
+ expect(repository.find_branch('feature')).not_to be_nil
+ end
+ end
+ end
+
+ context 'with gitaly disabled', skip_gitaly_mock: true do
+ it_behaves_like "user deleting a branch"
+
+ let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
+ let(:blank_sha) { '0000000000000000000000000000000000000000' }
+
+ context 'when pre hooks were successful' do
+ it 'runs without errors' do
+ expect_any_instance_of(Gitlab::Git::HooksService).to receive(:execute)
+ .with(git_user, repository.raw_repository, old_rev, blank_sha, 'refs/heads/feature')
+
+ expect { repository.rm_branch(user, 'feature') }.not_to raise_error
+ end
+
+ it 'deletes the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
+
+ expect { repository.rm_branch(user, 'feature') }.not_to raise_error
+
+ expect(repository.find_branch('feature')).to be_nil
+ end
+ end
+
+ context 'when pre hooks failed' do
+ it 'gets an error' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
+
+ expect do
+ repository.rm_branch(user, 'feature')
+ end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
+ end
+
+ it 'does not delete the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
+
+ expect do
+ repository.rm_branch(user, 'feature')
+ end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
+ expect(repository.find_branch('feature')).not_to be_nil
+ end
+ end
end
end
describe '#rm_tag' do
- it 'removes a tag' do
- expect(repository).to receive(:before_remove_tag)
+ shared_examples 'removing tag' do
+ it 'removes a tag' do
+ expect(repository).to receive(:before_remove_tag)
- repository.rm_tag(create(:user), 'v1.1.0')
+ repository.rm_tag(build_stubbed(:user), 'v1.1.0')
- expect(repository.find_tag('v1.1.0')).to be_nil
+ expect(repository.find_tag('v1.1.0')).to be_nil
+ end
+ end
+
+ context 'when Gitaly operation_user_delete_tag feature is enabled' do
+ it_behaves_like 'removing tag'
+ end
+
+ context 'when Gitaly operation_user_delete_tag feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'removing tag'
end
end
@@ -1860,6 +1964,15 @@ describe Repository do
repository.expire_all_method_caches
end
+
+ it 'all cache_method definitions are in the lists of method caches' do
+ methods = repository.methods.map do |method|
+ match = /^_uncached_(.*)/.match(method)
+ match[1].to_sym if match
+ end.compact
+
+ expect(methods).to match_array(Repository::CACHED_METHODS + Repository::MEMOIZED_CACHED_METHODS)
+ end
end
describe '#file_on_head' do
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index 9ef8d117123..1f14d06997e 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -80,7 +80,7 @@ describe WikiPage do
context "when initialized with an existing gollum page" do
before do
create_page("test page", "test content")
- @page = wiki.wiki.paged("test page")
+ @page = wiki.wiki.page(title: "test page")
@wiki_page = described_class.new(wiki, @page, true)
end
@@ -105,7 +105,7 @@ describe WikiPage do
end
it "sets the version attribute" do
- expect(@wiki_page.version).to be_a Gollum::Git::Commit
+ expect(@wiki_page.version).to be_a Gitlab::Git::WikiPageVersion
end
end
end
@@ -321,14 +321,14 @@ describe WikiPage do
end
it 'returns true when requesting an old version' do
- old_version = @page.versions.last.to_s
+ old_version = @page.versions.last.id
old_page = wiki.find_page('Update', old_version)
expect(old_page.historical?).to eq true
end
it 'returns false when requesting latest version' do
- latest_version = @page.versions.first.to_s
+ latest_version = @page.versions.first.id
latest_page = wiki.find_page('Update', latest_version)
expect(latest_page.historical?).to eq false
@@ -393,7 +393,7 @@ describe WikiPage do
end
def commit_details
- { name: user.name, email: user.email, message: "test commit" }
+ Gitlab::Git::Wiki::CommitDetails.new(user.name, user.email, "test commit")
end
def create_page(name, content)
@@ -401,8 +401,8 @@ describe WikiPage do
end
def destroy_page(title)
- page = wiki.wiki.paged(title)
- wiki.wiki.delete_page(page, commit_details)
+ page = wiki.wiki.page(title: title)
+ wiki.delete_page(page, commit_details)
end
def get_slugs(page_or_dir)
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
index 983f0e52d31..5b8cf2e6ab5 100644
--- a/spec/policies/global_policy_spec.rb
+++ b/spec/policies/global_policy_spec.rb
@@ -52,6 +52,29 @@ describe GlobalPolicy do
end
end
+ describe "create fork" do
+ context "when user has not exceeded project limit" do
+ it { is_expected.to be_allowed(:create_fork) }
+ end
+
+ context "when user has exceeded project limit" do
+ let(:current_user) { create(:user, projects_limit: 0) }
+
+ it { is_expected.not_to be_allowed(:create_fork) }
+ end
+
+ context "when user is a master in a group" do
+ let(:group) { create(:group) }
+ let(:current_user) { create(:user, projects_limit: 0) }
+
+ before do
+ group.add_master(current_user)
+ end
+
+ it { is_expected.to be_allowed(:create_fork) }
+ end
+ end
+
describe 'custom attributes' do
context 'regular user' do
it { is_expected.not_to be_allowed(:read_custom_attribute) }
diff --git a/spec/policies/namespace_policy_spec.rb b/spec/policies/namespace_policy_spec.rb
new file mode 100644
index 00000000000..e52ff02e5f0
--- /dev/null
+++ b/spec/policies/namespace_policy_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe NamespacePolicy do
+ let(:current_user) { create(:user) }
+ let(:namespace) { current_user.namespace }
+
+ subject { described_class.new(current_user, namespace) }
+
+ context "create projects" do
+ context "user namespace" do
+ it { is_expected.to be_allowed(:create_projects) }
+ end
+
+ context "user who has exceeded project limit" do
+ let(:current_user) { create(:user, projects_limit: 0) }
+
+ it { is_expected.not_to be_allowed(:create_projects) }
+ end
+ end
+end
diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb
index 2187be0190d..5e114434a67 100644
--- a/spec/presenters/merge_request_presenter_spec.rb
+++ b/spec/presenters/merge_request_presenter_spec.rb
@@ -300,6 +300,10 @@ describe MergeRequestPresenter do
described_class.new(resource, current_user: user).remove_wip_path
end
+ before do
+ allow(resource).to receive(:work_in_progress?).and_return(true)
+ end
+
context 'when merge request enabled and has permission' do
it 'has remove_wip_path' do
allow(project).to receive(:merge_requests_enabled?) { true }
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 98c49d3364c..060c8902471 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -480,6 +480,27 @@ describe API::Helpers do
handle_api_exception(exception)
end
+
+ context 'with a personal access token given' do
+ let(:token) { create(:personal_access_token, scopes: ['api'], user: user) }
+
+ # Regression test for https://gitlab.com/gitlab-org/gitlab-ce/issues/38571
+ it 'does not raise an additional exception because of missing `request`' do
+ # We need to stub at a lower level than #sentry_enabled? otherwise
+ # Sentry is not enabled when the request below is made, and the test
+ # would pass even without the fix
+ expect(Gitlab::Sentry).to receive(:enabled?).twice.and_return(true)
+ expect(ProjectsFinder).to receive(:new).and_raise('Runtime Error!')
+
+ get api('/projects', personal_access_token: token)
+
+ # The 500 status is expected as we're testing a case where an exception
+ # is raised, but Grape shouldn't raise an additional exception
+ expect(response).to have_gitlab_http_status(500)
+ expect(json_response['message']).not_to include("undefined local variable or method `request'")
+ expect(json_response['message']).to start_with("\nRuntimeError (Runtime Error!):")
+ end
+ end
end
describe '.authenticate_non_get!' do
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 12720355a6d..5068df5b43a 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -360,6 +360,8 @@ describe API::Runner do
'policy' => 'pull-push' }]
end
+ let(:expected_features) { { 'trace_sections' => true } }
+
it 'picks a job' do
request_job info: { platform: :darwin }
@@ -379,6 +381,7 @@ describe API::Runner do
expect(json_response['artifacts']).to eq(expected_artifacts)
expect(json_response['cache']).to eq(expected_cache)
expect(json_response['variables']).to include(*expected_variables)
+ expect(json_response['features']).to eq(expected_features)
end
context 'when job is made for tag' do
diff --git a/spec/serializers/build_serializer_spec.rb b/spec/serializers/build_serializer_spec.rb
index 01e2cfed6f8..9673b11c2a2 100644
--- a/spec/serializers/build_serializer_spec.rb
+++ b/spec/serializers/build_serializer_spec.rb
@@ -38,7 +38,7 @@ describe BuildSerializer do
expect(subject[:text]).to eq(status.text)
expect(subject[:label]).to eq(status.label)
expect(subject[:icon]).to eq(status.icon)
- expect(subject[:favicon]).to eq("/assets/ci_favicons/#{status.favicon}.ico")
+ expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.ico")
end
end
end
diff --git a/spec/serializers/container_repository_entity_spec.rb b/spec/serializers/container_repository_entity_spec.rb
new file mode 100644
index 00000000000..c589cd18f77
--- /dev/null
+++ b/spec/serializers/container_repository_entity_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+describe ContainerRepositoryEntity do
+ let(:entity) do
+ described_class.new(repository, request: request)
+ end
+
+ set(:project) { create(:project) }
+ set(:user) { create(:user) }
+ set(:repository) { create(:container_repository, project: project) }
+
+ let(:request) { double('request') }
+
+ subject { entity.as_json }
+
+ before do
+ stub_container_registry_config(enabled: true)
+ allow(request).to receive(:project).and_return(project)
+ allow(request).to receive(:current_user).and_return(user)
+ end
+
+ it 'exposes required informations' do
+ expect(subject).to include(:id, :path, :location, :tags_path)
+ end
+
+ context 'when user can manage repositories' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'exposes destroy_path' do
+ expect(subject).to include(:destroy_path)
+ end
+ end
+
+ context 'when user cannot manage repositories' do
+ it 'does not expose destroy_path' do
+ expect(subject).not_to include(:destroy_path)
+ end
+ end
+end
diff --git a/spec/serializers/container_tag_entity_spec.rb b/spec/serializers/container_tag_entity_spec.rb
new file mode 100644
index 00000000000..6dcc5204516
--- /dev/null
+++ b/spec/serializers/container_tag_entity_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe ContainerTagEntity do
+ let(:entity) do
+ described_class.new(tag, request: request)
+ end
+
+ set(:project) { create(:project) }
+ set(:user) { create(:user) }
+ set(:repository) { create(:container_repository, name: 'image', project: project) }
+
+ let(:request) { double('request') }
+ let(:tag) { repository.tag('test') }
+
+ subject { entity.as_json }
+
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags(repository: /image/, tags: %w[test])
+ allow(request).to receive(:project).and_return(project)
+ allow(request).to receive(:current_user).and_return(user)
+ end
+
+ it 'exposes required informations' do
+ expect(subject).to include(:name, :location, :revision, :total_size, :created_at)
+ end
+
+ context 'when user can manage repositories' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'exposes destroy_path' do
+ expect(subject).to include(:destroy_path)
+ end
+ end
+
+ context 'when user cannot manage repositories' do
+ it 'does not expose destroy_path' do
+ expect(subject).not_to include(:destroy_path)
+ end
+ end
+end
diff --git a/spec/serializers/merge_request_entity_spec.rb b/spec/serializers/merge_request_entity_spec.rb
index a2fd5b7daae..4aeb593da44 100644
--- a/spec/serializers/merge_request_entity_spec.rb
+++ b/spec/serializers/merge_request_entity_spec.rb
@@ -11,16 +11,6 @@ describe MergeRequestEntity do
described_class.new(resource, request: request).as_json
end
- it 'includes author' do
- req = double('request')
-
- author_payload = UserEntity
- .represent(resource.author, request: req)
- .as_json
-
- expect(subject[:author]).to eq(author_payload)
- end
-
it 'includes pipeline' do
req = double('request', current_user: user)
pipeline = build_stubbed(:ci_pipeline)
@@ -47,7 +37,8 @@ describe MergeRequestEntity do
:cancel_merge_when_pipeline_succeeds_path,
:create_issue_to_resolve_discussions_path,
:source_branch_path, :target_branch_commits_path,
- :target_branch_tree_path, :commits_count, :merge_ongoing)
+ :target_branch_tree_path, :commits_count, :merge_ongoing,
+ :ff_only_enabled)
end
it 'has email_patches_path' do
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index 3baf9b1edab..8fc1ceedc34 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -168,7 +168,7 @@ describe PipelineSerializer do
expect(subject[:text]).to eq(status.text)
expect(subject[:label]).to eq(status.label)
expect(subject[:icon]).to eq(status.icon)
- expect(subject[:favicon]).to eq("/assets/ci_favicons/#{status.favicon}.ico")
+ expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.ico")
end
end
end
diff --git a/spec/serializers/status_entity_spec.rb b/spec/serializers/status_entity_spec.rb
index 3964b998084..16431ed4188 100644
--- a/spec/serializers/status_entity_spec.rb
+++ b/spec/serializers/status_entity_spec.rb
@@ -18,12 +18,12 @@ describe StatusEntity do
it 'contains status details' do
expect(subject).to include :text, :icon, :favicon, :label, :group
expect(subject).to include :has_details, :details_path
- expect(subject[:favicon]).to eq('/assets/ci_favicons/favicon_status_success.ico')
+ expect(subject[:favicon]).to match_asset_path('/assets/ci_favicons/favicon_status_success.ico')
end
it 'contains a dev namespaced favicon if dev env' do
allow(Rails.env).to receive(:development?) { true }
- expect(entity.as_json[:favicon]).to eq('/assets/ci_favicons/dev/favicon_status_success.ico')
+ expect(entity.as_json[:favicon]).to match_asset_path('/assets/ci_favicons/dev/favicon_status_success.ico')
end
end
end
diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb
new file mode 100644
index 00000000000..aaabf3ed2b0
--- /dev/null
+++ b/spec/services/merge_requests/ff_merge_service_spec.rb
@@ -0,0 +1,84 @@
+require 'spec_helper'
+
+describe MergeRequests::FfMergeService do
+ let(:user) { create(:user) }
+ let(:user2) { create(:user) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_branch: 'flatten-dir',
+ target_branch: 'improve/awesome',
+ assignee: user2)
+ end
+ let(:project) { merge_request.project }
+
+ before do
+ project.team << [user, :master]
+ project.team << [user2, :developer]
+ end
+
+ describe '#execute' do
+ context 'valid params' do
+ let(:service) { described_class.new(project, user, {}) }
+
+ before do
+ allow(service).to receive(:execute_hooks)
+
+ perform_enqueued_jobs do
+ service.execute(merge_request)
+ end
+ end
+
+ it "does not create merge commit" do
+ source_branch_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
+ target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
+ expect(source_branch_sha).to eq(target_branch_sha)
+ end
+
+ it { expect(merge_request).to be_valid }
+ it { expect(merge_request).to be_merged }
+
+ it 'sends email to user2 about merge of new merge_request' do
+ email = ActionMailer::Base.deliveries.last
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(merge_request.title)
+ end
+
+ it 'creates system note about merge_request merge' do
+ note = merge_request.notes.last
+ expect(note.note).to include 'merged'
+ end
+ end
+
+ context "error handling" do
+ let(:service) { described_class.new(project, user, commit_message: 'Awesome message') }
+
+ before do
+ allow(Rails.logger).to receive(:error)
+ end
+
+ it 'logs and saves error if there is an exception' do
+ error_message = 'error message'
+
+ allow(service).to receive(:repository).and_raise("error message")
+ allow(service).to receive(:execute_hooks)
+
+ service.execute(merge_request)
+
+ expect(merge_request.merge_error).to include(error_message)
+ expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message))
+ end
+
+ it 'logs and saves error if there is an PreReceiveError exception' do
+ error_message = 'error message'
+
+ allow(service).to receive(:repository).and_raise(Gitlab::Git::HooksService::PreReceiveError, error_message)
+ allow(service).to receive(:execute_hooks)
+
+ service.execute(merge_request)
+
+ expect(merge_request.merge_error).to include(error_message)
+ expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message))
+ end
+ end
+ end
+end
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 5da634e2fb1..dc89fdebce7 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -76,9 +76,8 @@ describe Projects::CreateService, '#execute' do
context 'wiki_enabled true creates wiki repository directory' do
it do
project = create_project(user, opts)
- path = ProjectWiki.new(project, user).send(:path_to_repo)
- expect(File.exist?(path)).to be_truthy
+ expect(wiki_repo(project).exists?).to be_truthy
end
end
@@ -86,11 +85,15 @@ describe Projects::CreateService, '#execute' do
it do
opts[:wiki_enabled] = false
project = create_project(user, opts)
- path = ProjectWiki.new(project, user).send(:path_to_repo)
- expect(File.exist?(path)).to be_falsey
+ expect(wiki_repo(project).exists?).to be_falsey
end
end
+
+ def wiki_repo(project)
+ relative_path = ProjectWiki.new(project).disk_path + '.git'
+ Gitlab::Git::Repository.new(project.repository_storage, relative_path, 'foobar')
+ end
end
context 'builds_enabled global setting' do
@@ -149,6 +152,9 @@ describe Projects::CreateService, '#execute' do
end
context 'when another repository already exists on disk' do
+ let(:repository_storage) { 'default' }
+ let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
+
let(:opts) do
{
name: 'Existing',
@@ -156,30 +162,59 @@ describe Projects::CreateService, '#execute' do
}
end
- let(:repository_storage_path) { Gitlab.config.repositories.storages['default']['path'] }
+ context 'with legacy storage' do
+ before do
+ gitlab_shell.add_repository(repository_storage, "#{user.namespace.full_path}/existing")
+ end
- before do
- gitlab_shell.add_repository(repository_storage_path, "#{user.namespace.full_path}/existing")
- end
+ after do
+ gitlab_shell.remove_repository(repository_storage_path, "#{user.namespace.full_path}/existing")
+ end
- after do
- gitlab_shell.remove_repository(repository_storage_path, "#{user.namespace.full_path}/existing")
- end
+ it 'does not allow to create a project when path matches existing repository on disk' do
+ project = create_project(user, opts)
- it 'does not allow to create project with same path' do
- project = create_project(user, opts)
+ expect(project).not_to be_persisted
+ expect(project).to respond_to(:errors)
+ expect(project.errors.messages).to have_key(:base)
+ expect(project.errors.messages[:base].first).to match('There is already a repository with that name on disk')
+ end
- expect(project).to respond_to(:errors)
- expect(project.errors.messages).to have_key(:base)
- expect(project.errors.messages[:base].first).to match('There is already a repository with that name on disk')
+ it 'does not allow to import project when path matches existing repository on disk' do
+ project = create_project(user, opts.merge({ import_url: 'https://gitlab.com/gitlab-org/gitlab-test.git' }))
+
+ expect(project).not_to be_persisted
+ expect(project).to respond_to(:errors)
+ expect(project.errors.messages).to have_key(:base)
+ expect(project.errors.messages[:base].first).to match('There is already a repository with that name on disk')
+ end
end
- it 'does not allow to import a project with the same path' do
- project = create_project(user, opts.merge({ import_url: 'https://gitlab.com/gitlab-org/gitlab-test.git' }))
+ context 'with hashed storage' do
+ let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
+ let(:hashed_path) { '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
+
+ before do
+ stub_application_setting(hashed_storage_enabled: true)
+ allow(Digest::SHA2).to receive(:hexdigest) { hash }
+ end
- expect(project).to respond_to(:errors)
- expect(project.errors.messages).to have_key(:base)
- expect(project.errors.messages[:base].first).to match('There is already a repository with that name on disk')
+ before do
+ gitlab_shell.add_repository(repository_storage, hashed_path)
+ end
+
+ after do
+ gitlab_shell.remove_repository(repository_storage_path, hashed_path)
+ end
+
+ it 'does not allow to create a project when path matches existing repository on disk' do
+ project = create_project(user, opts)
+
+ expect(project).not_to be_persisted
+ expect(project).to respond_to(:errors)
+ expect(project.errors.messages).to have_key(:base)
+ expect(project.errors.messages[:base].first).to match('There is already a repository with that name on disk')
+ end
end
end
end
@@ -208,6 +243,15 @@ describe Projects::CreateService, '#execute' do
end
end
+ context 'when skip_disk_validation is used' do
+ it 'sets the project attribute' do
+ opts[:skip_disk_validation] = true
+ project = create_project(user, opts)
+
+ expect(project.skip_disk_validation).to be_truthy
+ end
+ end
+
def create_project(user, opts)
Projects::CreateService.new(user, opts).execute
end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index a6e0364d44c..fa9d6969830 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -76,10 +76,11 @@ describe Projects::ForkService do
end
context 'repository already exists' do
- let(:repository_storage_path) { Gitlab.config.repositories.storages['default']['path'] }
+ let(:repository_storage) { 'default' }
+ let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
before do
- gitlab_shell.add_repository(repository_storage_path, "#{@to_user.namespace.full_path}/#{@from_project.path}")
+ gitlab_shell.add_repository(repository_storage, "#{@to_user.namespace.full_path}/#{@from_project.path}")
end
after do
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index a14ed526f68..2459f371a91 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -121,11 +121,14 @@ describe Projects::TransferService do
end
context 'namespace which contains orphan repository with same projects path name' do
- let(:repository_storage_path) { Gitlab.config.repositories.storages['default']['path'] }
+ let(:repository_storage) { 'default' }
+ let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
before do
group.add_owner(user)
- gitlab_shell.add_repository(repository_storage_path, "#{group.full_path}/#{project.path}")
+ unless gitlab_shell.add_repository(repository_storage, "#{group.full_path}/#{project.path}")
+ raise 'failed to add repository'
+ end
@result = transfer_project(project, user, group)
end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index c551083ac90..d400304622e 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -149,24 +149,43 @@ describe Projects::UpdateService, '#execute' do
end
context 'when renaming a project' do
- let(:repository_storage_path) { Gitlab.config.repositories.storages['default']['path'] }
+ let(:repository_storage) { 'default' }
+ let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
- before do
- gitlab_shell.add_repository(repository_storage_path, "#{user.namespace.full_path}/existing")
- end
+ context 'with legacy storage' do
+ before do
+ gitlab_shell.add_repository(repository_storage, "#{user.namespace.full_path}/existing")
+ end
- after do
- gitlab_shell.remove_repository(repository_storage_path, "#{user.namespace.full_path}/existing")
+ after do
+ gitlab_shell.remove_repository(repository_storage_path, "#{user.namespace.full_path}/existing")
+ end
+
+ it 'does not allow renaming when new path matches existing repository on disk' do
+ result = update_project(project, admin, path: 'existing')
+
+ expect(result).to include(status: :error)
+ expect(result[:message]).to match('There is already a repository with that name on disk')
+ expect(project).not_to be_valid
+ expect(project.errors.messages).to have_key(:base)
+ expect(project.errors.messages[:base]).to include('There is already a repository with that name on disk')
+ end
end
- it 'does not allow renaming when new path matches existing repository on disk' do
- result = update_project(project, admin, path: 'existing')
+ context 'with hashed storage' do
+ let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
- expect(result).to include(status: :error)
- expect(result[:message]).to match('There is already a repository with that name on disk')
- expect(project).not_to be_valid
- expect(project.errors.messages).to have_key(:base)
- expect(project.errors.messages[:base]).to include('There is already a repository with that name on disk')
+ before do
+ stub_application_setting(hashed_storage_enabled: true)
+ end
+
+ it 'does not check if new path matches existing repository on disk' do
+ expect(project).not_to receive(:repository_with_same_path_already_exists?)
+
+ result = update_project(project, admin, path: 'existing')
+
+ expect(result).to include(status: :success)
+ end
end
end
diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb
index 57013b54560..e7e9080b6b0 100644
--- a/spec/services/tags/create_service_spec.rb
+++ b/spec/services/tags/create_service_spec.rb
@@ -28,7 +28,7 @@ describe Tags::CreateService do
it 'returns an error' do
expect(repository).to receive(:add_tag)
.with(user, 'v1.1.0', 'master', 'Foo')
- .and_raise(Rugged::TagError)
+ .and_raise(Gitlab::Git::Repository::TagExistsError)
response = service.execute('v1.1.0', 'master', 'Foo')
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index dbf05b7f004..576e4ae1d38 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -169,6 +169,24 @@ RSpec.configure do |config|
end
end
+# add simpler way to match asset paths containing digest strings
+RSpec::Matchers.define :match_asset_path do |expected|
+ match do |actual|
+ path = Regexp.escape(expected)
+ extname = Regexp.escape(File.extname(expected))
+ digest_regex = Regexp.new(path.sub(extname, "(?:-\\h+)?#{extname}") << '$')
+ digest_regex =~ actual
+ end
+
+ failure_message do |actual|
+ "expected that #{actual} would include an asset path for #{expected}"
+ end
+
+ failure_message_when_negated do |actual|
+ "expected that #{actual} would not include an asset path for #{expected}"
+ end
+end
+
FactoryGirl::SyntaxRunner.class_eval do
include RSpec::Mocks::ExampleMethods
end
diff --git a/spec/support/stub_gitlab_calls.rb b/spec/support/stub_gitlab_calls.rb
index 78a2ff73746..5f22d886910 100644
--- a/spec/support/stub_gitlab_calls.rb
+++ b/spec/support/stub_gitlab_calls.rb
@@ -39,11 +39,11 @@ module StubGitlabCalls
.and_return({ 'tags' => tags })
allow_any_instance_of(ContainerRegistry::Client)
- .to receive(:repository_manifest).with(repository)
+ .to receive(:repository_manifest).with(repository, anything)
.and_return(stub_container_registry_tag_manifest)
allow_any_instance_of(ContainerRegistry::Client)
- .to receive(:blob).with(repository)
+ .to receive(:blob).with(repository, anything, 'application/octet-stream')
.and_return(stub_container_registry_blob)
end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index b4e8b5ea67b..79395f4c564 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -17,6 +17,7 @@ module TestEnv
'feature_conflict' => 'bb5206f',
'fix' => '48f0be4',
'improve/awesome' => '5937ac0',
+ 'merged-target' => '21751bf',
'markdown' => '0ed8c6c',
'lfs' => 'be93687',
'master' => 'b83d6e3',
diff --git a/spec/support/update_invalid_issuable.rb b/spec/support/update_invalid_issuable.rb
index 1490287681b..50a1d4a56e2 100644
--- a/spec/support/update_invalid_issuable.rb
+++ b/spec/support/update_invalid_issuable.rb
@@ -25,11 +25,13 @@ shared_examples 'update invalid issuable' do |klass|
.and_raise(ActiveRecord::StaleObjectError.new(issuable, :save))
end
- it 'renders edit when format is html' do
- put :update, params
+ if klass == MergeRequest
+ it 'renders edit when format is html' do
+ put :update, params
- expect(response).to render_template(:edit)
- expect(assigns[:conflict]).to be_truthy
+ expect(response).to render_template(:edit)
+ expect(assigns[:conflict]).to be_truthy
+ end
end
it 'renders json error message when format is json' do
@@ -42,16 +44,17 @@ shared_examples 'update invalid issuable' do |klass|
end
end
- context 'when updating an invalid issuable' do
- before do
- key = klass == Issue ? :issue : :merge_request
- params[key][:title] = ""
- end
+ if klass == MergeRequest
+ context 'when updating an invalid issuable' do
+ before do
+ params[:merge_request][:title] = ""
+ end
- it 'renders edit when merge request is invalid' do
- put :update, params
+ it 'renders edit when merge request is invalid' do
+ put :update, params
- expect(response).to render_template(:edit)
+ expect(response).to render_template(:edit)
+ end
end
end
end
diff --git a/spec/views/projects/registry/repositories/index.html.haml_spec.rb b/spec/views/projects/registry/repositories/index.html.haml_spec.rb
deleted file mode 100644
index cf0aa44a4a2..00000000000
--- a/spec/views/projects/registry/repositories/index.html.haml_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require 'spec_helper'
-
-describe 'projects/registry/repositories/index' do
- let(:group) { create(:group, path: 'group') }
- let(:project) { create(:project, group: group, path: 'test') }
-
- let(:repository) do
- create(:container_repository, project: project, name: 'image')
- end
-
- before do
- stub_container_registry_config(enabled: true,
- host_port: 'registry.gitlab',
- api_url: 'http://registry.gitlab')
-
- stub_container_registry_tags(repository: :any, tags: [:latest])
-
- assign(:project, project)
- assign(:images, [repository])
-
- allow(view).to receive(:can?).and_return(true)
- end
-
- it 'contains container repository path' do
- render
-
- expect(rendered).to have_content 'group/test/image'
- end
-
- it 'contains attribute for copying tag location into clipboard' do
- render
-
- expect(rendered).to have_css 'button[data-clipboard-text="docker pull ' \
- 'registry.gitlab/group/test/image:latest"]'
- end
-end
diff --git a/spec/views/shared/issuable/_participants.html.haml.rb b/spec/views/shared/issuable/_participants.html.haml.rb
new file mode 100644
index 00000000000..51059d4c0d7
--- /dev/null
+++ b/spec/views/shared/issuable/_participants.html.haml.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+require 'nokogiri'
+
+describe 'shared/issuable/_participants.html.haml' do
+ let(:project) { create(:project) }
+ let(:participants) { create_list(:user, 100) }
+
+ before do
+ allow(view).to receive_messages(project: project,
+ participants: participants)
+ end
+
+ it 'renders lazy loaded avatars' do
+ render 'shared/issuable/participants'
+
+ html = Nokogiri::HTML(rendered)
+
+ avatars = html.css('.participants-author img')
+
+ avatars.each do |avatar|
+ expect(avatar[:class]).to include('lazy')
+ expect(avatar[:src]).to eql(LazyImageTagHelper.placeholder_image)
+ expect(avatar[:"data-src"]).to match('http://www.gravatar.com/avatar/')
+ end
+ end
+end
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index f7b67b8efc6..ab656d619f4 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -32,7 +32,7 @@ describe GitGarbageCollectWorker do
expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
- expect_any_instance_of(Gitlab::Git::Repository).to receive(:branch_count).and_call_original
+ expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original
subject.perform(project.id, :gc, lease_key, lease_uuid)
end
@@ -47,7 +47,6 @@ describe GitGarbageCollectWorker do
expect(subject).not_to receive(:command)
expect_any_instance_of(Repository).not_to receive(:after_create_branch).and_call_original
expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original
- expect_any_instance_of(Repository).not_to receive(:branch_count).and_call_original
expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original
subject.perform(project.id, :gc, lease_key, lease_uuid)
@@ -78,7 +77,7 @@ describe GitGarbageCollectWorker do
expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
- expect_any_instance_of(Gitlab::Git::Repository).to receive(:branch_count).and_call_original
+ expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original
subject.perform(project.id)
end
@@ -93,7 +92,6 @@ describe GitGarbageCollectWorker do
expect(subject).not_to receive(:command)
expect_any_instance_of(Repository).not_to receive(:after_create_branch).and_call_original
expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original
- expect_any_instance_of(Repository).not_to receive(:branch_count).and_call_original
expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original
subject.perform(project.id)
diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb
index d2609d21546..1d9bbf2ca62 100644
--- a/spec/workers/repository_check/single_repository_worker_spec.rb
+++ b/spec/workers/repository_check/single_repository_worker_spec.rb
@@ -69,7 +69,12 @@ describe RepositoryCheck::SingleRepositoryWorker do
end
def break_wiki(project)
- FileUtils.rm_rf(wiki_path(project) + '/objects')
+ objects_dir = wiki_path(project) + '/objects'
+
+ # Replace the /objects directory with a file so that the repo is
+ # invalid, _and_ 'git init' cannot fix it.
+ FileUtils.rm_rf(objects_dir)
+ FileUtils.touch(objects_dir) if File.directory?(wiki_path(project))
end
def wiki_path(project)
diff --git a/yarn.lock b/yarn.lock
index c95dd6433ca..ae86887630b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2714,7 +2714,7 @@ getpass@^0.1.1:
"gitlab-svgs@https://gitlab.com/gitlab-org/gitlab-svgs.git":
version "1.0.2"
- resolved "https://gitlab.com/gitlab-org/gitlab-svgs.git#7f36f3951dd08904761780da48efcd639f34c3af"
+ resolved "https://gitlab.com/gitlab-org/gitlab-svgs.git#e7621d7b028607ae9c69f8b496cd49b42fe607e4"
glob-base@^0.3.0:
version "0.3.0"