summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDJ Mountney <david@twkie.net>2017-09-06 16:09:20 -0700
committerDJ Mountney <david@twkie.net>2017-09-06 16:09:20 -0700
commitb373c56c7b2898fc0cac16a26a41c7019ab7ca3e (patch)
tree749c8661edb7cae36cae8f4eec548206b8a5ac5d
parentac38f36abe017dfe80a30c2e646a14c4c69c08b0 (diff)
parent21935d85382989e38dd4cc12de55966e0c9b6eba (diff)
downloadgitlab-ce-b373c56c7b2898fc0cac16a26a41c7019ab7ca3e.tar.gz
Merge remote-tracking branch 'origin/master' into dev-master
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--PROCESS.md22
-rw-r--r--app/assets/javascripts/breadcrumb.js28
-rw-r--r--app/assets/javascripts/dispatcher.js7
-rw-r--r--app/assets/javascripts/group_name.js76
-rw-r--r--app/assets/javascripts/issuable_bulk_update_sidebar.js25
-rw-r--r--app/assets/javascripts/layout_nav.js15
-rw-r--r--app/assets/javascripts/main.js3
-rw-r--r--app/assets/javascripts/new_sidebar.js2
-rw-r--r--app/assets/javascripts/right_sidebar.js2
-rw-r--r--app/assets/javascripts/sidebar_height_manager.js37
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss1
-rw-r--r--app/assets/stylesheets/new_nav.scss153
-rw-r--r--app/assets/stylesheets/new_sidebar.scss5
-rw-r--r--app/assets/stylesheets/pages/boards.scss1
-rw-r--r--app/assets/stylesheets/pages/commits.scss6
-rw-r--r--app/assets/stylesheets/pages/notes.scss18
-rw-r--r--app/controllers/admin/logs_controller.rb9
-rw-r--r--app/controllers/concerns/renders_commits.rb7
-rw-r--r--app/controllers/concerns/renders_notes.rb9
-rw-r--r--app/controllers/profiles_controller.rb2
-rw-r--r--app/controllers/projects/artifacts_controller.rb12
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/commits_controller.rb3
-rw-r--r--app/controllers/projects/compare_controller.rb3
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb3
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb9
-rw-r--r--app/controllers/projects/snippets_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/controllers/search_controller.rb7
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/helpers/application_helper.rb4
-rw-r--r--app/helpers/blame_helper.rb16
-rw-r--r--app/helpers/breadcrumbs_helper.rb12
-rw-r--r--app/helpers/groups_helper.rb28
-rw-r--r--app/helpers/issuables_helper.rb19
-rw-r--r--app/helpers/markup_helper.rb30
-rw-r--r--app/helpers/nav_helper.rb21
-rw-r--r--app/helpers/notes_helper.rb6
-rw-r--r--app/helpers/page_layout_helper.rb6
-rw-r--r--app/helpers/profiles_helper.rb13
-rw-r--r--app/helpers/projects_helper.rb15
-rw-r--r--app/helpers/search_helper.rb11
-rw-r--r--app/helpers/wiki_helper.rb11
-rw-r--r--app/models/ci/build.rb5
-rw-r--r--app/models/ci/pipeline.rb1
-rw-r--r--app/models/commit.rb9
-rw-r--r--app/models/concerns/issuable.rb7
-rw-r--r--app/models/concerns/resolvable_discussion.rb1
-rw-r--r--app/models/concerns/resolvable_note.rb28
-rw-r--r--app/models/merge_request.rb12
-rw-r--r--app/models/note.rb35
-rw-r--r--app/models/project.rb1
-rw-r--r--app/models/project_team.rb2
-rw-r--r--app/models/user.rb22
-rw-r--r--app/models/user_synced_attributes_metadata.rb25
-rw-r--r--app/services/discussions/update_diff_position_service.rb4
-rw-r--r--app/services/users/update_service.rb4
-rw-r--r--app/views/admin/applications/edit.html.haml2
-rw-r--r--app/views/admin/cohorts/index.html.haml1
-rw-r--r--app/views/admin/dashboard/index.html.haml1
-rw-r--r--app/views/admin/groups/show.html.haml2
-rw-r--r--app/views/admin/hooks/edit.html.haml1
-rw-r--r--app/views/admin/jobs/index.html.haml1
-rw-r--r--app/views/admin/labels/edit.html.haml2
-rw-r--r--app/views/admin/projects/show.html.haml2
-rw-r--r--app/views/admin/runners/index.html.haml1
-rw-r--r--app/views/admin/services/edit.html.haml2
-rw-r--r--app/views/admin/users/show.html.haml2
-rw-r--r--app/views/ci/variables/_content.html.haml12
-rw-r--r--app/views/ci/variables/_index.html.haml4
-rw-r--r--app/views/ci/variables/_show.html.haml2
-rw-r--r--app/views/dashboard/_groups_head.html.haml6
-rw-r--r--app/views/dashboard/_projects_head.html.haml6
-rw-r--r--app/views/dashboard/_snippets_head.html.haml6
-rw-r--r--app/views/dashboard/issues.html.haml11
-rw-r--r--app/views/dashboard/merge_requests.html.haml7
-rw-r--r--app/views/dashboard/milestones/index.html.haml7
-rw-r--r--app/views/discussions/_headline.html.haml4
-rw-r--r--app/views/groups/edit.html.haml1
-rw-r--r--app/views/groups/issues.html.haml4
-rw-r--r--app/views/groups/labels/index.html.haml4
-rw-r--r--app/views/groups/merge_requests.html.haml4
-rw-r--r--app/views/groups/milestones/index.html.haml4
-rw-r--r--app/views/groups/projects.html.haml1
-rw-r--r--app/views/groups/settings/ci_cd/show.html.haml3
-rw-r--r--app/views/groups/show.html.haml2
-rw-r--r--app/views/groups/subgroups.html.haml1
-rw-r--r--app/views/layouts/_head.html.haml6
-rw-r--r--app/views/layouts/_page.html.haml26
-rw-r--r--app/views/layouts/admin.html.haml7
-rw-r--r--app/views/layouts/application.html.haml5
-rw-r--r--app/views/layouts/group.html.haml7
-rw-r--r--app/views/layouts/header/_default.html.haml70
-rw-r--r--app/views/layouts/header/_new.html.haml79
-rw-r--r--app/views/layouts/header/_new_dropdown.haml8
-rw-r--r--app/views/layouts/nav/_admin.html.haml40
-rw-r--r--app/views/layouts/nav/_admin_settings.html.haml31
-rw-r--r--app/views/layouts/nav/_breadcrumbs.html.haml26
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml123
-rw-r--r--app/views/layouts/nav/_explore.html.haml30
-rw-r--r--app/views/layouts/nav/_group.html.haml31
-rw-r--r--app/views/layouts/nav/_new_dashboard.html.haml62
-rw-r--r--app/views/layouts/nav/_new_explore.html.haml12
-rw-r--r--app/views/layouts/nav/_profile.html.haml57
-rw-r--r--app/views/layouts/nav/_project.html.haml111
-rw-r--r--app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml11
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml (renamed from app/views/layouts/nav/_new_admin_sidebar.html.haml)0
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml (renamed from app/views/layouts/nav/_new_group_sidebar.html.haml)0
-rw-r--r--app/views/layouts/nav/sidebar/_profile.html.haml (renamed from app/views/layouts/nav/_new_profile_sidebar.html.haml)0
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml (renamed from app/views/layouts/nav/_new_project_sidebar.html.haml)0
-rw-r--r--app/views/layouts/profile.html.haml7
-rw-r--r--app/views/layouts/project.html.haml7
-rw-r--r--app/views/profiles/passwords/edit.html.haml1
-rw-r--r--app/views/profiles/personal_access_tokens/index.html.haml1
-rw-r--r--app/views/profiles/show.html.haml18
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml5
-rw-r--r--app/views/projects/_flash_messages.html.haml3
-rw-r--r--app/views/projects/_merge_request_merge_settings.html.haml4
-rw-r--r--app/views/projects/activity.html.haml4
-rw-r--r--app/views/projects/artifacts/browse.html.haml4
-rw-r--r--app/views/projects/blame/show.html.haml2
-rw-r--r--app/views/projects/boards/_show.html.haml4
-rw-r--r--app/views/projects/branches/_commit.html.haml2
-rw-r--r--app/views/projects/branches/index.html.haml3
-rw-r--r--app/views/projects/commit/show.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml5
-rw-r--r--app/views/projects/commits/_inline_commit.html.haml2
-rw-r--r--app/views/projects/commits/show.html.haml3
-rw-r--r--app/views/projects/compare/index.html.haml3
-rw-r--r--app/views/projects/compare/show.html.haml4
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml2
-rw-r--r--app/views/projects/deployments/_commit.html.haml2
-rw-r--r--app/views/projects/edit.html.haml1
-rw-r--r--app/views/projects/empty.html.haml1
-rw-r--r--app/views/projects/environments/index.html.haml4
-rw-r--r--app/views/projects/environments/show.html.haml2
-rw-r--r--app/views/projects/graphs/charts.html.haml2
-rw-r--r--app/views/projects/graphs/show.html.haml3
-rw-r--r--app/views/projects/issues/index.html.haml7
-rw-r--r--app/views/projects/issues/show.html.haml2
-rw-r--r--app/views/projects/jobs/index.html.haml3
-rw-r--r--app/views/projects/jobs/show.html.haml2
-rw-r--r--app/views/projects/labels/index.html.haml4
-rw-r--r--app/views/projects/merge_requests/index.html.haml7
-rw-r--r--app/views/projects/merge_requests/show.html.haml2
-rw-r--r--app/views/projects/milestones/index.html.haml6
-rw-r--r--app/views/projects/milestones/show.html.haml2
-rw-r--r--app/views/projects/network/show.html.haml2
-rw-r--r--app/views/projects/notes/_actions.html.haml8
-rw-r--r--app/views/projects/notes/_more_actions_dropdown.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/edit.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/index.html.haml8
-rw-r--r--app/views/projects/pipeline_schedules/new.html.haml3
-rw-r--r--app/views/projects/pipelines/charts.html.haml3
-rw-r--r--app/views/projects/pipelines/show.html.haml2
-rw-r--r--app/views/projects/pipelines_settings/_badge.html.haml62
-rw-r--r--app/views/projects/pipelines_settings/_show.html.haml5
-rw-r--r--app/views/projects/project_members/index.html.haml3
-rw-r--r--app/views/projects/releases/edit.html.haml2
-rw-r--r--app/views/projects/services/edit.html.haml4
-rw-r--r--app/views/projects/settings/ci_cd/show.html.haml58
-rw-r--r--app/views/projects/settings/integrations/show.html.haml3
-rw-r--r--app/views/projects/settings/repository/show.html.haml4
-rw-r--r--app/views/projects/show.html.haml2
-rw-r--r--app/views/projects/snippets/edit.html.haml2
-rw-r--r--app/views/projects/snippets/index.html.haml4
-rw-r--r--app/views/projects/snippets/new.html.haml2
-rw-r--r--app/views/projects/snippets/show.html.haml2
-rw-r--r--app/views/projects/tags/index.html.haml4
-rw-r--r--app/views/projects/tags/show.html.haml2
-rw-r--r--app/views/projects/tree/_tree_commit_column.html.haml2
-rw-r--r--app/views/projects/triggers/_content.html.haml10
-rw-r--r--app/views/projects/triggers/_index.html.haml3
-rw-r--r--app/views/projects/wikis/pages.html.haml2
-rw-r--r--app/views/projects/wikis/show.html.haml7
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/views/shared/notes/_note.html.haml4
-rw-r--r--app/views/shared/projects/_project.html.haml3
-rw-r--r--app/views/shared/snippets/_header.html.haml4
-rw-r--r--app/views/snippets/show.html.haml2
-rw-r--r--changelogs/unreleased/12968-generalize-profile-updates.yml4
-rw-r--r--changelogs/unreleased/19650-remove-admin-section-from-search-results-if-user-doesnt-have-access.yml5
-rw-r--r--changelogs/unreleased/34509-improves-markdown-rendering-performance-for-commits-list.yml5
-rw-r--r--changelogs/unreleased/35161_first_time_contributor_badge.yml4
-rw-r--r--changelogs/unreleased/35441-fix-division-by-zero.yml5
-rw-r--r--changelogs/unreleased/35942-api-binary-encoding.yaml3
-rw-r--r--changelogs/unreleased/36859-update-gpg-docs-with-gpg2.yml5
-rw-r--r--changelogs/unreleased/36994-toggle-for-automatically-collapsing-outdated-diff-comments.yml5
-rw-r--r--changelogs/unreleased/collapsable-pipeline-settings.yml5
-rw-r--r--changelogs/unreleased/feature-gb-download-single-job-artifact-using-api.yml5
-rw-r--r--changelogs/unreleased/fix-import-export-performance.yml5
-rw-r--r--changelogs/unreleased/fix_wiki_toc_indent.yml5
-rw-r--r--changelogs/unreleased/url-sanitizer-fixes.yml5
-rw-r--r--changelogs/unreleased/winh-dropdown-changelog-docs.yml5
-rw-r--r--config/gitlab.yml.example13
-rw-r--r--config/initializers/1_settings.rb15
-rw-r--r--config/initializers/8_metrics.rb3
-rw-r--r--db/migrate/20170820120108_create_user_synced_attributes_metadata.rb15
-rw-r--r--db/migrate/20170825104051_migrate_issues_to_ghost_user.rb1
-rw-r--r--db/migrate/20170825154015_resolve_outdated_diff_discussions.rb9
-rw-r--r--db/migrate/20170828135939_migrate_user_external_mail_data.rb57
-rw-r--r--db/migrate/20170905112933_add_resolved_by_push_to_notes.rb9
-rw-r--r--db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb57
-rw-r--r--db/post_migrate/20170828170513_remove_user_email_provider_column.rb12
-rw-r--r--db/post_migrate/20170828170516_remove_user_external_mail_columns.rb12
-rw-r--r--db/schema.rb17
-rw-r--r--doc/administration/monitoring/performance/performance_bar.md16
-rw-r--r--doc/api/README.md4
-rw-r--r--doc/api/environments.md2
-rw-r--r--doc/api/jobs.md38
-rw-r--r--doc/api/project_snippets.md3
-rw-r--r--doc/api/projects.md239
-rw-r--r--doc/api/users.md15
-rw-r--r--doc/integration/omniauth.md18
-rw-r--r--doc/user/discussions/img/automatically_resolve_outdated_discussions.pngbin0 -> 117604 bytes
-rw-r--r--doc/user/discussions/index.md18
-rw-r--r--doc/user/project/import/cvs.md68
-rw-r--r--doc/user/project/import/index.md8
-rw-r--r--doc/user/project/import/tfs.md42
-rw-r--r--doc/user/project/integrations/prometheus_library/kubernetes.md2
-rw-r--r--doc/user/project/repository/gpg_signed_commits/index.md10
-rw-r--r--features/steps/explore/projects.rb4
-rw-r--r--features/steps/project/redirects.rb2
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/commits.rb2
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/helpers.rb18
-rw-r--r--lib/api/helpers/internal_helpers.rb9
-rw-r--r--lib/api/internal.rb11
-rw-r--r--lib/api/job_artifacts.rb80
-rw-r--r--lib/api/jobs.rb78
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/api/v3/entities.rb1
-rw-r--r--lib/api/v3/projects.rb7
-rw-r--r--lib/banzai/commit_renderer.rb11
-rw-r--r--lib/banzai/filter/table_of_contents_filter.rb90
-rw-r--r--lib/banzai/object_renderer.rb2
-rw-r--r--lib/banzai/renderer.rb4
-rw-r--r--lib/github/representation/branch.rb2
-rw-r--r--lib/gitlab/access.rb6
-rw-r--r--lib/gitlab/ci/build/artifacts/metadata/entry.rb244
-rw-r--r--lib/gitlab/ci/build/artifacts/path.rb51
-rw-r--r--lib/gitlab/encoding_helper.rb17
-rw-r--r--lib/gitlab/git/blob.rb12
-rw-r--r--lib/gitlab/git/diff.rb16
-rw-r--r--lib/gitlab/git/repository.rb37
-rw-r--r--lib/gitlab/gitaly_client/ref_service.rb40
-rw-r--r--lib/gitlab/github_import/importer.rb2
-rw-r--r--lib/gitlab/import_export/import_export.yml1
-rw-r--r--lib/gitlab/import_export/project_tree_restorer.rb79
-rw-r--r--lib/gitlab/import_export/shared.rb2
-rw-r--r--lib/gitlab/ldap/user.rb4
-rw-r--r--lib/gitlab/o_auth/auth_hash.rb17
-rw-r--r--lib/gitlab/o_auth/user.rb32
-rw-r--r--lib/gitlab/saml/user.rb2
-rw-r--r--lib/gitlab/url_sanitizer.rb19
-rw-r--r--lib/gitlab/workhorse.rb4
-rw-r--r--locale/bg/gitlab.po191
-rw-r--r--locale/de/gitlab.po895
-rw-r--r--locale/en/gitlab.po48
-rw-r--r--locale/eo/gitlab.po191
-rw-r--r--locale/es/gitlab.po191
-rw-r--r--locale/fr/gitlab.po191
-rw-r--r--locale/gitlab.pot198
-rw-r--r--locale/it/gitlab.po191
-rw-r--r--locale/ja/gitlab.po191
-rw-r--r--locale/ko/gitlab.po279
-rw-r--r--locale/pt_BR/gitlab.po191
-rw-r--r--locale/ru/gitlab.po207
-rw-r--r--locale/uk/gitlab.po191
-rw-r--r--locale/zh_CN/gitlab.po285
-rw-r--r--locale/zh_HK/gitlab.po285
-rw-r--r--locale/zh_TW/gitlab.po287
-rw-r--r--spec/controllers/profiles_controller_spec.rb25
-rw-r--r--spec/controllers/projects/artifacts_controller_spec.rb8
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb22
-rw-r--r--spec/features/admin/admin_browses_logs_spec.rb8
-rw-r--r--spec/features/issues/form_spec.rb6
-rw-r--r--spec/features/merge_requests/diff_notes_avatars_spec.rb4
-rw-r--r--spec/features/merge_requests/form_spec.rb7
-rw-r--r--spec/features/merge_requests/resolve_outdated_diff_discussions.rb78
-rw-r--r--spec/features/projects/sub_group_issuables_spec.rb3
-rw-r--r--spec/helpers/blame_helper_spec.rb27
-rw-r--r--spec/helpers/groups_helper_spec.rb3
-rw-r--r--spec/helpers/markup_helper_spec.rb91
-rw-r--r--spec/helpers/notes_helper_spec.rb32
-rw-r--r--spec/helpers/profiles_helper_spec.rb31
-rw-r--r--spec/helpers/search_helper_spec.rb20
-rw-r--r--spec/lib/banzai/commit_renderer_spec.rb19
-rw-r--r--spec/lib/banzai/filter/table_of_contents_filter_spec.rb36
-rw-r--r--spec/lib/banzai/object_renderer_spec.rb90
-rw-r--r--spec/lib/banzai/renderer_spec.rb36
-rw-r--r--spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/path_spec.rb64
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb19
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb85
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb19
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml3
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb19
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb190
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb179
-rw-r--r--spec/models/concerns/issuable_spec.rb67
-rw-r--r--spec/models/concerns/resolvable_note_spec.rb16
-rw-r--r--spec/models/merge_request_spec.rb38
-rw-r--r--spec/models/user_spec.rb66
-rw-r--r--spec/requests/api/commits_spec.rb6
-rw-r--r--spec/requests/api/internal_spec.rb31
-rw-r--r--spec/requests/api/jobs_spec.rb94
-rw-r--r--spec/requests/api/projects_spec.rb58
-rw-r--r--spec/requests/api/v3/projects_spec.rb1
-rw-r--r--spec/services/ci/retry_build_service_spec.rb11
-rw-r--r--spec/services/discussions/update_diff_position_service_spec.rb62
-rw-r--r--spec/support/seed_helper.rb2
-rw-r--r--spec/support/test_env.rb18
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb (renamed from spec/views/layouts/nav/_project.html.haml_spec.rb)6
321 files changed, 6549 insertions, 2793 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 778d33fb960..70b0cde17ea 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -43,6 +43,7 @@ stages:
# Predefined scopes
.dedicated-runner: &dedicated-runner
+ retry: 1
tags:
- gitlab-org
@@ -411,7 +412,6 @@ db:migrate:reset-mysql:
.migration-paths: &migration-paths
<<: *dedicated-runner
- <<: *only-canonical-masters
<<: *pull-cache
stage: test
variables:
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 0f1a7dfc7c4..ca75280b09b 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.37.0
+0.38.0
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 11d9efa3d5a..b3d91f9cfc0 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-5.8.0
+5.9.0
diff --git a/PROCESS.md b/PROCESS.md
index 538e4389e00..ed4e84dd0b6 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -199,26 +199,8 @@ available in the package repositories.
## Release retrospective and kickoff
-### Retrospective
-
-After each release, we have a retrospective call where we discuss what went well,
-what went wrong, and what we can improve for the next release. The
-[retrospective notes] are public and you are invited to comment on them.
-If you're interested, you can even join the
-[retrospective call][retro-kickoff-call], on the first working day after the
-22nd at 6pm CET / 9am PST.
-
-### Kickoff
-
-Before working on the next release, we have a
-kickoff call to explain what we expect to ship in the next release. The
-[kickoff notes] are public and you are invited to comment on them.
-If you're interested, you can even join the [kickoff call][retro-kickoff-call],
-on the first working day after the 7th at 6pm CET / 9am PST..
-
-[retrospective notes]: https://docs.google.com/document/d/1nEkM_7Dj4bT21GJy0Ut3By76FZqCfLBmFQNVThmW2TY/edit?usp=sharing
-[kickoff notes]: https://docs.google.com/document/d/1ElPkZ90A8ey_iOkTvUs_ByMlwKK6NAB2VOK5835wYK0/edit?usp=sharing
-[retro-kickoff-call]: https://gitlab.zoom.us/j/918821206
+- [Retrospective](https://about.gitlab.com/handbook/engineering/workflow/#retrospective)
+- [Kickoff](https://about.gitlab.com/handbook/engineering/workflow/#kickoff)
## Copy & paste responses
diff --git a/app/assets/javascripts/breadcrumb.js b/app/assets/javascripts/breadcrumb.js
new file mode 100644
index 00000000000..10fbcfe96cf
--- /dev/null
+++ b/app/assets/javascripts/breadcrumb.js
@@ -0,0 +1,28 @@
+export const addTooltipToEl = (el) => {
+ const textEl = el.querySelector('.js-breadcrumb-item-text');
+
+ if (textEl && textEl.scrollWidth > textEl.offsetWidth) {
+ el.setAttribute('title', el.textContent);
+ el.setAttribute('data-container', 'body');
+ el.classList.add('has-tooltip');
+ }
+};
+
+export default () => {
+ const breadcrumbs = document.querySelector('.js-breadcrumbs-list');
+
+ if (breadcrumbs) {
+ const topLevelLinks = [...breadcrumbs.children].filter(el => !el.classList.contains('dropdown'))
+ .map(el => el.querySelector('a'))
+ .filter(el => el);
+ const $expander = $('.js-breadcrumbs-collapsed-expander');
+
+ topLevelLinks.forEach(el => addTooltipToEl(el));
+
+ $expander.closest('.dropdown')
+ .on('show.bs.dropdown hide.bs.dropdown', (e) => {
+ $('.js-breadcrumbs-collapsed-expander', e.currentTarget).toggleClass('open')
+ .tooltip('hide');
+ });
+ }
+};
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 3dec4de06ec..6db0b18ae5a 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -41,7 +41,6 @@ import Issue from './issue';
import BindInOut from './behaviors/bind_in_out';
import DeleteModal from './branches/branches_delete_modal';
import Group from './group';
-import GroupName from './group_name';
import GroupsList from './groups_list';
import ProjectsList from './projects_list';
import setupProjectEdit from './project_edit';
@@ -489,6 +488,8 @@ import initChangesDropdown from './init_changes_dropdown';
initSettingsPanels();
break;
case 'projects:settings:ci_cd:show':
+ // Initialize expandable settings panels
+ initSettingsPanels();
case 'groups:settings:ci_cd:show':
new gl.ProjectVariables();
break;
@@ -554,9 +555,6 @@ import initChangesDropdown from './init_changes_dropdown';
case 'root':
new UserCallout();
break;
- case 'groups':
- new GroupName();
- break;
case 'profiles':
new NotificationsForm();
new NotificationsDropdown();
@@ -564,7 +562,6 @@ import initChangesDropdown from './init_changes_dropdown';
case 'projects':
new Project();
new ProjectAvatar();
- new GroupName();
switch (path[1]) {
case 'compare':
new CompareAutocomplete();
diff --git a/app/assets/javascripts/group_name.js b/app/assets/javascripts/group_name.js
deleted file mode 100644
index 3e483b69fd2..00000000000
--- a/app/assets/javascripts/group_name.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import Cookies from 'js-cookie';
-import _ from 'underscore';
-
-export default class GroupName {
- constructor() {
- this.titleContainer = document.querySelector('.js-title-container');
- this.title = this.titleContainer.querySelector('.title');
-
- if (this.title) {
- this.titleWidth = this.title.offsetWidth;
- this.groupTitle = this.titleContainer.querySelector('.group-title');
- this.groups = this.titleContainer.querySelectorAll('.group-path');
- this.toggle = null;
- this.isHidden = false;
- this.init();
- }
- }
-
- init() {
- if (this.groups.length > 0) {
- this.groups[this.groups.length - 1].classList.remove('hidable');
- this.toggleHandler();
- window.addEventListener('resize', _.debounce(this.toggleHandler.bind(this), 100));
- }
- this.render();
- }
-
- toggleHandler() {
- if (this.titleWidth > this.titleContainer.offsetWidth) {
- if (!this.toggle) this.createToggle();
- this.showToggle();
- } else if (this.toggle) {
- this.hideToggle();
- }
- }
-
- createToggle() {
- this.toggle = document.createElement('button');
- this.toggle.setAttribute('type', 'button');
- this.toggle.className = 'text-expander group-name-toggle';
- this.toggle.setAttribute('aria-label', 'Toggle full path');
- if (Cookies.get('new_nav') === 'true') {
- this.toggle.innerHTML = '<i class="fa fa-ellipsis-h" aria-hidden="true"></i>';
- } else {
- this.toggle.innerHTML = '...';
- }
- this.toggle.addEventListener('click', this.toggleGroups.bind(this));
- if (Cookies.get('new_nav') === 'true') {
- this.title.insertBefore(this.toggle, this.groupTitle);
- } else {
- this.titleContainer.insertBefore(this.toggle, this.title);
- }
- this.toggleGroups();
- }
-
- showToggle() {
- this.title.classList.add('wrap');
- this.toggle.classList.remove('hidden');
- if (this.isHidden) this.groupTitle.classList.add('hidden');
- }
-
- hideToggle() {
- this.title.classList.remove('wrap');
- this.toggle.classList.add('hidden');
- if (this.isHidden) this.groupTitle.classList.remove('hidden');
- }
-
- toggleGroups() {
- this.isHidden = !this.isHidden;
- this.groupTitle.classList.toggle('hidden');
- }
-
- render() {
- this.title.classList.remove('initializing');
- }
-}
diff --git a/app/assets/javascripts/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable_bulk_update_sidebar.js
index d314f3c4d43..0e8a0519928 100644
--- a/app/assets/javascripts/issuable_bulk_update_sidebar.js
+++ b/app/assets/javascripts/issuable_bulk_update_sidebar.js
@@ -5,7 +5,6 @@
/* global SubscriptionSelect */
import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
-import SidebarHeightManager from './sidebar_height_manager';
const HIDDEN_CLASS = 'hidden';
const DISABLED_CONTENT_CLASS = 'disabled-content';
@@ -50,13 +49,6 @@ export default class IssuableBulkUpdateSidebar {
new SubscriptionSelect();
}
- getNavHeight() {
- const navbarHeight = $('.navbar-gitlab').outerHeight();
- const layoutNavHeight = $('.layout-nav').outerHeight();
- const subNavScroll = $('.sub-nav-scroll').outerHeight();
- return navbarHeight + layoutNavHeight + subNavScroll;
- }
-
setupBulkUpdateActions() {
IssuableBulkUpdateActions.setOriginalDropdownData();
}
@@ -84,23 +76,6 @@ export default class IssuableBulkUpdateSidebar {
this.toggleBulkEditButtonDisabled(enable);
this.toggleOtherFiltersDisabled(enable);
this.toggleCheckboxDisplay(enable);
-
- if (enable) {
- this.initAffix();
- SidebarHeightManager.init();
- }
- }
-
- initAffix() {
- if (!this.$sidebar.hasClass('affix-top')) {
- const offsetTop = $('.scrolling-tabs-container').outerHeight() + $('.sub-nav-scroll').outerHeight();
-
- this.$sidebar.affix({
- offset: {
- top: offsetTop,
- },
- });
- }
}
updateSelectedIssuableIds() {
diff --git a/app/assets/javascripts/layout_nav.js b/app/assets/javascripts/layout_nav.js
index 5c1ba416a03..d064a2c0024 100644
--- a/app/assets/javascripts/layout_nav.js
+++ b/app/assets/javascripts/layout_nav.js
@@ -50,19 +50,10 @@ import initFlyOutNav from './fly_out_nav';
});
});
- function applyScrollNavClass() {
- const scrollOpacityHeight = 40;
- $('.navbar-border').css('opacity', Math.min($(window).scrollTop() / scrollOpacityHeight, 1));
- }
-
$(() => {
- if (Cookies.get('new_nav') === 'true') {
- const newNavSidebar = new NewNavSidebar();
- newNavSidebar.bindEvents();
-
- initFlyOutNav();
- }
+ const newNavSidebar = new NewNavSidebar();
+ newNavSidebar.bindEvents();
- $(window).on('scroll', _.throttle(applyScrollNavClass, 100));
+ initFlyOutNav();
});
}).call(window);
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index f14458c8d41..0bc31a56684 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -144,6 +144,7 @@ import './smart_interval';
import './star';
import './subscription';
import './subscription_select';
+import initBreadcrumbs from './breadcrumb';
import './dispatcher';
@@ -181,6 +182,8 @@ $(function () {
var bootstrapBreakpoint = bp.getBreakpointSize();
var fitSidebarForSize;
+ initBreadcrumbs();
+
// Set the default path for all cookies to GitLab's root directory
Cookies.defaults.path = gon.relative_url_root || '/';
diff --git a/app/assets/javascripts/new_sidebar.js b/app/assets/javascripts/new_sidebar.js
index 05e3f33f5ed..709a5d33b9f 100644
--- a/app/assets/javascripts/new_sidebar.js
+++ b/app/assets/javascripts/new_sidebar.js
@@ -63,7 +63,7 @@ export default class NewNavSidebar {
if (breakpoint === 'sm' || breakpoint === 'md') {
this.toggleCollapsedSidebar(true);
} else if (breakpoint === 'lg') {
- const collapse = Cookies.get('sidebar_collapsed') === 'true';
+ const collapse = this.$sidebar.hasClass('sidebar-icons-only');
this.toggleCollapsedSidebar(collapse);
}
}
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 4c87d46c96e..a4eae135403 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -2,7 +2,6 @@
import _ from 'underscore';
import Cookies from 'js-cookie';
-import SidebarHeightManager from './sidebar_height_manager';
(function() {
this.Sidebar = (function() {
@@ -23,7 +22,6 @@ import SidebarHeightManager from './sidebar_height_manager';
};
Sidebar.prototype.addEventListeners = function() {
- SidebarHeightManager.init();
const $document = $(document);
this.sidebar.on('click', '.sidebar-collapsed-icon', this, this.sidebarCollapseClicked);
diff --git a/app/assets/javascripts/sidebar_height_manager.js b/app/assets/javascripts/sidebar_height_manager.js
deleted file mode 100644
index 2752fe2b911..00000000000
--- a/app/assets/javascripts/sidebar_height_manager.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import _ from 'underscore';
-import Cookies from 'js-cookie';
-
-export default {
- init() {
- if (!this.initialized) {
- if (Cookies.get('new_nav') === 'true' && $('.js-issuable-sidebar').length) return;
-
- this.$window = $(window);
- this.$rightSidebar = $('.js-right-sidebar');
- this.$navHeight = $('.navbar-gitlab').outerHeight() +
- $('.layout-nav').outerHeight() +
- $('.sub-nav-scroll').outerHeight();
-
- const throttledSetSidebarHeight = _.throttle(() => this.setSidebarHeight(), 20);
- const debouncedSetSidebarHeight = _.debounce(() => this.setSidebarHeight(), 200);
-
- this.$window.on('scroll', throttledSetSidebarHeight);
- this.$window.on('resize', debouncedSetSidebarHeight);
- this.initialized = true;
- }
- },
-
- setSidebarHeight() {
- const currentScrollDepth = window.pageYOffset || 0;
- const diff = this.$navHeight - currentScrollDepth;
-
- if (diff > 0) {
- const newSidebarHeight = window.innerHeight - diff;
- this.$rightSidebar.outerHeight(newSidebarHeight);
- this.sidebarHeightIsCustom = true;
- } else if (this.sidebarHeightIsCustom) {
- this.$rightSidebar.outerHeight('100%');
- this.sidebarHeightIsCustom = false;
- }
- },
-};
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 6b21def33a6..5f397f08936 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -829,6 +829,7 @@
}
}
+@include new-style-dropdown('.breadcrumbs-list .dropdown ');
@include new-style-dropdown('.js-namespace-select + ');
header.navbar-gitlab-new .header-content .dropdown-menu.projects-dropdown-menu {
diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss
index 4deb7431284..e4b52ab480d 100644
--- a/app/assets/stylesheets/new_nav.scss
+++ b/app/assets/stylesheets/new_nav.scss
@@ -1,6 +1,7 @@
@import "framework/variables";
@import 'framework/tw_bootstrap_variables';
@import "bootstrap/variables";
+@import "framework/mixins";
.content-wrapper.page-with-new-nav {
margin-top: $new-navbar-height;
@@ -422,109 +423,38 @@ header.navbar-gitlab-new {
.breadcrumbs {
display: flex;
- min-height: 61px;
+ min-height: 48px;
color: $gl-text-color;
- border-bottom: 1px solid $border-color;
-
- .dropdown-toggle-caret {
- position: relative;
- top: -1px;
- padding: 0 5px;
- color: $gl-text-color-secondary;
- font-size: 10px;
- line-height: 1;
- background: none;
- border: 0;
-
- &:focus {
- outline: 0;
- }
- }
-
- // TODO: fallback to global style
- .dropdown-menu {
- .divider {
- margin: 6px 0;
- }
-
- li {
- padding: 0 1px;
-
- a {
- border-radius: 0;
- padding: 8px 16px;
-
- &.is-focused,
- &:hover,
- &:active,
- &:focus {
- background-color: $gray-darker;
- }
- }
- }
- }
}
.breadcrumbs-container {
+ display: -webkit-flex;
display: flex;
width: 100%;
position: relative;
+ padding-top: $gl-padding;
+ padding-bottom: $gl-padding;
align-items: center;
-
- .dropdown-menu-projects {
- margin-top: -$gl-padding;
- margin-left: $gl-padding;
- }
+ border-bottom: 1px solid $border-color;
}
.breadcrumbs-links {
+ -webkit-flex: 1;
flex: 1;
min-width: 0;
align-self: center;
- color: $gl-text-color-quaternary;
-
- a {
- color: $gl-text-color-secondary;
-
- &:not(:first-child),
- &.group-path {
- margin-left: 4px;
- }
-
- &:not(:last-of-type),
- &.group-path {
- margin-right: 3px;
- }
- }
-
- .title {
- display: inline-block;
-
- > a {
- &:last-of-type:not(:first-child) {
- font-weight: $gl-font-weight-bold;
- }
- }
- }
+ color: $gl-text-color-secondary;
.avatar-tile {
- margin-right: 5px;
+ margin-right: 4px;
border: 1px solid $border-color;
border-radius: 50%;
vertical-align: sub;
-
- &.identicon {
- float: left;
- width: 16px;
- height: 16px;
- margin-top: 2px;
- font-size: 10px;
- }
}
.text-expander {
- margin-left: 4px;
- margin-right: 4px;
+ margin-left: 0;
+ margin-right: 2px;
> i {
position: relative;
@@ -533,37 +463,52 @@ header.navbar-gitlab-new {
}
}
-.breadcrumbs-extra {
+.breadcrumbs-list {
+ display: -webkit-flex;
display: flex;
- flex: 0 0 auto;
- margin-left: auto;
-}
+ flex-wrap: wrap;
+ margin-bottom: 0;
+ line-height: 16px;
-.breadcrumbs-sub-title {
- margin: 2px 0;
- font-size: 16px;
- font-weight: $gl-font-weight-normal;
- line-height: 1;
-
- ul {
- margin: 0;
- }
-
- li {
- display: inline-block;
+ > li {
+ display: flex;
+ align-items: center;
+ position: relative;
&:not(:last-child) {
- &::after {
- content: "/";
- margin: 0 2px 0 5px;
- color: rgba($black, .65);
- }
+ margin-right: 20px;
}
- &:last-child a {
- font-weight: $gl-font-weight-bold;
+ > a {
+ font-size: 12px;
+ color: currentColor;
}
}
+}
+
+.breadcrumb-item-text {
+ @include str-truncated(128px);
+}
+
+.breadcrumbs-list-angle {
+ position: absolute;
+ right: -12px;
+ top: 50%;
+ color: $gl-text-color-tertiary;
+ transform: translateY(-50%);
+}
+
+.breadcrumbs-extra {
+ display: flex;
+ flex: 0 0 auto;
+ margin-left: auto;
+}
+
+.breadcrumbs-sub-title {
+ margin: 0;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: 1;
a {
color: $gl-text-color;
diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss
index 90b0a543c5c..fd5e344d8c9 100644
--- a/app/assets/stylesheets/new_sidebar.scss
+++ b/app/assets/stylesheets/new_sidebar.scss
@@ -45,7 +45,6 @@ $new-sidebar-collapsed-width: 50px;
margin-right: 2px;
a {
- border-bottom: 1px solid $border-color;
font-weight: $gl-font-weight-bold;
display: flex;
align-items: center;
@@ -389,6 +388,10 @@ $new-sidebar-collapsed-width: 50px;
}
}
+ .nav-icon-container {
+ margin-right: 0;
+ }
+
.toggle-sidebar-button {
width: $new-sidebar-collapsed-width - 2px;
padding: 16px 18px;
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
index 0f3074076ce..314dd2d1a21 100644
--- a/app/assets/stylesheets/pages/boards.scss
+++ b/app/assets/stylesheets/pages/boards.scss
@@ -440,6 +440,7 @@
&.right-sidebar {
top: 0;
bottom: 0;
+ height: 100%;
}
.issuable-sidebar-header {
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index c051d37aad6..587a202d6dd 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -141,17 +141,17 @@
display: inline-block;
background: $white-light;
color: $gl-text-color-secondary;
- padding: 0 5px;
+ padding: 0 4px;
cursor: pointer;
border: 1px solid $border-gray-dark;
border-radius: $border-radius-default;
margin-left: 5px;
- font-size: $gl-font-size;
+ font-size: 12px;
line-height: $gl-font-size;
outline: none;
&.open {
- background: $gray-light;
+ background-color: darken($gray-light, 10%);
box-shadow: inset 0 0 2px rgba($black, 0.2);
}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 45f2aed1531..e437bad4912 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -516,7 +516,7 @@ ul.notes {
}
.note-actions-item {
- margin-left: 15px;
+ margin-left: 12px;
display: flex;
align-items: center;
@@ -620,15 +620,25 @@ ul.notes {
.note-role {
position: relative;
- padding: 0 7px;
+ display: inline-block;
color: $notes-role-color;
font-size: 12px;
line-height: 20px;
- border: 1px solid $border-color;
- border-radius: $label-border-radius;
+ margin: 0 3px;
+
+ &.note-role-access {
+ padding: 0 7px;
+ border: 1px solid $border-color;
+ border-radius: $label-border-radius;
+ }
+
+ &.note-role-special {
+ text-shadow: 0 0 15px $gl-text-color-inverted;
+ }
}
+
/**
* Line note button on the side of diffs
*/
diff --git a/app/controllers/admin/logs_controller.rb b/app/controllers/admin/logs_controller.rb
index bdc4332ae69..12a27cede75 100644
--- a/app/controllers/admin/logs_controller.rb
+++ b/app/controllers/admin/logs_controller.rb
@@ -1,6 +1,13 @@
class Admin::LogsController < Admin::ApplicationController
+ before_action :loggers
+
def show
- @loggers = [
+ end
+
+ private
+
+ def loggers
+ @loggers ||= [
Gitlab::AppLogger,
Gitlab::GitLogger,
Gitlab::EnvironmentLogger,
diff --git a/app/controllers/concerns/renders_commits.rb b/app/controllers/concerns/renders_commits.rb
new file mode 100644
index 00000000000..bb2c1dfa00a
--- /dev/null
+++ b/app/controllers/concerns/renders_commits.rb
@@ -0,0 +1,7 @@
+module RendersCommits
+ def prepare_commits_for_rendering(commits)
+ Banzai::CommitRenderer.render(commits, @project, current_user)
+
+ commits
+ end
+end
diff --git a/app/controllers/concerns/renders_notes.rb b/app/controllers/concerns/renders_notes.rb
index 41c3114ad1e..4791bc561a4 100644
--- a/app/controllers/concerns/renders_notes.rb
+++ b/app/controllers/concerns/renders_notes.rb
@@ -1,7 +1,8 @@
module RendersNotes
- def prepare_notes_for_rendering(notes)
+ def prepare_notes_for_rendering(notes, noteable = nil)
preload_noteable_for_regular_notes(notes)
preload_max_access_for_authors(notes, @project)
+ preload_first_time_contribution_for_authors(noteable, notes)
Banzai::NoteRenderer.render(notes, @project, current_user)
notes
@@ -19,4 +20,10 @@ module RendersNotes
def preload_noteable_for_regular_notes(notes)
ActiveRecord::Associations::Preloader.new.preload(notes.reject(&:for_commit?), :noteable)
end
+
+ def preload_first_time_contribution_for_authors(noteable, notes)
+ return unless noteable.is_a?(Issuable) && noteable.first_contribution?
+
+ notes.each {|n| n.specialize_for_first_contribution!(noteable)}
+ end
end
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 076076fd1b3..d83824fef06 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -9,8 +9,6 @@ class ProfilesController < Profiles::ApplicationController
end
def update
- user_params.except!(:email) if @user.external_email?
-
respond_to do |format|
result = Users::UpdateService.new(@user, user_params).execute
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index f637a9a803b..eb010923466 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -7,7 +7,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
before_action :authorize_update_build!, only: [:keep]
before_action :extract_ref_name_and_path
before_action :validate_artifacts!
- before_action :set_path_and_entry, only: [:file, :raw]
+ before_action :entry, only: [:file]
def download
if artifacts_file.file_storage?
@@ -41,7 +41,10 @@ class Projects::ArtifactsController < Projects::ApplicationController
end
def raw
- send_artifacts_entry(build, @entry)
+ path = Gitlab::Ci::Build::Artifacts::Path
+ .new(params[:path])
+
+ send_artifacts_entry(build, path)
end
def keep
@@ -93,9 +96,8 @@ class Projects::ArtifactsController < Projects::ApplicationController
@artifacts_file ||= build.artifacts_file
end
- def set_path_and_entry
- @path = params[:path]
- @entry = build.artifacts_metadata_entry(@path)
+ def entry
+ @entry = build.artifacts_metadata_entry(params[:path])
render_404 unless @entry.exists?
end
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 6de125e7e80..1a775def506 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -127,7 +127,7 @@ class Projects::CommitController < Projects::ApplicationController
@discussions = commit.discussions
@notes = (@grouped_diff_discussions.values.flatten + @discussions).flat_map(&:notes)
- @notes = prepare_notes_for_rendering(@notes)
+ @notes = prepare_notes_for_rendering(@notes, @commit)
end
def assign_change_commit_vars
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 2de9900d449..4a841bf2073 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -2,6 +2,7 @@ require "base64"
class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath
+ include RendersCommits
before_action :require_non_empty_project
before_action :assign_ref_vars
@@ -56,5 +57,7 @@ class Projects::CommitsController < Projects::ApplicationController
else
@repository.commits(@ref, path: @path, limit: @limit, offset: @offset)
end
+
+ @commits = prepare_commits_for_rendering(@commits)
end
end
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index c8613c0d634..193549663ac 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -3,6 +3,7 @@ require 'addressable/uri'
class Projects::CompareController < Projects::ApplicationController
include DiffForPath
include DiffHelper
+ include RendersCommits
# Authorize
before_action :require_non_empty_project
@@ -50,7 +51,7 @@ class Projects::CompareController < Projects::ApplicationController
.execute(@project, @start_ref)
if @compare
- @commits = @compare.commits
+ @commits = prepare_commits_for_rendering(@compare.commits)
@diffs = @compare.diffs(diff_options)
environment_params = @repository.branch_exists?(@head_ref) ? { ref: @head_ref } : { commit: @compare.commit }
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index dc9e6f71152..ab9f132b502 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -85,7 +85,7 @@ class Projects::IssuesController < Projects::ApplicationController
@note = @project.notes.new(noteable: @issue)
@discussions = @issue.discussions
- @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
respond_to do |format|
format.html
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index f35d53896ba..1096afbb798 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -1,6 +1,7 @@
class Projects::MergeRequests::CreationsController < Projects::MergeRequests::ApplicationController
include DiffForPath
include DiffHelper
+ include RendersCommits
skip_before_action :merge_request
skip_before_action :ensure_ref_fetched
@@ -107,7 +108,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
@target_project = @merge_request.target_project
@source_project = @merge_request.source_project
- @commits = @merge_request.commits
+ @commits = prepare_commits_for_rendering(@merge_request.commits)
@commit = @merge_request.diff_head_commit
@note_counts = Note.where(commit_id: @commits.map(&:id))
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 330b7df4541..109418c73f7 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -61,6 +61,6 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
@use_legacy_diff_notes = !@merge_request.has_complete_diff_refs?
@grouped_diff_discussions = @merge_request.grouped_diff_discussions(@compare.diff_refs)
- @notes = prepare_notes_for_rendering(@grouped_diff_discussions.values.flatten.flat_map(&:notes))
+ @notes = prepare_notes_for_rendering(@grouped_diff_discussions.values.flatten.flat_map(&:notes), @merge_request)
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 5095d7fd445..3aa5dadb5ca 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -2,6 +2,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
include ToggleSubscriptionAction
include IssuableActions
include RendersNotes
+ include RendersCommits
include ToggleAwardEmoji
include IssuableCollections
@@ -60,12 +61,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
- @discussions = @merge_request.discussions
- @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
-
@noteable = @merge_request
@commits_count = @merge_request.commits_count
+ @discussions = @merge_request.discussions
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
+
labels
set_pipeline_variables
@@ -94,7 +95,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
def commits
# Get commits from repository
# or from cache if already merged
- @commits = @merge_request.commits
+ @commits = prepare_commits_for_rendering(@merge_request.commits)
@note_counts = Note.where(commit_id: @commits.map(&:id))
.group(:commit_id).count
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index d07143d294f..7c19aa7bb23 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -64,7 +64,7 @@ class Projects::SnippetsController < Projects::ApplicationController
@noteable = @snippet
@discussions = @snippet.discussions
- @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
render 'show'
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index ed17b3b4689..b13034d3333 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -323,6 +323,7 @@ class ProjectsController < Projects::ApplicationController
:build_allow_git_fetch,
:build_coverage_regex,
:build_timeout_in_minutes,
+ :resolve_outdated_diff_discussions,
:container_registry_enabled,
:default_branch,
:description,
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index d58c8d14a75..fbad9ba7db8 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -2,6 +2,7 @@ class SearchController < ApplicationController
skip_before_action :authenticate_user!
include SearchHelper
+ include RendersCommits
layout 'search'
@@ -20,6 +21,8 @@ class SearchController < ApplicationController
@search_results = search_service.search_results
@search_objects = search_service.search_objects
+ render_commits if @scope == 'commits'
+
check_single_commit_result
end
@@ -38,6 +41,10 @@ class SearchController < ApplicationController
private
+ def render_commits
+ @search_objects = prepare_commits_for_rendering(@search_objects)
+ end
+
def check_single_commit_result
if @search_results.single_commit_result?
only_commit = @search_results.objects('commits').first
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 8c3abd0a085..c1cdc7c9831 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -66,7 +66,7 @@ class SnippetsController < ApplicationController
@noteable = @snippet
@discussions = @snippet.discussions
- @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
respond_to do |format|
format.html do
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 017df8f6794..8d02d5de5c3 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -302,10 +302,6 @@ module ApplicationHelper
end
end
- def show_new_nav?
- true
- end
-
def collapsed_sidebar?
cookies["sidebar_collapsed"] == "true"
end
diff --git a/app/helpers/blame_helper.rb b/app/helpers/blame_helper.rb
index d1dc4d94560..089d9e3e387 100644
--- a/app/helpers/blame_helper.rb
+++ b/app/helpers/blame_helper.rb
@@ -11,11 +11,15 @@ module BlameHelper
end
def age_map_class(commit_date, duration)
- commit_date_days_ago = (duration[:now] - commit_date).to_i / 1.day
- # Numbers 0 to 10 come from this calculation, but only commits on the oldest
- # day get number 10 (all other numbers can be multiple days), so the range
- # is normalized to 0-9
- age_group = [(10 * commit_date_days_ago) / duration[:started_days_ago], 9].min
- "blame-commit-age-#{age_group}"
+ if duration[:started_days_ago] == 0
+ "blame-commit-age-0"
+ else
+ commit_date_days_ago = (duration[:now] - commit_date).to_i / 1.day
+ # Numbers 0 to 10 come from this calculation, but only commits on the oldest
+ # day get number 10 (all other numbers can be multiple days), so the range
+ # is normalized to 0-9
+ age_group = [(10 * commit_date_days_ago) / duration[:started_days_ago], 9].min
+ "blame-commit-age-#{age_group}"
+ end
end
end
diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb
index abe8edd6a8c..ee1b7ed083e 100644
--- a/app/helpers/breadcrumbs_helper.rb
+++ b/app/helpers/breadcrumbs_helper.rb
@@ -22,4 +22,16 @@ module BreadcrumbsHelper
@breadcrumb_title = title
end
+
+ def breadcrumb_list_item(link)
+ content_tag "li" do
+ link + icon("angle-right", class: "breadcrumbs-list-angle")
+ end
+ end
+
+ def add_to_breadcrumb_dropdown(link, location: :before)
+ @breadcrumb_dropdown_links ||= {}
+ @breadcrumb_dropdown_links[location] ||= []
+ @breadcrumb_dropdown_links[location] << link
+ end
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index dd159d12aa0..eab1feb8a1f 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -15,18 +15,20 @@ module GroupsHelper
@has_group_title = true
full_title = ''
- group.ancestors.reverse.each do |parent|
- full_title += group_title_link(parent, hidable: true)
-
- full_title += '<span class="hidable"> / </span>'.html_safe
+ group.ancestors.reverse.each_with_index do |parent, index|
+ if index > 0
+ add_to_breadcrumb_dropdown(group_title_link(parent, hidable: false, show_avatar: true), location: :before)
+ else
+ full_title += breadcrumb_list_item group_title_link(parent, hidable: false)
+ end
end
- full_title += group_title_link(group)
- full_title += ' &middot; '.html_safe + link_to(simple_sanitize(name), url, class: 'group-path') if name
+ full_title += render "layouts/nav/breadcrumbs/collapsed_dropdown", location: :before, title: _("Show parent subgroups")
- content_tag :span, class: 'group-title' do
- full_title.html_safe
- end
+ full_title += breadcrumb_list_item group_title_link(group)
+ full_title += ' &middot; '.html_safe + link_to(simple_sanitize(name), url, class: 'group-path breadcrumb-item-text js-breadcrumb-item-text') if name
+
+ full_title.html_safe
end
def projects_lfs_status(group)
@@ -65,11 +67,11 @@ module GroupsHelper
private
- def group_title_link(group, hidable: false)
- link_to(group_path(group), class: "group-path #{'hidable' if hidable}") do
+ def group_title_link(group, hidable: false, show_avatar: false)
+ link_to(group_path(group), class: "group-path breadcrumb-item-text js-breadcrumb-item-text #{'hidable' if hidable}") do
output =
- if show_new_nav? && !Rails.env.test?
- image_tag(group_icon(group), class: "avatar-tile", width: 16, height: 16)
+ if (group.try(:avatar_url) || show_avatar) && !Rails.env.test?
+ image_tag(group_icon(group), class: "avatar-tile", width: 15, height: 15)
else
""
end
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 717abf2082d..ce2999e6696 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -126,22 +126,20 @@ module IssuablesHelper
end
def issuable_meta(issuable, project, text)
- output = content_tag(:strong, class: "identifier") do
- concat("#{text} ")
- concat(to_url_reference(issuable))
- end
-
- output << " opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe
+ output = ""
+ output << "Opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe
output << content_tag(:strong) do
author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs", tooltip: true)
author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg")
end
output << "&ensp;".html_safe
+ output << content_tag(:span, (issuable_first_contribution_icon if issuable.first_contribution?), class: 'has-tooltip', title: _('1st contribution!'))
+
output << content_tag(:span, (issuable.task_status if issuable.tasks?), id: "task_status", class: "hidden-xs hidden-sm")
output << content_tag(:span, (issuable.task_status_short if issuable.tasks?), id: "task_status_short", class: "hidden-md hidden-lg")
- output
+ output.html_safe
end
def issuable_todo(issuable)
@@ -173,6 +171,13 @@ module IssuablesHelper
html.html_safe
end
+ def issuable_first_contribution_icon
+ content_tag(:span, class: 'fa-stack') do
+ concat(icon('certificate', class: "fa-stack-2x"))
+ concat(content_tag(:strong, '1', class: 'fa-inverse fa-stack-1x'))
+ end
+ end
+
def assigned_issuables_count(issuable_type)
case issuable_type
when :issues
diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb
index 941cfce8370..46bced00c72 100644
--- a/app/helpers/markup_helper.rb
+++ b/app/helpers/markup_helper.rb
@@ -21,25 +21,28 @@ module MarkupHelper
end
# Use this in places where you would normally use link_to(gfm(...), ...).
- #
+ def link_to_markdown(body, url, html_options = {})
+ return '' if body.blank?
+
+ link_to_html(markdown(body, pipeline: :single_line), url, html_options)
+ end
+
+ def link_to_markdown_field(object, field, url, html_options = {})
+ rendered_field = markdown_field(object, field)
+
+ link_to_html(rendered_field, url, html_options)
+ end
+
# It solves a problem occurring with nested links (i.e.
# "<a>outer text <a>gfm ref</a> more outer text</a>"). This will not be
# interpreted as intended. Browsers will parse something like
# "<a>outer text </a><a>gfm ref</a> more outer text" (notice the last part is
- # not linked any more). link_to_gfm corrects that. It wraps all parts to
+ # not linked any more). link_to_html corrects that. It wraps all parts to
# explicitly produce the correct linking behavior (i.e.
# "<a>outer text </a><a>gfm ref</a><a> more outer text</a>").
- def link_to_gfm(body, url, html_options = {})
- return '' if body.blank?
+ def link_to_html(redacted, url, html_options = {})
+ fragment = Nokogiri::HTML::DocumentFragment.parse(redacted)
- context = {
- project: @project,
- current_user: (current_user if defined?(current_user)),
- pipeline: :single_line
- }
- gfm_body = Banzai.render(body, context)
-
- fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body)
if fragment.children.size == 1 && fragment.children[0].name == 'a'
# Fragment has only one node, and it's a link generated by `gfm`.
# Replace it with our requested link.
@@ -82,7 +85,10 @@ module MarkupHelper
def markdown_field(object, field)
object = object.for_display if object.respond_to?(:for_display)
+ redacted_field_html = object.try(:"redacted_#{field}_html")
+
return '' unless object.present?
+ return redacted_field_html if redacted_field_html
html = Banzai.render_field(object, field)
prepare_for_rendering(html, object.banzai_render_context(field))
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 73b3386fe9c..a23a43c9f43 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -1,8 +1,8 @@
module NavHelper
def page_with_sidebar_class
class_name = page_gutter_class
- class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar
- class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @new_sidebar
+ class_name << 'page-with-new-sidebar' if defined?(@left_sidebar) && @left_sidebar
+ class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @left_sidebar
class_name
end
@@ -30,23 +30,6 @@ module NavHelper
end
end
- def nav_header_class
- class_names = []
- class_names << 'with-horizontal-nav' if defined?(nav) && nav
-
- class_names
- end
-
- def layout_nav_class
- return 'page-with-new-nav' if show_new_nav?
-
- class_names = []
- class_names << 'page-with-layout-nav' if defined?(nav) && nav
- class_names << 'page-with-sub-nav' if content_for?(:sub_nav)
-
- class_names
- end
-
def nav_control_class
"nav-control" if current_user
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 8c5e258f519..ce028195e51 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -73,7 +73,7 @@ module NotesHelper
end
def note_max_access_for_user(note)
- note.project.team.human_max_access(note.author_id)
+ note.project.team.max_member_access(note.author_id)
end
def discussion_path(discussion)
@@ -146,4 +146,8 @@ module NotesHelper
autocomplete: autocomplete
}
end
+
+ def discussion_resolved_intro(discussion)
+ discussion.resolved_by_push? ? 'Automatically resolved' : 'Resolved'
+ end
end
diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb
index b30b2eb1d03..5946c475835 100644
--- a/app/helpers/page_layout_helper.rb
+++ b/app/helpers/page_layout_helper.rb
@@ -4,7 +4,7 @@ module PageLayoutHelper
@page_title.push(*titles.compact) if titles.any?
- if show_new_nav? && titles.any? && !defined?(@breadcrumb_title)
+ if titles.any? && !defined?(@breadcrumb_title)
@breadcrumb_title = @page_title.last
end
@@ -80,7 +80,9 @@ module PageLayoutHelper
@header_title = title
@header_title_url = title_url
else
- @header_title_url ? link_to(@header_title, @header_title_url) : @header_title
+ return @header_title unless @header_title_url
+
+ breadcrumb_list_item(link_to(@header_title, @header_title_url))
end
end
diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb
index 45238f12ac7..5a4fda0724c 100644
--- a/app/helpers/profiles_helper.rb
+++ b/app/helpers/profiles_helper.rb
@@ -1,7 +1,12 @@
module ProfilesHelper
- def email_provider_label
- return unless current_user.external_email?
-
- current_user.email_provider.present? ? Gitlab::OAuth::Provider.label_for(current_user.email_provider) : "LDAP"
+ def attribute_provider_label(attribute)
+ user_synced_attributes_metadata = current_user.user_synced_attributes_metadata
+ if user_synced_attributes_metadata&.synced?(attribute)
+ if user_synced_attributes_metadata.provider
+ Gitlab::OAuth::Provider.label_for(user_synced_attributes_metadata.provider)
+ else
+ 'LDAP'
+ end
+ end
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 02fe82ea872..86665ea2aec 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -54,25 +54,28 @@ module ProjectsHelper
def project_title(project)
namespace_link =
if project.group
- group_title(project.group)
+ group_title(project.group, nil, nil)
else
owner = project.namespace.owner
link_to(simple_sanitize(owner.name), user_path(owner))
end
- project_link = link_to project_path(project), { class: "project-item-select-holder" } do
+ project_link = link_to project_path(project) do
output =
- if show_new_nav? && !Rails.env.test?
- project_icon(project, alt: project.name, class: 'avatar-tile', width: 16, height: 16)
+ if project.avatar_url && !Rails.env.test?
+ project_icon(project, alt: project.name, class: 'avatar-tile', width: 15, height: 15)
else
""
end
- output << simple_sanitize(project.name)
+ output << content_tag("span", simple_sanitize(project.name), class: "breadcrumb-item-text js-breadcrumb-item-text")
output.html_safe
end
- "#{namespace_link} / #{project_link}".html_safe
+ namespace_link = breadcrumb_list_item(namespace_link) unless project.group
+ project_link = breadcrumb_list_item project_link
+
+ "#{namespace_link} #{project_link}".html_safe
end
def remove_project_message(project)
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index ae0e0aa3cf9..98e824a8c65 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -10,6 +10,7 @@ module SearchHelper
search_pattern = Regexp.new(Regexp.escape(term), "i")
generic_results = project_autocomplete + default_autocomplete + help_autocomplete
+ generic_results.concat(default_autocomplete_admin) if current_user.admin?
generic_results.select! { |result| result[:label] =~ search_pattern }
[
@@ -41,8 +42,14 @@ module SearchHelper
[
{ category: "Settings", label: "User settings", url: profile_path },
{ category: "Settings", label: "SSH Keys", url: profile_keys_path },
- { category: "Settings", label: "Dashboard", url: root_path },
- { category: "Settings", label: "Admin Section", url: admin_root_path }
+ { category: "Settings", label: "Dashboard", url: root_path }
+ ]
+ end
+
+ # Autocomplete results for settings pages, for admins
+ def default_autocomplete_admin
+ [
+ { category: "Settings", label: "Admin Section", url: admin_root_path }
]
end
diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb
index 99212a3438f..815fab9e061 100644
--- a/app/helpers/wiki_helper.rb
+++ b/app/helpers/wiki_helper.rb
@@ -10,4 +10,15 @@ module WikiHelper
.map { |dir_or_page| WikiPage.unhyphenize(dir_or_page).capitalize }
.join(' / ')
end
+
+ def wiki_breadcrumb_dropdown_links(page_slug)
+ page_slug_split = page_slug.split('/')
+ page_slug_split.pop(1)
+ current_slug = ""
+ page_slug_split
+ .map do |dir_or_page|
+ current_slug = "#{current_slug}#{dir_or_page}/"
+ add_to_breadcrumb_dropdown link_to(WikiPage.unhyphenize(dir_or_page).capitalize, project_wiki_path(@project, current_slug)), location: :after
+ end
+ end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index ba3156154ac..64c93966dff 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -27,7 +27,6 @@ module Ci
validates :coverage, numericality: true, allow_blank: true
validates :ref, presence: true
- validates :protected, inclusion: { in: [true, false], unless: :importing? }, on: :create
scope :unstarted, ->() { where(runner_id: nil) }
scope :ignore_failures, ->() { where(allow_failure: false) }
@@ -451,6 +450,10 @@ module Ci
trace
end
+ def serializable_hash(options = {})
+ super(options).merge(when: read_attribute(:when))
+ end
+
private
def update_artifacts_size
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 35d14b6e297..46e5c344fdc 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -36,7 +36,6 @@ module Ci
validates :sha, presence: { unless: :importing? }
validates :ref, presence: { unless: :importing? }
validates :status, presence: { unless: :importing? }
- validates :protected, inclusion: { in: [true, false], unless: :importing? }, on: :create
validate :valid_commit_sha, unless: :importing?
after_create :keep_around_commits, unless: :importing?
diff --git a/app/models/commit.rb b/app/models/commit.rb
index ba3845df867..2ae8890c1b3 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -16,6 +16,8 @@ class Commit
participant :notes_with_associations
attr_accessor :project, :author
+ attr_accessor :redacted_description_html
+ attr_accessor :redacted_title_html
DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines]
@@ -26,6 +28,13 @@ class Commit
# The SHA can be between 7 and 40 hex characters.
COMMIT_SHA_PATTERN = '\h{7,40}'.freeze
+ def banzai_render_context(field)
+ context = { pipeline: :single_line, project: self.project }
+ context[:author] = self.author if self.author
+
+ context
+ end
+
class << self
def decorate(commits, project)
commits.map do |commit|
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 681c3241dbb..265f6e48540 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -334,4 +334,11 @@ module Issuable
metrics = self.metrics || create_metrics
metrics.record!
end
+
+ ##
+ # Override in issuable specialization
+ #
+ def first_contribution?
+ false
+ end
end
diff --git a/app/models/concerns/resolvable_discussion.rb b/app/models/concerns/resolvable_discussion.rb
index dd979e7bb17..f006a271327 100644
--- a/app/models/concerns/resolvable_discussion.rb
+++ b/app/models/concerns/resolvable_discussion.rb
@@ -24,6 +24,7 @@ module ResolvableDiscussion
delegate :resolved_at,
:resolved_by,
+ :resolved_by_push?,
to: :last_resolved_note,
allow_nil: true
diff --git a/app/models/concerns/resolvable_note.rb b/app/models/concerns/resolvable_note.rb
index 05eb6f86704..668c5a079e3 100644
--- a/app/models/concerns/resolvable_note.rb
+++ b/app/models/concerns/resolvable_note.rb
@@ -51,22 +51,34 @@ module ResolvableNote
end
# If you update this method remember to also update `.resolve!`
- def resolve!(current_user)
- return unless resolvable?
- return if resolved?
+ def resolve_without_save(current_user, resolved_by_push: false)
+ return false unless resolvable?
+ return false if resolved?
self.resolved_at = Time.now
self.resolved_by = current_user
- save!
+ self.resolved_by_push = resolved_by_push
+
+ true
end
# If you update this method remember to also update `.unresolve!`
- def unresolve!
- return unless resolvable?
- return unless resolved?
+ def unresolve_without_save
+ return false unless resolvable?
+ return false unless resolved?
self.resolved_at = nil
self.resolved_by = nil
- save!
+
+ true
+ end
+
+ def resolve!(current_user, resolved_by_push: false)
+ resolve_without_save(current_user, resolved_by_push: resolved_by_push) &&
+ save!
+ end
+
+ def unresolve!
+ unresolve_without_save && save!
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 724fb4ccef1..2a56bab48a3 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -918,6 +918,12 @@ class MergeRequest < ActiveRecord::Base
active_diff_discussions.each do |discussion|
service.execute(discussion)
end
+
+ if project.resolve_outdated_diff_discussions?
+ MergeRequests::ResolvedDiscussionNotificationService
+ .new(project, current_user)
+ .execute(self)
+ end
end
def keep_around_commit
@@ -954,6 +960,12 @@ class MergeRequest < ActiveRecord::Base
Projects::OpenMergeRequestsCountService.new(target_project).refresh_cache
end
+ def first_contribution?
+ return false if project.team.max_member_access(author_id) > Gitlab::Access::GUEST
+
+ project.merge_requests.merged.where(author_id: author_id).empty?
+ end
+
private
def write_ref
diff --git a/app/models/note.rb b/app/models/note.rb
index 1073c115630..f44590e2144 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -15,6 +15,16 @@ class Note < ActiveRecord::Base
include IgnorableColumn
include Editable
+ module SpecialRole
+ FIRST_TIME_CONTRIBUTOR = :first_time_contributor
+
+ class << self
+ def values
+ constants.map {|const| self.const_get(const)}
+ end
+ end
+ end
+
ignore_column :original_discussion_id
cache_markdown_field :note, pipeline: :note, issuable_state_filter_enabled: true
@@ -32,9 +42,12 @@ class Note < ActiveRecord::Base
# Banzai::ObjectRenderer
attr_accessor :user_visible_reference_count
- # Attribute used to store the attributes that have ben changed by quick actions.
+ # Attribute used to store the attributes that have been changed by quick actions.
attr_accessor :commands_changes
+ # A special role that may be displayed on issuable's discussions
+ attr_accessor :special_role
+
default_value_for :system, false
attr_mentionable :note, pipeline: :note
@@ -141,6 +154,10 @@ class Note < ActiveRecord::Base
.group(:noteable_id)
.where(noteable_type: type, noteable_id: ids)
end
+
+ def has_special_role?(role, note)
+ note.special_role == role
+ end
end
def cross_reference?
@@ -206,6 +223,22 @@ class Note < ActiveRecord::Base
super(noteable_type.to_s.classify.constantize.base_class.to_s)
end
+ def special_role=(role)
+ raise "Role is undefined, #{role} not found in #{SpecialRole.values}" unless SpecialRole.values.include?(role)
+
+ @special_role = role
+ end
+
+ def has_special_role?(role)
+ self.class.has_special_role?(role, self)
+ end
+
+ def specialize_for_first_contribution!(noteable)
+ return unless noteable.author_id == self.author_id
+
+ self.special_role = Note::SpecialRole::FIRST_TIME_CONTRIBUTOR
+ end
+
def editable?
!system?
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 3d89dabd96f..fdd516ec2ae 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -37,6 +37,7 @@ class Project < ActiveRecord::Base
default_value_for :archived, false
default_value_for :visibility_level, gitlab_config_features.visibility_level
+ default_value_for :resolve_outdated_diff_discussions, false
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
default_value_for(:repository_storage) { current_application_settings.pick_repository_storage }
default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 674eacd28e8..09049824ff7 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -150,7 +150,7 @@ class ProjectTeam
end
def human_max_access(user_id)
- Gitlab::Access.options_with_owner.key(max_member_access(user_id))
+ Gitlab::Access.human_access(max_member_access(user_id))
end
# Determine the maximum access level for a group of users in bulk.
diff --git a/app/models/user.rb b/app/models/user.rb
index c5b5f09722f..105eb62f1fa 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -15,10 +15,12 @@ class User < ActiveRecord::Base
include IgnorableColumn
include FeatureGate
include CreatedAtFilterable
+ include IgnorableColumn
DEFAULT_NOTIFICATION_LEVEL = :participating
- ignore_column :authorized_projects_populated
+ ignore_column :external_email
+ ignore_column :email_provider
add_authentication_token_field :authentication_token
add_authentication_token_field :incoming_email_token
@@ -85,6 +87,7 @@ class User < ActiveRecord::Base
has_many :identities, dependent: :destroy, autosave: true # rubocop:disable Cop/ActiveRecordDependent
has_many :u2f_registrations, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :chat_names, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_one :user_synced_attributes_metadata, autosave: true
# Groups
has_many :members, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -161,6 +164,7 @@ class User < ActiveRecord::Base
after_update :update_emails_with_primary_email, if: :email_changed?
before_save :ensure_authentication_token, :ensure_incoming_email_token
before_save :ensure_user_rights_and_limits, if: :external_changed?
+ before_save :skip_reconfirmation!, if: ->(user) { user.email_changed? && user.read_only_attribute?(:email) }
after_save :ensure_namespace_correct
after_commit :update_invalid_gpg_signatures, on: :update, if: -> { previous_changes.key?('email') }
after_initialize :set_projects_limit
@@ -1045,6 +1049,22 @@ class User < ActiveRecord::Base
self.email == email
end
+ def sync_attribute?(attribute)
+ return true if ldap_user? && attribute == :email
+
+ attributes = Gitlab.config.omniauth.sync_profile_attributes
+
+ if attributes.is_a?(Array)
+ attributes.include?(attribute.to_s)
+ else
+ attributes
+ end
+ end
+
+ def read_only_attribute?(attribute)
+ user_synced_attributes_metadata&.read_only?(attribute)
+ end
+
protected
# override, from Devise::Validatable
diff --git a/app/models/user_synced_attributes_metadata.rb b/app/models/user_synced_attributes_metadata.rb
new file mode 100644
index 00000000000..9f374304164
--- /dev/null
+++ b/app/models/user_synced_attributes_metadata.rb
@@ -0,0 +1,25 @@
+class UserSyncedAttributesMetadata < ActiveRecord::Base
+ belongs_to :user
+
+ validates :user, presence: true
+
+ SYNCABLE_ATTRIBUTES = %i[name email location].freeze
+
+ def read_only?(attribute)
+ Gitlab.config.omniauth.sync_profile_from_provider && synced?(attribute)
+ end
+
+ def read_only_attributes
+ return [] unless Gitlab.config.omniauth.sync_profile_from_provider
+
+ SYNCABLE_ATTRIBUTES.select { |key| synced?(key) }
+ end
+
+ def synced?(attribute)
+ read_attribute("#{attribute}_synced")
+ end
+
+ def set_attribute_synced(attribute, value)
+ write_attribute("#{attribute}_synced", value)
+ end
+end
diff --git a/app/services/discussions/update_diff_position_service.rb b/app/services/discussions/update_diff_position_service.rb
index 1ef8d9edbe1..746f209e20f 100644
--- a/app/services/discussions/update_diff_position_service.rb
+++ b/app/services/discussions/update_diff_position_service.rb
@@ -10,6 +10,10 @@ module Discussions
discussion.notes.each do |note|
if outdated
note.change_position = position
+
+ if project.resolve_outdated_diff_discussions?
+ note.resolve_without_save(current_user, resolved_by_push: true)
+ end
else
note.position = position
note.change_position = nil
diff --git a/app/services/users/update_service.rb b/app/services/users/update_service.rb
index 2f9855273dc..6188b8a4349 100644
--- a/app/services/users/update_service.rb
+++ b/app/services/users/update_service.rb
@@ -34,6 +34,10 @@ module Users
private
def assign_attributes(&block)
+ if @user.user_synced_attributes_metadata
+ params.except!(*@user.user_synced_attributes_metadata.read_only_attributes)
+ end
+
@user.assign_attributes(params) if params.any?
end
end
diff --git a/app/views/admin/applications/edit.html.haml b/app/views/admin/applications/edit.html.haml
index 13b583e6072..13c408914bb 100644
--- a/app/views/admin/applications/edit.html.haml
+++ b/app/views/admin/applications/edit.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Applications", admin_applications_path
+- breadcrumb_title @application.name
- page_title "Edit", @application.name, "Applications"
%h3.page-title Edit application
diff --git a/app/views/admin/cohorts/index.html.haml b/app/views/admin/cohorts/index.html.haml
index be8644c0ca6..bff53da1d9a 100644
--- a/app/views/admin/cohorts/index.html.haml
+++ b/app/views/admin/cohorts/index.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Cohorts"
- @no_container = true
= render "admin/dashboard/head"
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 8e94e68bc11..069f8f89e0b 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -1,4 +1,5 @@
- @no_container = true
+- breadcrumb_title "Dashboard"
= render "admin/dashboard/head"
%div{ class: container_class }
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 2aadc071c75..3e02f7b1e16 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Groups", admin_groups_path
+- breadcrumb_title @group.name
- page_title @group.name, "Groups"
%h3.page-title
Group: #{@group.full_name}
diff --git a/app/views/admin/hooks/edit.html.haml b/app/views/admin/hooks/edit.html.haml
index 665e8c7e74f..efb15ccc8df 100644
--- a/app/views/admin/hooks/edit.html.haml
+++ b/app/views/admin/hooks/edit.html.haml
@@ -1,3 +1,4 @@
+- add_to_breadcrumbs "System Hooks", admin_hooks_path
- page_title 'Edit System Hook'
%h3.page-title
Edit System Hook
diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml
index 09be17f07be..aa6e9db3900 100644
--- a/app/views/admin/jobs/index.html.haml
+++ b/app/views/admin/jobs/index.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Jobs"
- @no_container = true
= render "admin/dashboard/head"
diff --git a/app/views/admin/labels/edit.html.haml b/app/views/admin/labels/edit.html.haml
index 309aedceded..96f0d404ac4 100644
--- a/app/views/admin/labels/edit.html.haml
+++ b/app/views/admin/labels/edit.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Labels", admin_labels_path
+- breadcrumb_title "Edit Label"
- page_title "Edit", @label.name, "Labels"
%h3.page-title
Edit Label
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 7b1b15cfeb8..ab4165c0bf2 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Projects", admin_projects_path
+- breadcrumb_title @project.name_with_namespace
- page_title @project.name_with_namespace, "Projects"
%h3.page-title
Project: #{@project.name_with_namespace}
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index 126550ee10e..6793ce557c4 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Runners"
- @no_container = true
= render "admin/dashboard/head"
diff --git a/app/views/admin/services/edit.html.haml b/app/views/admin/services/edit.html.haml
index 53d970e33c1..512176649e6 100644
--- a/app/views/admin/services/edit.html.haml
+++ b/app/views/admin/services/edit.html.haml
@@ -1,2 +1,4 @@
+- add_to_breadcrumbs "Service Templates", admin_application_settings_services_path
+- breadcrumb_title @service.title
- page_title @service.title, "Service Templates"
= render 'form'
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index b556ff056c0..98ff592eb64 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Users", admin_users_path
+- breadcrumb_title @user.name
- page_title @user.name, "Users"
= render 'admin/users/head'
diff --git a/app/views/ci/variables/_content.html.haml b/app/views/ci/variables/_content.html.haml
index 98f618ca3b8..fbfe3e56588 100644
--- a/app/views/ci/variables/_content.html.haml
+++ b/app/views/ci/variables/_content.html.haml
@@ -1,9 +1,3 @@
-%h4.prepend-top-0
- Secret variables
- = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'secret-variables'), target: '_blank'
-%p
- These variables will be set to environment by the runner, and could be protected by exposing only to protected branches or tags.
-%p
- So you can use them for passwords, secret keys or whatever you want.
-%p
- The value of the variable can be visible in job log if explicitly asked to do so.
+%p.append-bottom-default
+ Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags.
+ You can use variables for passwords, secret keys, or whatever you want.
diff --git a/app/views/ci/variables/_index.html.haml b/app/views/ci/variables/_index.html.haml
index 007c2344b5a..2bac69bc536 100644
--- a/app/views/ci/variables/_index.html.haml
+++ b/app/views/ci/variables/_index.html.haml
@@ -1,7 +1,5 @@
.row.prepend-top-default.append-bottom-default
- .col-lg-4
- = render "ci/variables/content"
- .col-lg-8
+ .col-lg-12
%h5.prepend-top-0
Add a variable
= render "ci/variables/form", btn_text: "Add new variable"
diff --git a/app/views/ci/variables/_show.html.haml b/app/views/ci/variables/_show.html.haml
index 2bfb290629d..6d75ae96124 100644
--- a/app/views/ci/variables/_show.html.haml
+++ b/app/views/ci/variables/_show.html.haml
@@ -4,6 +4,6 @@
.col-lg-3
= render "ci/variables/content"
.col-lg-9
- %h5.prepend-top-0
+ %h4.prepend-top-0
Update variable
= render "ci/variables/form", btn_text: "Save variable"
diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml
index 5a379eae8f4..11bf3f5d323 100644
--- a/app/views/dashboard/_groups_head.html.haml
+++ b/app/views/dashboard/_groups_head.html.haml
@@ -1,4 +1,4 @@
-- if show_new_nav? && current_user.can_create_group?
+- if current_user.can_create_group?
- content_for :breadcrumbs_extra do
= link_to "New group", new_group_path, class: "btn btn-new"
@@ -10,8 +10,8 @@
= nav_link(page: explore_groups_path) do
= link_to explore_groups_path, title: 'Explore public groups' do
Explore public groups
- .nav-controls{ class: ("nav-controls-new-nav" if show_new_nav?) }
+ .nav-controls.nav-controls-new-nav
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
- if current_user.can_create_group?
- = link_to "New group", new_group_path, class: "btn btn-new #{("visible-xs" if show_new_nav?)}"
+ = link_to "New group", new_group_path, class: "btn btn-new visible-xs"
diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml
index 1f9a5b401b6..e2a1914ada2 100644
--- a/app/views/dashboard/_projects_head.html.haml
+++ b/app/views/dashboard/_projects_head.html.haml
@@ -1,7 +1,7 @@
= content_for :flash_message do
= render 'shared/project_limit'
-- if show_new_nav? && current_user.can_create_project?
+- if current_user.can_create_project?
- content_for :breadcrumbs_extra do
= link_to "New project", new_project_path, class: 'btn btn-new'
@@ -19,8 +19,8 @@
= link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
Explore projects
- .nav-controls{ class: ("nav-controls-new-nav" if show_new_nav?) }
+ .nav-controls.nav-controls-new-nav
= render 'shared/projects/search_form'
= render 'shared/projects/dropdown'
- if current_user.can_create_project?
- = link_to "New project", new_project_path, class: "btn btn-new #{("visible-xs" if show_new_nav?)}"
+ = link_to "New project", new_project_path, class: "btn btn-new visible-xs"
diff --git a/app/views/dashboard/_snippets_head.html.haml b/app/views/dashboard/_snippets_head.html.haml
index fd5389106bb..14c18678ab1 100644
--- a/app/views/dashboard/_snippets_head.html.haml
+++ b/app/views/dashboard/_snippets_head.html.haml
@@ -1,4 +1,4 @@
-- if show_new_nav? && current_user
+- if current_user
- content_for :breadcrumbs_extra do
= link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"
@@ -10,7 +10,3 @@
= nav_link(page: explore_snippets_path) do
= link_to explore_snippets_path, title: 'Explore snippets', data: {placement: 'right'} do
Explore Snippets
-
- - if current_user
- .nav-controls.hidden-xs{ class: ("hidden-sm hidden-md hidden-lg" if show_new_nav?) }
- = link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 9ac44674b73..ad0e205a79f 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -4,15 +4,14 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{current_user.name} issues")
-- if show_new_nav?
- - content_for :breadcrumbs_extra do
- = link_to params.merge(rss_url_options), class: 'btn has-tooltip append-right-10', title: 'Subscribe' do
- = icon('rss')
- = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
+- content_for :breadcrumbs_extra do
+ = link_to params.merge(rss_url_options), class: 'btn has-tooltip append-right-10', title: 'Subscribe' do
+ = icon('rss')
+ = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
.top-area
= render 'shared/issuable/nav', type: :issues
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= link_to params.merge(rss_url_options), class: 'btn has-tooltip', title: 'Subscribe' do
= icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index 960e1e55f36..ccc74f7cf3d 100644
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -2,13 +2,12 @@
- page_title "Merge Requests"
- header_title "Merge Requests", merge_requests_dashboard_path(assignee_id: current_user.id)
-- if show_new_nav?
- - content_for :breadcrumbs_extra do
- = render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
+- content_for :breadcrumbs_extra do
+ = render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
.top-area
= render 'shared/issuable/nav', type: :merge_requests
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
= render 'shared/issuable/filter', type: :merge_requests
diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml
index cb8bf57cba1..9fffdded1a0 100644
--- a/app/views/dashboard/milestones/index.html.haml
+++ b/app/views/dashboard/milestones/index.html.haml
@@ -2,14 +2,13 @@
- page_title 'Milestones'
- header_title 'Milestones', dashboard_milestones_path
-- if show_new_nav?
- - content_for :breadcrumbs_extra do
- = render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
+- content_for :breadcrumbs_extra do
+ = render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
.milestones
diff --git a/app/views/discussions/_headline.html.haml b/app/views/discussions/_headline.html.haml
index 25e90924413..b865eb815f0 100644
--- a/app/views/discussions/_headline.html.haml
+++ b/app/views/discussions/_headline.html.haml
@@ -1,9 +1,11 @@
- if discussion.resolved?
.discussion-headline-light.js-discussion-headline
- Resolved
+ = discussion_resolved_intro(discussion)
- if discussion.resolved_by
by
= link_to_member(@project, discussion.resolved_by, avatar: false)
+ - if discussion.resolved_by_push?
+ with a push
= time_ago_with_tooltip(discussion.resolved_at, placement: "bottom")
- elsif discussion.updated?
.discussion-headline-light.js-discussion-headline
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 9ebb3894c55..839f23e69fd 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "General Settings"
= render "groups/settings_head"
.panel.panel-default.prepend-top-default
.panel-heading
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index 837ef385dd5..13a4b4c90c9 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -8,7 +8,7 @@
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
-- if show_new_nav? && group_issues_exists
+- if group_issues_exists
- content_for :breadcrumbs_extra do
= link_to params.merge(rss_url_options), class: 'btn btn-default append-right-10' do
= icon('rss')
@@ -19,7 +19,7 @@
- if group_issues_exists
.top-area
= render 'shared/issuable/nav', type: :issues
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= link_to params.merge(rss_url_options), class: 'btn' do
= icon('rss')
%span.icon-label
diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml
index 50179a47797..9e59a09d459 100644
--- a/app/views/groups/labels/index.html.haml
+++ b/app/views/groups/labels/index.html.haml
@@ -1,5 +1,5 @@
- page_title 'Labels'
-- if show_new_nav? && can?(current_user, :admin_label, @group)
+- if can?(current_user, :admin_label, @group)
- content_for :breadcrumbs_extra do
= link_to "New label", new_group_label_path(@group), class: "btn btn-new"
@@ -10,7 +10,7 @@
.nav-text
Labels can be applied to issues and merge requests. Group labels are available for any project within the group.
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
- if can?(current_user, :admin_label, @group)
= link_to "New label", new_group_label_path(@group), class: "btn btn-new"
diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml
index 184df6f5406..0344770e0dd 100644
--- a/app/views/groups/merge_requests.html.haml
+++ b/app/views/groups/merge_requests.html.haml
@@ -4,7 +4,7 @@
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
-- if show_new_nav? && current_user
+- if current_user
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests
@@ -14,7 +14,7 @@
.top-area
= render 'shared/issuable/nav', type: :merge_requests
- if current_user
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests
= render 'shared/issuable/search_bar', type: :merge_requests
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index 66c6cc9e279..6e7a1af243d 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -1,5 +1,5 @@
- page_title "Milestones"
-- if show_new_nav? && can?(current_user, :admin_milestones, @group)
+- if can?(current_user, :admin_milestones, @group)
- content_for :breadcrumbs_extra do
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
@@ -8,7 +8,7 @@
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
- if can?(current_user, :admin_milestones, @group)
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 7a2e688a114..7f3f2f707f7 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Projects"
= render "groups/settings_head"
.panel.panel-default.prepend-top-default
diff --git a/app/views/groups/settings/ci_cd/show.html.haml b/app/views/groups/settings/ci_cd/show.html.haml
index bf36baf48ab..9f9ae01e7c5 100644
--- a/app/views/groups/settings/ci_cd/show.html.haml
+++ b/app/views/groups/settings/ci_cd/show.html.haml
@@ -1,4 +1,5 @@
-- page_title "Pipelines"
+- breadcrumb_title "CI / CD Settings"
+- page_title "CI / CD"
= render "groups/settings_head"
= render 'ci/variables/index'
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index e07f61c94e4..f4f76887422 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,5 +1,5 @@
- @no_container = true
-- breadcrumb_title "Group"
+- breadcrumb_title "Details"
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
diff --git a/app/views/groups/subgroups.html.haml b/app/views/groups/subgroups.html.haml
index 8f0724c0677..7abc84412c6 100644
--- a/app/views/groups/subgroups.html.haml
+++ b/app/views/groups/subgroups.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Details"
- @no_container = true
= render 'head'
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 3babdae3968..34e85fef6d9 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -32,9 +32,9 @@
= stylesheet_link_tag "test", media: "all" if Rails.env.test?
= stylesheet_link_tag 'performance_bar' if performance_bar_enabled?
- - if show_new_nav?
- = stylesheet_link_tag "new_nav", media: "all"
- = stylesheet_link_tag "new_sidebar", media: "all"
+ // TODO: Combine these 2 stylesheets into application.scss
+ = stylesheet_link_tag "new_nav", media: "all"
+ = stylesheet_link_tag "new_sidebar", media: "all"
= Gon::Base.render_data
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index c4f8cd71395..1fd301d6850 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -1,26 +1,14 @@
.page-with-sidebar{ class: page_with_sidebar_class }
- - if show_new_nav?
- - if defined?(nav) && nav
- = render "layouts/nav/#{nav}"
- - else
- - if defined?(nav) && nav
- .layout-nav
- .container-fluid
- = render "layouts/nav/#{nav}"
- - if content_for?(:sub_nav)
- = yield :sub_nav
- .content-wrapper{ class: layout_nav_class }
- - if show_new_nav?
- .mobile-overlay
+ - if defined?(nav) && nav
+ = render "layouts/nav/sidebar/#{nav}"
+ .content-wrapper.page-with-new-nav
+ .mobile-overlay
.alert-wrapper
= render "layouts/broadcast"
- - if show_new_nav?
- - if content_for?(:new_global_flash)
- = yield :new_global_flash
- - unless @hide_breadcrumbs
- = render "layouts/nav/breadcrumbs"
- = render "layouts/flash"
= yield :flash_message
+ - unless @hide_breadcrumbs
+ = render "layouts/nav/breadcrumbs"
+ = render "layouts/flash"
%div{ class: "#{(container_class unless @no_container)} #{@content_class}" }
.content{ id: "content-body" }
= yield
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index ae9eee215e0..8595157a997 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -1,9 +1,6 @@
- page_title "Admin Area"
- header_title "Admin Area", admin_root_path
-- if show_new_nav?
- - nav "new_admin_sidebar"
- - @new_sidebar = true
-- else
- - nav "admin"
+- nav "admin"
+- @left_sidebar = true
= render template: "layouts/application"
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index b53f382fa3d..65ac8aaa59b 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -4,10 +4,7 @@
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form
= render 'peek/bar'
- - if show_new_nav?
- = render "layouts/header/new"
- - else
- = render "layouts/header/default", title: header_title
+ = render "layouts/header/default"
= render 'layouts/page', sidebar: sidebar, nav: nav
= yield :scripts_body
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 35abfa0e80c..08bd6fc311e 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,10 +1,7 @@
- page_title @group.name
- page_description @group.description unless page_description
- header_title group_title(@group) unless header_title
-- if show_new_nav?
- - nav "new_group_sidebar"
- - @new_sidebar = true
-- else
- - nav "group"
+- nav "group"
+- @left_sidebar = true
= render template: "layouts/application"
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 0d6760e7b8f..d8fc371497d 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -1,55 +1,37 @@
-%header.navbar.navbar-gitlab{ class: nav_header_class }
- .navbar-border
+%header.navbar.navbar-gitlab.navbar-gitlab-new
%a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
.container-fluid
.header-content
- .dropdown.global-dropdown
- %button.global-dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
- %span.sr-only Toggle navigation
- = icon('bars')
- .dropdown-menu-nav.global-dropdown-menu
- - if current_user
- = render 'layouts/nav/dashboard'
- - else
- = render 'layouts/nav/explore'
-
- .header-logo
- = link_to root_path, class: 'home', title: 'Dashboard', id: 'logo' do
- = brand_header_logo
+ .title-container
+ %h1.title
+ = link_to root_path, title: 'Dashboard', id: 'logo' do
+ = brand_header_logo
+ %span.logo-text.hidden-xs
+ = render 'shared/logo_type.svg'
- .title-container.js-title-container
- %h1.title{ class: ('initializing' if @has_group_title) }= title
+ - if current_user
+ = render "layouts/nav/dashboard"
+ - else
+ = render "layouts/nav/explore"
.navbar-collapse.collapse
%ul.nav.navbar-nav
+ - if current_user
+ = render 'layouts/header/new_dropdown'
%li.hidden-sm.hidden-xs
= 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')
- if current_user
- - if session[:impersonator_id]
- %li.impersonation
- = link_to admin_impersonation_path, method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = icon('user-secret fw')
- - if current_user.admin?
- %li
- = link_to admin_root_path, title: 'Admin area', aria: { label: "Admin area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = icon('wrench fw')
- = render 'layouts/header/new_dropdown'
- - if Gitlab::Sherlock.enabled?
- %li
- = link_to sherlock_transactions_path, title: 'Sherlock Transactions',
- data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = icon('tachometer fw')
%li.user-counter
- = link_to assigned_issues_dashboard_path, title: 'Issues', aria: { label: "Issues" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} 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')
- issues_count = assigned_issuables_count(:issues)
%span.badge.issues-count{ class: ('hidden' if issues_count.zero?) }
= number_with_delimiter(issues_count)
%li.user-counter
- = link_to assigned_mrs_dashboard_path, title: 'Merge requests', aria: { label: "Merge requests" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} 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')
- merge_requests_count = assigned_issuables_count(:merge_requests)
%span.badge.merge-requests-count{ class: ('hidden' if merge_requests_count.zero?) }
@@ -60,9 +42,9 @@
%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: "header-user-dropdown-toggle", data: { toggle: "dropdown" } do
- = image_tag avatar_icon(current_user, 26), width: 26, height: 26, class: "header-user-avatar"
- = icon('caret-down')
+ = 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')
.dropdown-menu-nav.dropdown-menu-align-right
%ul
%li.current-user
@@ -74,18 +56,24 @@
= link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
%li
= link_to "Settings", profile_path
+ - if current_user
+ %li
+ = link_to "Help", help_path
%li.divider
%li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
+ - if session[:impersonator_id]
+ %li.impersonation
+ = link_to admin_impersonation_path, class: 'impersonation-btn', method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
+ = icon('user-secret')
- else
%li
%div
- = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success'
+ = link_to "Sign in / Register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in'
- %button.navbar-toggle{ type: 'button' }
+ %button.navbar-toggle.hidden-sm.hidden-md.hidden-lg{ type: 'button' }
%span.sr-only Toggle navigation
- = icon('ellipsis-v')
-
- = yield :header_content
+ = icon('ellipsis-v', class: 'js-navbar-toggle-right')
+ = icon('times', class: 'js-navbar-toggle-left')
= render 'shared/outdated_browser'
diff --git a/app/views/layouts/header/_new.html.haml b/app/views/layouts/header/_new.html.haml
deleted file mode 100644
index 61b71c091be..00000000000
--- a/app/views/layouts/header/_new.html.haml
+++ /dev/null
@@ -1,79 +0,0 @@
-%header.navbar.navbar-gitlab.navbar-gitlab-new{ class: nav_header_class }
- %a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
- .container-fluid
- .header-content
- .title-container
- %h1.title
- = link_to root_path, title: 'Dashboard', id: 'logo' do
- = brand_header_logo
- %span.logo-text.hidden-xs
- = render 'shared/logo_type.svg'
-
- - if current_user
- = render "layouts/nav/new_dashboard"
- - else
- = render "layouts/nav/new_explore"
-
- .navbar-collapse.collapse
- %ul.nav.navbar-nav
- - if current_user
- = render 'layouts/header/new_dropdown'
- %li.hidden-sm.hidden-xs
- = 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')
- - if current_user
- %li.user-counter
- = 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')
- - issues_count = assigned_issuables_count(:issues)
- %span.badge.issues-count{ class: ('hidden' if issues_count.zero?) }
- = number_with_delimiter(issues_count)
- %li.user-counter
- = 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')
- - 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
- = 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')
- %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')
- .dropdown-menu-nav.dropdown-menu-align-right
- %ul
- %li.current-user
- .user-name.bold
- = current_user.name
- @#{current_user.username}
- %li.divider
- %li
- = link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
- %li
- = link_to "Settings", profile_path
- - if current_user
- %li
- = link_to "Help", help_path
- %li.divider
- %li
- = link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
- - if session[:impersonator_id]
- %li.impersonation
- = link_to admin_impersonation_path, class: 'impersonation-btn', method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = icon('user-secret')
- - else
- %li
- %div
- = link_to "Sign in / Register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in'
-
- %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')
-
-= render 'shared/outdated_browser'
diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml
index 9cf2739b368..63d1c077ecd 100644
--- a/app/views/layouts/header/_new_dropdown.haml
+++ b/app/views/layouts/header/_new_dropdown.haml
@@ -1,11 +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
- - if show_new_nav?
- = custom_icon('plus_square')
- = custom_icon('caret_down')
- - else
- = icon('plus fw')
- = custom_icon('caret_down')
+ = custom_icon('plus_square')
+ = custom_icon('caret_down')
.dropdown-menu-nav.dropdown-menu-align-right
%ul
- if @group&.persisted?
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
deleted file mode 100644
index 6df0adfd742..00000000000
--- a/app/views/layouts/nav/_admin.html.haml
+++ /dev/null
@@ -1,40 +0,0 @@
-= render 'layouts/nav/admin_settings'
-.scrolling-tabs-container{ class: nav_control_class }
- .fade-left
- = icon('angle-left')
- .fade-right
- = icon('angle-right')
- %ul.nav-links.scrolling-tabs
- = nav_link(controller: %w(dashboard admin projects users groups builds runners cohorts), html_options: {class: 'home'}) do
- = link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do
- %span
- Overview
- = nav_link(controller: %w(conversational_development_index system_info background_jobs logs health_check requests_profiles)) do
- = link_to admin_conversational_development_index_path, title: 'Monitoring' do
- %span
- Monitoring
- = nav_link(controller: :broadcast_messages) do
- = link_to admin_broadcast_messages_path, title: 'Messages' do
- %span
- Messages
- = nav_link(controller: [:hooks, :hook_logs]) do
- = link_to admin_hooks_path, title: 'Hooks' do
- %span
- System Hooks
-
- = nav_link(controller: :applications) do
- = link_to admin_applications_path, title: 'Applications' do
- %span
- Applications
-
- = nav_link(controller: :abuse_reports) do
- = link_to admin_abuse_reports_path, title: "Abuse Reports" do
- %span
- Abuse Reports
- %span.badge.count= number_with_delimiter(AbuseReport.count(:all))
-
- - if akismet_enabled?
- = nav_link(controller: :spam_logs) do
- = link_to admin_spam_logs_path, title: "Spam Logs" do
- %span
- Spam Logs
diff --git a/app/views/layouts/nav/_admin_settings.html.haml b/app/views/layouts/nav/_admin_settings.html.haml
deleted file mode 100644
index 9de0e12a826..00000000000
--- a/app/views/layouts/nav/_admin_settings.html.haml
+++ /dev/null
@@ -1,31 +0,0 @@
-.controls
- .dropdown.admin-settings-dropdown
- %a.dropdown-new.btn.btn-default{ href: '#', 'data-toggle' => 'dropdown' }
- = icon('cog')
- = icon('caret-down')
- %ul.dropdown-menu.dropdown-menu-align-right
- = nav_link(controller: :deploy_keys) do
- = link_to admin_deploy_keys_path, title: 'Deploy Keys' do
- %span
- Deploy Keys
-
- = nav_link(controller: :services) do
- = link_to admin_application_settings_services_path, title: 'Service Templates' do
- %span
- Service Templates
-
- = nav_link(controller: :labels) do
- = link_to admin_labels_path, title: 'Labels' do
- %span
- Labels
-
- = nav_link(controller: :appearances) do
- = link_to admin_appearances_path, title: 'Appearances' do
- %span
- Appearance
-
- %li.divider
- = nav_link(controller: :application_settings) do
- = link_to admin_application_settings_path, title: 'Settings' do
- %span
- Settings
diff --git a/app/views/layouts/nav/_breadcrumbs.html.haml b/app/views/layouts/nav/_breadcrumbs.html.haml
index 653452871a0..feffd7707dc 100644
--- a/app/views/layouts/nav/_breadcrumbs.html.haml
+++ b/app/views/layouts/nav/_breadcrumbs.html.haml
@@ -1,28 +1,22 @@
-- breadcrumb_link = breadcrumb_title_link
- container = @no_breadcrumb_container ? 'container-fluid' : container_class
- hide_top_links = @hide_top_links || false
-%nav.breadcrumbs{ role: "navigation" }
+%nav.breadcrumbs{ role: "navigation", class: [container, @content_class] }
.breadcrumbs-container{ class: [container, @content_class] }
- - if defined?(@new_sidebar)
+ - if defined?(@left_sidebar)
= button_tag class: 'toggle-mobile-nav', type: 'button' do
%span.sr-only Open sidebar
= icon ('bars')
.breadcrumbs-links.js-title-container
- - unless hide_top_links
- .title
- = link_to "GitLab", root_path
- \/
- - if content_for?(:header_title_before)
- = yield :header_title_before
- \/
+ %ul.list-unstyled.breadcrumbs-list.js-breadcrumbs-list
+ - unless hide_top_links
= header_title
- %h2.breadcrumbs-sub-title
- %ul.list-unstyled
- - if @breadcrumbs_extra_links
- - @breadcrumbs_extra_links.each do |extra|
- %li= link_to extra[:text], extra[:link]
- %li= link_to @breadcrumb_title, breadcrumb_link
+ - if @breadcrumbs_extra_links
+ - @breadcrumbs_extra_links.each do |extra|
+ = breadcrumb_list_item link_to(extra[:text], extra[:link])
+ = render "layouts/nav/breadcrumbs/collapsed_dropdown", location: :after
+ %li
+ %h2.breadcrumbs-sub-title= @breadcrumb_title
- if content_for?(:breadcrumbs_extra)
.breadcrumbs-extra.hidden-xs= yield :breadcrumbs_extra
= yield :header_content
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index be7d27df2a0..8a39c4d775f 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -1,67 +1,62 @@
-%ul
- = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
- = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- P
- %span
- Projects
- = nav_link(path: 'dashboard#activity') do
- = link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- A
- %span
- Activity
- - if koding_enabled?
- = nav_link(controller: :koding) do
- = link_to koding_path, title: 'Koding' do
- %span
- Koding
- = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
+%ul.list-unstyled.navbar-sub-nav
+ = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown" }) do
+ %a{ href: "#", data: { toggle: "dropdown" } }
+ Projects
+ = custom_icon('caret_down')
+ .dropdown-menu.projects-dropdown-menu
+ = render "layouts/nav/projects_dropdown/show"
+
+ = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "hidden-xs" }) do
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- G
- %span
- Groups
- = nav_link(controller: 'dashboard/milestones') do
+ Groups
+
+ = nav_link(path: 'dashboard#activity', html_options: { class: "visible-lg" }) do
+ = link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
+ Activity
+
+ = nav_link(controller: 'dashboard/milestones', html_options: { class: "visible-lg" }) do
= link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- L
- %span
- Milestones
- = nav_link(path: 'dashboard#issues') do
- = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- I
- %span.badge.pull-right= number_with_delimiter(assigned_issuables_count(:issues))
- %span
- Issues
- = nav_link(path: 'dashboard#merge_requests') do
- = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- M
- %span.badge.pull-right= number_with_delimiter(assigned_issuables_count(:merge_requests))
- %span
- Merge Requests
- = nav_link(controller: 'dashboard/snippets') do
+ Milestones
+
+ = nav_link(controller: 'dashboard/snippets', html_options: { class: "visible-lg" }) do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- S
- %span
- Snippets
- %li.divider
- %li
- = link_to "Help", help_path, title: 'About GitLab CE', class: 'about-gitlab'
+ Snippets
+
+ %li.dropdown.hidden-lg
+ %a{ href: "#", data: { toggle: "dropdown" } }
+ More
+ = custom_icon('caret_down')
+ .dropdown-menu
+ %ul
+ = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "visible-xs" }) do
+ = link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
+ Groups
+
+ = nav_link(path: 'dashboard#activity') do
+ = link_to activity_dashboard_path, title: 'Activity' do
+ Activity
+
+ = nav_link(controller: 'dashboard/milestones') do
+ = link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
+ Milestones
+
+ = nav_link(controller: 'dashboard/snippets') do
+ = link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
+ Snippets
+
+ -# Shortcut to Dashboard > Projects
+ %li.hidden
+ = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
+ Projects
+
+ - if current_user.admin? || Gitlab::Sherlock.enabled?
+ %li.line-separator.hidden-xs
+ - 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')
+ - if Gitlab::Sherlock.enabled?
+ %li
+ = link_to sherlock_transactions_path, class: 'admin-icon', title: 'Sherlock Transactions',
+ data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
+ = icon('tachometer fw')
diff --git a/app/views/layouts/nav/_explore.html.haml b/app/views/layouts/nav/_explore.html.haml
index 0cb367452f7..cd1c39f3226 100644
--- a/app/views/layouts/nav/_explore.html.haml
+++ b/app/views/layouts/nav/_explore.html.haml
@@ -1,30 +1,12 @@
-%ul
+%ul.list-unstyled.navbar-sub-nav
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to explore_root_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- P
- %span
- Projects
+ Projects
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to explore_groups_path, title: 'Groups', class: 'dashboard-shortcuts-groups' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- G
- %span
- Groups
+ Groups
= nav_link(controller: :snippets) do
= link_to explore_snippets_path, title: 'Snippets', class: 'dashboard-shortcuts-snippets' do
- .shortcut-mappings
- .key
- = icon('arrow-up', 'aria-label' => 'hidden')
- S
- %span
- Snippets
- %li.divider
- = nav_link(controller: :help) do
- = link_to help_path, title: 'Help' do
- %span
- Help
+ Snippets
+ %li
+ = link_to "Help", help_path, title: 'About GitLab CE'
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
deleted file mode 100644
index 261445ecd2b..00000000000
--- a/app/views/layouts/nav/_group.html.haml
+++ /dev/null
@@ -1,31 +0,0 @@
-.scrolling-tabs-container{ class: nav_control_class }
- .fade-left
- = icon('angle-left')
- .fade-right
- = icon('angle-right')
- %ul.nav-links.scrolling-tabs
- = nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: 'home' }) do
- = link_to group_path(@group), title: 'Home' do
- %span
- Group
- = nav_link(path: ['groups#issues', 'labels#index', 'milestones#index']) do
- = link_to issues_group_path(@group), title: 'Issues' do
- %span
- Issues
- - issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- %span.badge.count= number_with_delimiter(issues.count)
- = nav_link(path: 'groups#merge_requests') do
- = link_to merge_requests_group_path(@group), title: 'Merge Requests' do
- %span
- Merge Requests
- - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
- %span.badge.count= number_with_delimiter(merge_requests.count)
- = nav_link(path: 'group_members#index') do
- = link_to group_group_members_path(@group), title: 'Members' do
- %span
- Members
- - if current_user && can?(current_user, :admin_group, @group)
- = nav_link(path: %w[groups#projects groups#edit ci_cd#show]) do
- = link_to edit_group_path(@group), title: 'Settings' do
- %span
- Settings
diff --git a/app/views/layouts/nav/_new_dashboard.html.haml b/app/views/layouts/nav/_new_dashboard.html.haml
deleted file mode 100644
index 8a39c4d775f..00000000000
--- a/app/views/layouts/nav/_new_dashboard.html.haml
+++ /dev/null
@@ -1,62 +0,0 @@
-%ul.list-unstyled.navbar-sub-nav
- = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown" }) do
- %a{ href: "#", data: { toggle: "dropdown" } }
- Projects
- = custom_icon('caret_down')
- .dropdown-menu.projects-dropdown-menu
- = render "layouts/nav/projects_dropdown/show"
-
- = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "hidden-xs" }) do
- = link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
- Groups
-
- = nav_link(path: 'dashboard#activity', html_options: { class: "visible-lg" }) do
- = link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
- Activity
-
- = nav_link(controller: 'dashboard/milestones', html_options: { class: "visible-lg" }) do
- = link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
- Milestones
-
- = nav_link(controller: 'dashboard/snippets', html_options: { class: "visible-lg" }) do
- = link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
- Snippets
-
- %li.dropdown.hidden-lg
- %a{ href: "#", data: { toggle: "dropdown" } }
- More
- = custom_icon('caret_down')
- .dropdown-menu
- %ul
- = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "visible-xs" }) do
- = link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
- Groups
-
- = nav_link(path: 'dashboard#activity') do
- = link_to activity_dashboard_path, title: 'Activity' do
- Activity
-
- = nav_link(controller: 'dashboard/milestones') do
- = link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
- Milestones
-
- = nav_link(controller: 'dashboard/snippets') do
- = link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
- Snippets
-
- -# Shortcut to Dashboard > Projects
- %li.hidden
- = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
- Projects
-
- - if current_user.admin? || Gitlab::Sherlock.enabled?
- %li.line-separator.hidden-xs
- - 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')
- - if Gitlab::Sherlock.enabled?
- %li
- = link_to sherlock_transactions_path, class: 'admin-icon', title: 'Sherlock Transactions',
- data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = icon('tachometer fw')
diff --git a/app/views/layouts/nav/_new_explore.html.haml b/app/views/layouts/nav/_new_explore.html.haml
deleted file mode 100644
index cd1c39f3226..00000000000
--- a/app/views/layouts/nav/_new_explore.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-%ul.list-unstyled.navbar-sub-nav
- = nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
- = link_to explore_root_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
- Projects
- = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
- = link_to explore_groups_path, title: 'Groups', class: 'dashboard-shortcuts-groups' do
- Groups
- = nav_link(controller: :snippets) do
- = link_to explore_snippets_path, title: 'Snippets', class: 'dashboard-shortcuts-snippets' do
- Snippets
- %li
- = link_to "Help", help_path, title: 'About GitLab CE'
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
deleted file mode 100644
index 448f6abedf2..00000000000
--- a/app/views/layouts/nav/_profile.html.haml
+++ /dev/null
@@ -1,57 +0,0 @@
-.scrolling-tabs-container
- .fade-left
- = icon('angle-left')
- .fade-right
- = icon('angle-right')
- %ul.nav-links.scrolling-tabs
- = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
- = link_to profile_path, title: 'Profile Settings' do
- %span
- Profile
- = nav_link(controller: [:accounts, :two_factor_auths]) do
- = link_to profile_account_path, title: 'Account' do
- %span
- Account
- - if current_application_settings.user_oauth_applications?
- = nav_link(controller: 'oauth/applications') do
- = link_to applications_profile_path, title: 'Applications' do
- %span
- Applications
- = nav_link(controller: :chat_names) do
- = link_to profile_chat_names_path, title: 'Chat' do
- %span
- Chat
- = nav_link(controller: :personal_access_tokens) do
- = link_to profile_personal_access_tokens_path, title: 'Access Tokens' do
- %span
- Access Tokens
- = nav_link(controller: :emails) do
- = link_to profile_emails_path, title: 'Emails' do
- %span
- Emails
- - unless current_user.ldap_user?
- = nav_link(controller: :passwords) do
- = link_to edit_profile_password_path, title: 'Password' do
- %span
- Password
- = nav_link(controller: :notifications) do
- = link_to profile_notifications_path, title: 'Notifications' do
- %span
- Notifications
-
- = nav_link(controller: :keys) do
- = link_to profile_keys_path, title: 'SSH Keys' do
- %span
- SSH Keys
- = nav_link(controller: :gpg_keys) do
- = link_to profile_gpg_keys_path, title: 'GPG Keys' do
- %span
- GPG Keys
- = nav_link(controller: :preferences) do
- = link_to profile_preferences_path, title: 'Preferences' do
- %span
- Preferences
- = nav_link(path: 'profiles#audit_log') do
- = link_to audit_log_profile_path, title: 'Authentication log' do
- %span
- Authentication log
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
deleted file mode 100644
index b88465848e3..00000000000
--- a/app/views/layouts/nav/_project.html.haml
+++ /dev/null
@@ -1,111 +0,0 @@
-- can_edit = can?(current_user, :admin_project, @project)
-.scrolling-tabs-container{ class: nav_control_class }
- .fade-left
- = icon('angle-left')
- .fade-right
- = icon('angle-right')
- %ul.nav-links.scrolling-tabs
- = nav_link(path: ['projects#show', 'projects#activity', 'cycle_analytics#show'], html_options: { class: 'home' }) do
- = link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
- %span
- Project
-
- - if project_nav_tab? :files
- = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare projects/repositories tags branches releases graphs network)) do
- = link_to project_tree_path(@project), title: 'Repository', class: 'shortcuts-tree' do
- %span
- Repository
-
- - if project_nav_tab? :container_registry
- = nav_link(controller: %w[projects/registry/repositories]) do
- = link_to project_container_registry_index_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
- %span
- Registry
-
- - if project_nav_tab? :issues
- = nav_link(controller: @project.issues_enabled? ? [:issues, :labels, :milestones, :boards] : :issues) do
- = link_to project_issues_path(@project), title: 'Issues', class: 'shortcuts-issues' do
- %span
- Issues
- - if @project.issues_enabled?
- %span.badge.count.issue_counter
- = number_with_delimiter(@project.open_issues_count)
-
- - if project_nav_tab? :merge_requests
- - controllers = [:merge_requests, 'projects/merge_requests/conflicts']
- - controllers.push(:merge_requests, :labels, :milestones) unless @project.issues_enabled?
- = nav_link(controller: controllers) do
- = link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
- %span
- Merge Requests
- %span.badge.count.merge_counter.js-merge-counter
- = number_with_delimiter(@project.open_merge_requests_count)
-
- - if project_nav_tab? :pipelines
- = nav_link(controller: [:pipelines, :builds, :environments, :artifacts]) do
- = link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
- %span
- Pipelines
-
- - if project_nav_tab? :wiki
- = nav_link(controller: :wikis) do
- = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
- %span
- Wiki
-
- - if project_nav_tab? :snippets
- = nav_link(controller: :snippets) do
- = link_to project_snippets_path(@project), title: 'Snippets', class: 'shortcuts-snippets' do
- %span
- Snippets
-
- - if project_nav_tab? :project_members
- = nav_link(controller: :project_members) do
- = link_to project_project_members_path(@project), title: 'Members', class: 'shortcuts-members' do
- %span
- Members
-
- - if project_nav_tab? :settings
- = nav_link(path: %w[projects#edit members#show integrations#show services#edit repository#show ci_cd#show pages#show]) do
- = link_to edit_project_path(@project), title: 'Settings', class: 'shortcuts-tree' do
- %span
- Settings
-
- -# Shortcut to Project > Activity
- %li.hidden
- = link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
- %span
- Activity
-
- -# Shortcut to Repository > Graph (formerly, Network)
- - if project_nav_tab? :network
- %li.hidden
- = link_to project_network_path(@project, current_ref), title: 'Network', class: 'shortcuts-network' do
- Graph
-
- -# Shortcut to Repository > Charts (formerly, top-nav item "Graphs")
- - unless @project.empty_repo?
- %li.hidden
- = link_to charts_project_graph_path(@project, current_ref), title: 'Charts', class: 'shortcuts-repository-charts' do
- Charts
-
- -# Shortcut to Issues > New Issue
- %li.hidden
- = link_to new_project_issue_path(@project), class: 'shortcuts-new-issue' do
- Create a new issue
-
- -# Shortcut to Pipelines > Jobs
- - if project_nav_tab? :builds
- %li.hidden
- = link_to project_jobs_path(@project), title: 'Jobs', class: 'shortcuts-builds' do
- Jobs
-
- -# Shortcut to commits page
- - if project_nav_tab? :commits
- %li.hidden
- = link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
- Commits
-
- -# Shortcut to issue boards
- %li.hidden
- = link_to 'Issue Boards', project_boards_path(@project), title: 'Issue Boards', class: 'shortcuts-issue-boards'
diff --git a/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml b/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml
new file mode 100644
index 00000000000..28022eebb19
--- /dev/null
+++ b/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml
@@ -0,0 +1,11 @@
+- dropdown_location = local_assigns.fetch(:location, nil)
+- button_tooltip = local_assigns.fetch(:title, _("Show parent pages"))
+- if defined?(@breadcrumb_dropdown_links) && @breadcrumb_dropdown_links.key?(dropdown_location)
+ %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")
+ .dropdown-menu
+ %ul
+ - @breadcrumb_dropdown_links[dropdown_location].each_with_index do |link, index|
+ %li{ style: "text-indent: #{[index * 16, 60].min}px;" }= link
diff --git a/app/views/layouts/nav/_new_admin_sidebar.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml
index 3b53117deb6..3b53117deb6 100644
--- a/app/views/layouts/nav/_new_admin_sidebar.html.haml
+++ b/app/views/layouts/nav/sidebar/_admin.html.haml
diff --git a/app/views/layouts/nav/_new_group_sidebar.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index 5a1511b262f..5a1511b262f 100644
--- a/app/views/layouts/nav/_new_group_sidebar.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
diff --git a/app/views/layouts/nav/_new_profile_sidebar.html.haml b/app/views/layouts/nav/sidebar/_profile.html.haml
index ccb6d1492f1..ccb6d1492f1 100644
--- a/app/views/layouts/nav/_new_profile_sidebar.html.haml
+++ b/app/views/layouts/nav/sidebar/_profile.html.haml
diff --git a/app/views/layouts/nav/_new_project_sidebar.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 760c4c97c33..760c4c97c33 100644
--- a/app/views/layouts/nav/_new_project_sidebar.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index c365839e605..67aa05b655c 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -1,10 +1,7 @@
- page_title "User Settings"
- header_title "User Settings", profile_path unless header_title
- sidebar "dashboard"
-- if show_new_nav?
- - nav "new_profile_sidebar"
- - @new_sidebar = true
-- else
- - nav "profile"
+- nav "profile"
+- @left_sidebar = true
= render template: "layouts/application"
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index d6db85ee87a..6b847fb4b7c 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -1,11 +1,8 @@
- page_title @project.name_with_namespace
- page_description @project.description unless page_description
- header_title project_title(@project) unless header_title
-- if show_new_nav?
- - nav "new_project_sidebar"
- - @new_sidebar = true
-- else
- - nav "project"
+- nav "project"
+- @left_sidebar = true
- content_for :project_javascripts do
- project = @target_project || @project
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index 985bb79508f..c606b5a1e6c 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Edit Password"
- page_title "Password"
- @content_class = "limit-container-width" unless fluid_layout
diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml
index 2216708d354..06bb72b9f0d 100644
--- a/app/views/profiles/personal_access_tokens/index.html.haml
+++ b/app/views/profiles/personal_access_tokens/index.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Access Tokens"
- page_title "Personal Access Tokens"
- @content_class = "limit-container-width" unless fluid_layout
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index a8ae0b92334..35ad280b037 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -1,4 +1,4 @@
-- breadcrumb_title "Profile"
+- breadcrumb_title "Edit Profile"
- @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head'
@@ -45,12 +45,15 @@
Some options are unavailable for LDAP accounts
.col-lg-8
.row
- = f.text_field :name, required: true, wrapper: { class: 'col-md-9' },
- help: 'Enter your name, so people you know can recognize you.'
+ - if @user.read_only_attribute?(:name)
+ = f.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9' },
+ help: "Your name was automatically set based on your #{ attribute_provider_label(:name) } account, so people you know can recognize you."
+ - else
+ = f.text_field :name, required: true, wrapper: { class: 'col-md-9' }, help: "Enter your name, so people you know can recognize you."
= f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' }
- - if @user.external_email?
- = f.text_field :email, required: true, readonly: true, help: "Your email address was automatically set based on your #{email_provider_label} account."
+ - if @user.read_only_attribute?(:email)
+ = f.text_field :email, required: true, readonly: true, help: "Your email address was automatically set based on your #{ attribute_provider_label(:email) } account."
- else
= f.text_field :email, required: true, value: (@user.email unless @user.temp_oauth_email?),
help: user_email_help_text(@user)
@@ -64,7 +67,10 @@
= f.text_field :linkedin
= f.text_field :twitter
= f.text_field :website_url, label: 'Website'
- = f.text_field :location
+ - if @user.read_only_attribute?(:location)
+ = f.text_field :location, readonly: true, help: "Your location was automatically set based on your #{ attribute_provider_label(:location) } account."
+ - else
+ = f.text_field :location
= f.text_field :organization
= f.text_area :bio, rows: 4, maxlength: 250, help: 'Tell us about yourself in fewer than 250 characters.'
.prepend-top-default.append-bottom-default
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index 33e062c1c9c..0b03276efcc 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -1,8 +1,5 @@
- page_title 'Two-Factor Authentication', 'Account'
-- if show_new_nav?
- - add_to_breadcrumbs("Account", profile_account_path)
-- else
- - header_title "Two-Factor Authentication", profile_two_factor_auth_path
+- add_to_breadcrumbs("Account", profile_account_path)
- @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head'
diff --git a/app/views/projects/_flash_messages.html.haml b/app/views/projects/_flash_messages.html.haml
index f47d84ef755..0175b519867 100644
--- a/app/views/projects/_flash_messages.html.haml
+++ b/app/views/projects/_flash_messages.html.haml
@@ -1,7 +1,6 @@
- project = local_assigns.fetch(:project)
-- flash_message_container = show_new_nav? ? :new_global_flash : :flash_message
-= content_for flash_message_container do
+= content_for :flash_message do
= render partial: 'deletion_failed', locals: { project: project }
- if current_user && can?(current_user, :download_code, project)
= render 'shared/no_ssh'
diff --git a/app/views/projects/_merge_request_merge_settings.html.haml b/app/views/projects/_merge_request_merge_settings.html.haml
index 61420fd0fb6..e3effe45d6c 100644
--- a/app/views/projects/_merge_request_merge_settings.html.haml
+++ b/app/views/projects/_merge_request_merge_settings.html.haml
@@ -14,6 +14,10 @@
= form.check_box :only_allow_merge_if_all_discussions_are_resolved
%strong Only allow merge requests to be merged if all discussions are resolved
.checkbox
+ = form.label :resolve_outdated_diff_discussions do
+ = form.check_box :resolve_outdated_diff_discussions
+ %strong Automatically resolve merge request diff discussions when they become outdated
+ .checkbox
= form.label :printing_merge_request_link_enabled do
= form.check_box :printing_merge_request_link_enabled
%strong Show link to create/view merge request when pushing from the command line
diff --git a/app/views/projects/activity.html.haml b/app/views/projects/activity.html.haml
index 5452c6db6a6..f80dadb8037 100644
--- a/app/views/projects/activity.html.haml
+++ b/app/views/projects/activity.html.haml
@@ -1,9 +1,7 @@
- @no_container = true
-- if show_new_nav?
- - add_to_breadcrumbs(_("Project"), project_path(@project))
-
- page_title _("Activity")
+
= render "projects/head"
= render 'projects/last_push'
diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml
index a33743c2f57..4cc3218d967 100644
--- a/app/views/projects/artifacts/browse.html.haml
+++ b/app/views/projects/artifacts/browse.html.haml
@@ -1,8 +1,12 @@
+- breadcrumb_title _('Artifacts')
- page_title @path.presence, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs'
= render "projects/pipelines/head"
= render "projects/jobs/header", show_controls: false
+- add_to_breadcrumbs(_('Jobs'), project_jobs_path(@project))
+- add_to_breadcrumbs("##{@build.id}", project_jobs_path(@project))
+
.tree-holder
.nav-block
%ul.breadcrumb.repo-breadcrumb
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index c7359d873d9..60ac202bde0 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -22,7 +22,7 @@
= author_avatar(commit, size: 36)
.commit-row-title
%span.item-title.str-truncated-100
- = link_to_gfm commit.title, project_commit_path(@project, commit.id), class: "cdark", title: commit.title
+ = link_to_markdown commit.title, project_commit_path(@project, commit.id), class: "cdark", title: commit.title
.pull-right
= link_to commit.short_id, project_commit_path(@project, commit), class: "commit-sha"
&nbsp;
diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml
index 5354ec8522e..303e20e8780 100644
--- a/app/views/projects/boards/_show.html.haml
+++ b/app/views/projects/boards/_show.html.haml
@@ -1,11 +1,9 @@
- @no_breadcrumb_container = true
- @no_container = true
- @content_class = "issue-boards-content"
+- breadcrumb_title "Issue Board"
- page_title "Boards"
-- if show_new_nav?
- - add_to_breadcrumbs("Issues", project_issues_path(@project))
-
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
diff --git a/app/views/projects/branches/_commit.html.haml b/app/views/projects/branches/_commit.html.haml
index 18fbb81c167..7892019bb15 100644
--- a/app/views/projects/branches/_commit.html.haml
+++ b/app/views/projects/branches/_commit.html.haml
@@ -4,6 +4,6 @@
= link_to commit.short_id, project_commit_path(project, commit.id), class: "commit-sha"
&middot;
%span.str-truncated
- = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
+ = link_to_markdown commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
&middot;
#{time_ago_with_tooltip(commit.committed_date)}
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 945a5c11d6d..73583c6bbc2 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -2,9 +2,6 @@
- page_title "Branches"
= render "projects/commits/head"
-- if show_new_nav?
- - add_to_breadcrumbs("Repository", project_tree_path(@project))
-
%div{ class: container_class }
.top-area.adjust
- if can?(current_user, :admin_project, @project)
diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml
index 07c83c0a590..717de85c5d2 100644
--- a/app/views/projects/commit/show.html.haml
+++ b/app/views/projects/commit/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Commits", project_commits_path(@project)
+- breadcrumb_title @commit.short_id
- container_class = !fluid_layout && diff_view == :inline ? 'container-limited' : ''
- limited_container_width = fluid_layout ? '' : 'limit-container-width'
- @content_class = limited_container_width
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 1214aabe837..b8655808d89 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -16,7 +16,7 @@
.commit-detail
.commit-content
- = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message item-title"
+ = link_to_markdown_field(commit, :title, project_commit_path(project, commit.id), class: "commit-row-message item-title")
%span.commit-row-message.visible-xs-inline
&middot;
= commit.short_id
@@ -28,7 +28,8 @@
- if commit.description?
%pre.commit-row-description.js-toggle-content
- = preserve(markdown(commit.description, pipeline: :single_line, author: commit.author))
+ = preserve(markdown_field(commit, :description))
+
.commiter
- commit_author_link = commit_author_link(commit, avatar: false, size: 24)
- commit_timeago = time_ago_with_tooltip(commit.committed_date)
diff --git a/app/views/projects/commits/_inline_commit.html.haml b/app/views/projects/commits/_inline_commit.html.haml
index 48cefbe45f2..26385d2f534 100644
--- a/app/views/projects/commits/_inline_commit.html.haml
+++ b/app/views/projects/commits/_inline_commit.html.haml
@@ -3,6 +3,6 @@
= link_to commit.short_id, project_commit_path(project, commit), class: "commit-sha"
&nbsp;
%span.str-truncated
- = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
+ = link_to_markdown_field(commit, :title, project_commit_path(project, commit.id), class: "commit-row-message")
.pull-right
#{time_ago_with_tooltip(commit.committed_date)}
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 7ae56086177..e873b931683 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -5,9 +5,6 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
-- if show_new_nav?
- - add_to_breadcrumbs("Repository", project_tree_path(@project))
-
= content_for :sub_nav do
= render "head"
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index 05de21e8dbf..2632fea6eba 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,7 +1,6 @@
- @no_container = true
+- breadcrumb_title "Compare Revisions"
- page_title "Compare"
-- if show_new_nav?
- - add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
%div{ class: container_class }
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 8bc863f77b3..7cc42455394 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -1,8 +1,6 @@
- @no_container = true
-- breadcrumb_title "Compare"
+- add_to_breadcrumbs "Compare Revisions", project_compare_index_path(@project)
- page_title "#{params[:from]}...#{params[:to]}"
-- if show_new_nav?
- - add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
%div{ class: container_class }
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index 3467e357c49..8d008be5aae 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1,7 +1,5 @@
- @no_container = true
- page_title "Cycle Analytics"
-- if show_new_nav?
- - add_to_breadcrumbs("Project", project_path(@project))
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('cycle_analytics')
diff --git a/app/views/projects/deployments/_commit.html.haml b/app/views/projects/deployments/_commit.html.haml
index 4c22166c256..014486be868 100644
--- a/app/views/projects/deployments/_commit.html.haml
+++ b/app/views/projects/deployments/_commit.html.haml
@@ -12,6 +12,6 @@
%span.flex-truncate-child
- if commit_title = deployment.commit_title
= author_avatar(deployment.commit, size: 20)
- = link_to_gfm commit_title, project_commit_path(@project, deployment.sha), class: "commit-row-message"
+ = link_to_markdown commit_title, project_commit_path(@project, deployment.sha), class: "commit-row-message"
- else
Cant find HEAD commit for this branch
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 9e26bdecd31..994119051d2 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "General Settings"
- page_title "General"
- @content_class = "limit-container-width" unless fluid_layout
- expanded = Rails.env.test?
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index d17709380d5..5e980314307 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,4 +1,5 @@
- @no_container = true
+- breadcrumb_title "Details"
= render partial: 'flash_messages', locals: { project: @project }
diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml
index d0f723af5bf..acc80b49dd0 100644
--- a/app/views/projects/environments/index.html.haml
+++ b/app/views/projects/environments/index.html.haml
@@ -1,10 +1,8 @@
- @no_container = true
- page_title "Environments"
+- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
= render "projects/pipelines/head"
-- if show_new_nav?
- - add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
-
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag("environments")
diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml
index 0ce0f5465fc..c35d1b5aaee 100644
--- a/app/views/projects/environments/show.html.haml
+++ b/app/views/projects/environments/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Environments", project_environments_path(@project)
+- breadcrumb_title @environment.name
- page_title "Environments"
= render "projects/pipelines/head"
diff --git a/app/views/projects/graphs/charts.html.haml b/app/views/projects/graphs/charts.html.haml
index 9f5a1239a82..f0ef647ddb3 100644
--- a/app/views/projects/graphs/charts.html.haml
+++ b/app/views/projects/graphs/charts.html.haml
@@ -1,7 +1,5 @@
- @no_container = true
- page_title "Charts"
-- if show_new_nav?
- - add_to_breadcrumbs("Repository", project_tree_path(@project))
- content_for :page_specific_javascripts do
= webpack_bundle_tag('common_d3')
= webpack_bundle_tag('graphs')
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index f41a0d8293b..08b38428b50 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -5,9 +5,6 @@
= webpack_bundle_tag('graphs')
= webpack_bundle_tag('graphs_show')
-- if show_new_nav?
- - add_to_breadcrumbs("Repository", project_tree_path(@project))
-
= render 'projects/commits/head'
.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index aacb057840d..6fcb5975707 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -13,15 +13,14 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@project.name} issues")
-- if show_new_nav?
- - content_for :breadcrumbs_extra do
- = render "projects/issues/nav_btns"
+- content_for :breadcrumbs_extra do
+ = render "projects/issues/nav_btns"
- if project_issues(@project).exists?
%div{ class: (container_class) }
.top-area
= render 'shared/issuable/nav', type: :issues
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= render "projects/issues/nav_btns"
= render 'shared/issuable/search_bar', type: :issues
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 04b4ed95a2d..fbaf88356bf 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,4 +1,6 @@
- @content_class = "limit-container-width" unless fluid_layout
+- add_to_breadcrumbs "Issues", project_issues_path(@project)
+- breadcrumb_title @issue.to_reference
- page_title "#{@issue.title} (#{@issue.to_reference})", "Issues"
- page_description @issue.description
- page_card_attributes @issue.card_attributes
diff --git a/app/views/projects/jobs/index.html.haml b/app/views/projects/jobs/index.html.haml
index d78891546f7..8604c7d3ea4 100644
--- a/app/views/projects/jobs/index.html.haml
+++ b/app/views/projects/jobs/index.html.haml
@@ -2,9 +2,6 @@
- page_title "Jobs"
= render "projects/pipelines/head"
-- if show_new_nav?
- - add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
-
%div{ class: container_class }
.top-area
- build_path_proc = ->(scope) { project_jobs_path(@project, scope: scope) }
diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml
index fa086413fbe..975c08c06e6 100644
--- a/app/views/projects/jobs/show.html.haml
+++ b/app/views/projects/jobs/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Jobs", project_jobs_path(@project)
+- breadcrumb_title "##{@build.id}"
- page_title "#{@build.name} (##{@build.id})", "Jobs"
= render "projects/pipelines/head"
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 4b9da02c6b8..ec9e8444ac5 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -3,7 +3,7 @@
- hide_class = ''
- can_admin_label = can?(current_user, :admin_label, @project)
-- if show_new_nav? && can?(current_user, :admin_label, @project)
+- if can?(current_user, :admin_label, @project)
- content_for :breadcrumbs_extra do
= link_to "New label", new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new"
@@ -18,7 +18,7 @@
Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.
- if can_admin_label
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= link_to new_project_label_path(@project), class: "btn btn-new" do
New label
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index c020e7db380..27c3002366b 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -12,9 +12,8 @@
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
-- if show_new_nav?
- - content_for :breadcrumbs_extra do
- = render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
+- content_for :breadcrumbs_extra do
+ = render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
= render 'projects/last_push'
@@ -22,7 +21,7 @@
%div{ class: container_class }
.top-area
= render 'shared/issuable/nav', type: :merge_requests
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
= render 'shared/issuable/search_bar', type: :merge_requests
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index d27e121beb4..c2d16f7e731 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -1,4 +1,6 @@
- @content_class = "limit-container-width" unless fluid_layout
+- add_to_breadcrumbs "Merge Requests", project_merge_requests_path(@project)
+- breadcrumb_title @merge_request.to_reference
- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests"
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index e0b29b0c2e1..71ec88ef1c1 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -1,7 +1,7 @@
- @no_container = true
- page_title 'Milestones'
-- if show_new_nav? && can?(current_user, :admin_milestone, @project)
+- if can?(current_user, :admin_milestone, @project)
- content_for :breadcrumbs_extra do
= link_to "New milestone", new_namespace_project_milestone_path(@project.namespace, @project), class: 'btn btn-new', title: 'New milestone'
@@ -11,10 +11,10 @@
.top-area
= render 'shared/milestones_filter', counts: milestone_counts(@project.milestones)
- .nav-controls{ class: ("nav-controls-new-nav" if show_new_nav?) }
+ .nav-controls.nav-controls-new-nav
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @project)
- = link_to new_project_milestone_path(@project), class: "btn btn-new #{("visible-xs" if show_new_nav?)}", title: 'New milestone' do
+ = link_to new_project_milestone_path(@project), class: "btn btn-new visible-xs", title: 'New milestone' do
New milestone
.milestones
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 0bf0e11c107..1f5f18801ad 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Milestones", project_milestones_path(@project)
+- breadcrumb_title @milestone.title
- page_title @milestone.title, "Milestones"
- page_description @milestone.description
= render "shared/mr_head"
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index ab948df4a3f..e29cb277389 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -2,8 +2,6 @@
- page_title "Graph", @ref
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('network')
-- if show_new_nav?
- - add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
= render "head"
%div{ class: container_class }
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index fb07141d2ac..de76832331a 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -1,6 +1,8 @@
-- access = note_max_access_for_user(note)
-- if access
- %span.note-role= access
+- 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.") }
+ = issuable_first_contribution_icon
+- if access = note_max_access_for_user(note)
+ %span.note-role.note-role-access= Gitlab::Access.human_access(access)
- if note.resolvable?
- can_resolve = can?(current_user, :resolve_note, note)
diff --git a/app/views/projects/notes/_more_actions_dropdown.html.haml b/app/views/projects/notes/_more_actions_dropdown.html.haml
index 7e854186973..88085c7185b 100644
--- a/app/views/projects/notes/_more_actions_dropdown.html.haml
+++ b/app/views/projects/notes/_more_actions_dropdown.html.haml
@@ -7,7 +7,7 @@
= custom_icon('ellipsis_v')
%ul.dropdown-menu.more-actions-dropdown.dropdown-open-left
%li
- = clipboard_button(text: noteable_note_url(note), title: "Copy reference to clipboard", button_text: 'Copy link', hide_tooltip: true, hide_button_icon: true)
+ = clipboard_button(text: noteable_note_url(note), title: 'Copy reference to clipboard', button_text: 'Copy link', class: 'btn-clipboard', hide_tooltip: true, hide_button_icon: true)
- unless is_current_user
%li
= link_to new_abuse_report_path(user_id: note.author.id, ref_url: noteable_note_url(note)) do
diff --git a/app/views/projects/pipeline_schedules/edit.html.haml b/app/views/projects/pipeline_schedules/edit.html.haml
index 9b2a7b5821d..d95fa6da903 100644
--- a/app/views/projects/pipeline_schedules/edit.html.haml
+++ b/app/views/projects/pipeline_schedules/edit.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs _("Schedules"), pipeline_schedules_path(@project)
+- breadcrumb_title "##{@schedule.id}"
- page_title _("Edit"), @schedule.description, _("Pipeline Schedule")
%h3.page-title
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index 8426b29bb14..d9957b54a4d 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -1,4 +1,4 @@
-- breadcrumb_title "Schedules"
+- breadcrumb_title _("Schedules")
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
@@ -7,12 +7,10 @@
- @no_container = true
- page_title _("Pipeline Schedules")
-- if show_new_nav? && can?(current_user, :create_pipeline_schedule, @project)
+- if can?(current_user, :create_pipeline_schedule, @project)
- content_for :breadcrumbs_extra do
= link_to _('New schedule'), new_namespace_project_pipeline_schedule_path(@project.namespace, @project), class: 'btn btn-create'
- - add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
-
= render "projects/pipelines/head"
%div{ class: container_class }
@@ -22,7 +20,7 @@
= render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
- if can?(current_user, :create_pipeline_schedule, @project)
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
= link_to new_project_pipeline_schedule_path(@project), class: 'btn btn-create' do
%span= _('New schedule')
diff --git a/app/views/projects/pipeline_schedules/new.html.haml b/app/views/projects/pipeline_schedules/new.html.haml
index c7237cb96d8..cfdaf6d43bb 100644
--- a/app/views/projects/pipeline_schedules/new.html.haml
+++ b/app/views/projects/pipeline_schedules/new.html.haml
@@ -2,8 +2,7 @@
- @breadcrumb_link = namespace_project_pipeline_schedules_path(@project.namespace, @project)
- page_title _("New Pipeline Schedule")
-- if show_new_nav?
- - add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
+- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
%h3.page-title
= _("Schedule a new pipeline")
diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml
index fd3ad69d85d..487ac87186d 100644
--- a/app/views/projects/pipelines/charts.html.haml
+++ b/app/views/projects/pipelines/charts.html.haml
@@ -1,7 +1,6 @@
- @no_container = true
+- breadcrumb_title "CI / CD Charts"
- page_title _("Charts"), _("Pipelines")
-- if show_new_nav?
- - add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs')
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
index 63f85fc69a2..7cc9fe79afd 100644
--- a/app/views/projects/pipelines/show.html.haml
+++ b/app/views/projects/pipelines/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Pipelines", project_pipelines_path(@project)
+- breadcrumb_title "##{@pipeline.id}"
- page_title "Pipeline"
= render "projects/pipelines/head"
diff --git a/app/views/projects/pipelines_settings/_badge.html.haml b/app/views/projects/pipelines_settings/_badge.html.haml
index 3de518c8b9a..e8028059487 100644
--- a/app/views/projects/pipelines_settings/_badge.html.haml
+++ b/app/views/projects/pipelines_settings/_badge.html.haml
@@ -1,34 +1,32 @@
%div{ class: badge.title.gsub(' ', '-') }
- .col-lg-4.profile-settings-sidebar
- %h4.prepend-top-0
+ .col-lg-12
+ %h4
= badge.title.capitalize
- .col-lg-8
- .prepend-top-10
- .panel.panel-default
- .panel-heading
- %b
- = badge.title.capitalize
- &middot;
- = badge.to_html
- .pull-right
- = render 'shared/ref_switcher', destination: 'badges', align_right: true
- .panel-body
- .row
- .col-md-2.text-center
- Markdown
- .col-md-10.code.js-syntax-highlight
- = highlight('.md', badge.to_markdown)
- .row
- %hr
- .row
- .col-md-2.text-center
- HTML
- .col-md-10.code.js-syntax-highlight
- = highlight('.html', badge.to_html)
- .row
- %hr
- .row
- .col-md-2.text-center
- AsciiDoc
- .col-md-10.code.js-syntax-highlight
- = highlight('.adoc', badge.to_asciidoc)
+ .panel.panel-default
+ .panel-heading
+ %b
+ = badge.title.capitalize
+ &middot;
+ = badge.to_html
+ .pull-right
+ = render 'shared/ref_switcher', destination: 'badges', align_right: true
+ .panel-body
+ .row
+ .col-md-2.text-center
+ Markdown
+ .col-md-10.code.js-syntax-highlight
+ = highlight('.md', badge.to_markdown)
+ .row
+ %hr
+ .row
+ .col-md-2.text-center
+ HTML
+ .col-md-10.code.js-syntax-highlight
+ = highlight('.html', badge.to_html)
+ .row
+ %hr
+ .row
+ .col-md-2.text-center
+ AsciiDoc
+ .col-md-10.code.js-syntax-highlight
+ = highlight('.adoc', badge.to_asciidoc)
diff --git a/app/views/projects/pipelines_settings/_show.html.haml b/app/views/projects/pipelines_settings/_show.html.haml
index d407e187df0..8bf76b646f7 100644
--- a/app/views/projects/pipelines_settings/_show.html.haml
+++ b/app/views/projects/pipelines_settings/_show.html.haml
@@ -1,8 +1,5 @@
.row.prepend-top-default
- .col-lg-4.profile-settings-sidebar
- %h4.prepend-top-0
- Pipelines
- .col-lg-8
+ .col-lg-12
= form_for @project, url: project_pipelines_settings_path(@project) do |f|
%fieldset.builds-feature
- unless @repository.gitlab_ci_yml
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index 9f7c5a315eb..25153fd0b6f 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -1,8 +1,5 @@
- page_title "Members"
-- if show_new_nav?
- - add_to_breadcrumbs("Settings", edit_project_path(@project))
-
.row.prepend-top-default
.col-lg-12
%h4
diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml
index 0a5a38a3694..c786298e341 100644
--- a/app/views/projects/releases/edit.html.haml
+++ b/app/views/projects/releases/edit.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Tags", project_tags_path(@project)
+- breadcrumb_title @tag.name
- page_title "Edit", @tag.name, "Tags"
= render "projects/commits/head"
diff --git a/app/views/projects/services/edit.html.haml b/app/views/projects/services/edit.html.haml
index 8056217bb1e..3e2a24a4c32 100644
--- a/app/views/projects/services/edit.html.haml
+++ b/app/views/projects/services/edit.html.haml
@@ -1,8 +1,6 @@
- breadcrumb_title "Integrations"
- page_title @service.title, "Services"
-
-- if show_new_nav?
- - add_to_breadcrumbs("Settings", edit_project_path(@project))
+- add_to_breadcrumbs("Settings", edit_project_path(@project))
= render "projects/settings/head"
= render 'form'
diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml
index 0c4130857da..eaf374bcb83 100644
--- a/app/views/projects/settings/ci_cd/show.html.haml
+++ b/app/views/projects/settings/ci_cd/show.html.haml
@@ -1,12 +1,54 @@
- @content_class = "limit-container-width" unless fluid_layout
-- page_title "Pipelines"
-
-- if show_new_nav?
- - add_to_breadcrumbs("Settings", edit_project_path(@project))
+- page_title "CI / CD Settings"
+- page_title "CI / CD"
= render "projects/settings/head"
-= render 'projects/runners/index'
-= render 'ci/variables/index'
-= render 'projects/triggers/index'
-= render 'projects/pipelines_settings/show'
+- expanded = Rails.env.test?
+
+%section.settings
+ .settings-header
+ %h4
+ General pipelines settings
+ %button.btn.js-settings-toggle
+ = expanded ? 'Collapse' : 'Expand'
+ %p
+ Update your CI/CD configuration, like job timeout.
+ .settings-content.no-animate{ class: ('expanded' if expanded) }
+ = render 'projects/pipelines_settings/show'
+
+%section.settings
+ .settings-header
+ %h4
+ Runners settings
+ %button.btn.js-settings-toggle
+ = expanded ? 'Collapse' : 'Expand'
+ %p
+ Register and see your runners for this project.
+ .settings-content.no-animate{ class: ('expanded' if expanded) }
+ = render 'projects/runners/index'
+
+%section.settings
+ .settings-header
+ %h4
+ Secret variables
+ = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'secret-variables'), target: '_blank'
+ %button.btn.js-settings-toggle
+ = expanded ? 'Collapse' : 'Expand'
+ %p
+ = render "ci/variables/content"
+ .settings-content.no-animate{ class: ('expanded' if expanded) }
+ = render 'ci/variables/index'
+
+%section.settings
+ .settings-header
+ %h4
+ Pipeline triggers
+ %button.btn.js-settings-toggle
+ = expanded ? 'Collapse' : 'Expand'
+ %p
+ Triggers can force a specific branch or tag to get rebuilt with an API call. These tokens will
+ impersonate their associated user including their access to projects and their project
+ permissions.
+ .settings-content.no-animate{ class: ('expanded' if expanded) }
+ = render 'projects/triggers/index'
diff --git a/app/views/projects/settings/integrations/show.html.haml b/app/views/projects/settings/integrations/show.html.haml
index 149da96d3f6..933daa7f549 100644
--- a/app/views/projects/settings/integrations/show.html.haml
+++ b/app/views/projects/settings/integrations/show.html.haml
@@ -1,7 +1,6 @@
- @content_class = "limit-container-width" unless fluid_layout
+- breadcrumb_title "Integrations Settings"
- page_title 'Integrations'
-- if show_new_nav?
- - add_to_breadcrumbs("Settings", edit_project_path(@project))
= render "projects/settings/head"
= render 'projects/hooks/index'
= render 'projects/services/index'
diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml
index cb37f3c7580..6d4af72b8ea 100644
--- a/app/views/projects/settings/repository/show.html.haml
+++ b/app/views/projects/settings/repository/show.html.haml
@@ -1,9 +1,7 @@
+- breadcrumb_title "Repository Settings"
- page_title "Repository"
- @content_class = "limit-container-width" unless fluid_layout
-- if show_new_nav?
- - add_to_breadcrumbs("Settings", edit_project_path(@project))
-
= render "projects/settings/head"
- content_for :page_specific_javascripts do
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index a9b39cedb1d..3f0a24cfe83 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,5 +1,5 @@
- @no_container = true
-- breadcrumb_title "Project"
+- breadcrumb_title "Details"
- @content_class = "limit-container-width" unless fluid_layout
= content_for :meta_tags do
diff --git a/app/views/projects/snippets/edit.html.haml b/app/views/projects/snippets/edit.html.haml
index d41cc8e0425..32844f5204a 100644
--- a/app/views/projects/snippets/edit.html.haml
+++ b/app/views/projects/snippets/edit.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Snippets", project_snippets_path(@project)
+- breadcrumb_title @snippet.to_reference
- page_title "Edit", "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
%h3.page-title
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index ccc5fe80755..1803e7f7211 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -1,6 +1,6 @@
- page_title "Snippets"
-- if show_new_nav? && can?(current_user, :create_project_snippet, @project)
+- if can?(current_user, :create_project_snippet, @project)
- content_for :breadcrumbs_extra do
= link_to "New snippet", new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New snippet"
@@ -9,7 +9,7 @@
- include_private = @project.team.member?(current_user) || current_user.admin?
= render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private }
- .nav-controls{ class: ("visible-xs" if show_new_nav?) }
+ .nav-controls.visible-xs
- if can?(current_user, :create_project_snippet, @project)
= link_to "New snippet", new_project_snippet_path(@project), class: "btn btn-new", title: "New snippet"
diff --git a/app/views/projects/snippets/new.html.haml b/app/views/projects/snippets/new.html.haml
index d3e6b456f48..1359a815429 100644
--- a/app/views/projects/snippets/new.html.haml
+++ b/app/views/projects/snippets/new.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Snippets", project_snippets_path(@project)
+- breadcrumb_title "New"
- page_title "New Snippets"
%h3.page-title
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index d8e448dd2af..fda068f08c2 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -1,4 +1,6 @@
- @content_class = "limit-container-width limited-inner-width-container" unless fluid_layout
+- add_to_breadcrumbs "Snippets", dashboard_snippets_path
+- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
= render 'shared/snippets/header'
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index 00000e0667c..a6fe02fcae0 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -1,11 +1,9 @@
- @no_container = true
- @sort ||= sort_value_recently_updated
- page_title "Tags"
+- add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
-- if show_new_nav?
- - add_to_breadcrumbs("Repository", project_tree_path(@project))
-
.flex-list{ class: container_class }
.top-area.adjust
.nav-text.row-main-content
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index d02cd70f4c3..5d6eb4f4026 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Tags", project_tags_path(@project)
+- breadcrumb_title @tag.name
- page_title @tag.name, "Tags"
= render "projects/commits/head"
diff --git a/app/views/projects/tree/_tree_commit_column.html.haml b/app/views/projects/tree/_tree_commit_column.html.haml
index f3d4706809f..abb3e918e87 100644
--- a/app/views/projects/tree/_tree_commit_column.html.haml
+++ b/app/views/projects/tree/_tree_commit_column.html.haml
@@ -1,2 +1,2 @@
%span.str-truncated
- = link_to_gfm commit.full_title, project_commit_path(@project, commit.id), class: "tree-commit-link"
+ = link_to_markdown commit.full_title, project_commit_path(@project, commit.id), class: "tree-commit-link"
diff --git a/app/views/projects/triggers/_content.html.haml b/app/views/projects/triggers/_content.html.haml
index ea32eac2ae2..6c2d603d95d 100644
--- a/app/views/projects/triggers/_content.html.haml
+++ b/app/views/projects/triggers/_content.html.haml
@@ -1,14 +1,8 @@
-%h4.prepend-top-0
- Triggers
-%p.prepend-top-20
- Triggers can force a specific branch or tag to get rebuilt with an API call. These tokens will
- impersonate their associated user including their access to projects and their project
- permissions.
-%p.prepend-top-20
+%p.append-bottom-default
Triggers with the
%span.label.label-primary legacy
label do not have an associated user and only have access to the current project.
-%p.append-bottom-0
+ %br
= succeed '.' do
Learn more in the
= link_to 'triggers documentation', help_page_path('ci/triggers/README'), target: '_blank'
diff --git a/app/views/projects/triggers/_index.html.haml b/app/views/projects/triggers/_index.html.haml
index e9a2f803edd..0f655e4ed83 100644
--- a/app/views/projects/triggers/_index.html.haml
+++ b/app/views/projects/triggers/_index.html.haml
@@ -1,7 +1,6 @@
.row.prepend-top-default.append-bottom-default.triggers-container
- .col-lg-4
+ .col-lg-12
= render "projects/triggers/content"
- .col-lg-8
.panel.panel-default
.panel-heading
%h4.panel-title
diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml
index dece1fad0bb..d533c611a38 100644
--- a/app/views/projects/wikis/pages.html.haml
+++ b/app/views/projects/wikis/pages.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Wiki", get_project_wiki_path(@project)
+- breadcrumb_title "Pages"
- page_title "Pages", "Wiki"
%div{ class: container_class }
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index 9dadd685ea2..b066a812ec8 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -1,14 +1,13 @@
- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout
-- breadcrumb_title "Wiki"
+- 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)
.wiki-page-header.has-sidebar-toggle
%button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
= icon('angle-double-left')
- .wiki-breadcrumb
- %span= breadcrumb(@page.slug)
-
.nav-text
%h2.wiki-page-title= @page.title.capitalize
%span.wiki-last-edit-by
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index b07bc45512f..0afa48b392c 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -3,7 +3,7 @@
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('sidebar')
-%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { "offset-top" => ("50" unless show_new_nav?), "spy" => ("affix" unless show_new_nav?), signed: { in: current_user.present? } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
+%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: current_user.present? } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
.issuable-sidebar{ data: { endpoint: "#{issuable_json_path(issuable)}" } }
- can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.block.issuable-sidebar-header
diff --git a/app/views/shared/notes/_note.html.haml b/app/views/shared/notes/_note.html.haml
index 7174855e176..4f00a9f2759 100644
--- a/app/views/shared/notes/_note.html.haml
+++ b/app/views/shared/notes/_note.html.haml
@@ -28,7 +28,7 @@
commented
- if note.system
%span.system-note-message
- = note.redacted_note_html
+ = markdown_field(note, :note)
%a{ href: "##{dom_id(note)}" }
= time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note-created-ago')
- unless note.system?
@@ -39,7 +39,7 @@
= render 'projects/notes/actions', note: note, note_editable: note_editable
.note-body{ class: note_editable ? 'js-task-list-container' : '' }
.note-text.md
- = note.redacted_note_html
+ = markdown_field(note, :note)
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago')
.original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore } }
#{note.note}
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index f4f155c8d94..52a8fe8bb67 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -31,8 +31,7 @@
- if show_last_commit_as_description
.description.prepend-top-5
- = link_to_gfm project.commit.title, project_commit_path(project, project.commit),
- class: "commit-row-message"
+ = link_to_markdown(project.commit.title, project_commit_path(project, project.commit), class: "commit-row-message")
- elsif project.description.present?
.description.prepend-top-5
= markdown_field(project, :description)
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
index 17b34c5eeb3..119d189f21d 100644
--- a/app/views/shared/snippets/_header.html.haml
+++ b/app/views/shared/snippets/_header.html.haml
@@ -3,10 +3,8 @@
%span.sr-only
= visibility_level_label(@snippet.visibility_level)
= visibility_level_icon(@snippet.visibility_level, fw: false)
- %strong.item-title
- Snippet #{@snippet.to_reference}
%span.creator
- authored
+ Authored
= time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title", avatar_class: "hidden-xs")}
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 706f13dd004..578327883e5 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -1,5 +1,7 @@
- @hide_top_links = true
- @content_class = "limit-container-width limited-inner-width-container" unless fluid_layout
+- add_to_breadcrumbs "Snippets", dashboard_snippets_path
+- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
= render 'shared/snippets/header'
diff --git a/changelogs/unreleased/12968-generalize-profile-updates.yml b/changelogs/unreleased/12968-generalize-profile-updates.yml
new file mode 100644
index 00000000000..d09793512c1
--- /dev/null
+++ b/changelogs/unreleased/12968-generalize-profile-updates.yml
@@ -0,0 +1,4 @@
+---
+title: Generalize profile updates from providers
+merge_request: 12968
+author: Alexandros Keramidas
diff --git a/changelogs/unreleased/19650-remove-admin-section-from-search-results-if-user-doesnt-have-access.yml b/changelogs/unreleased/19650-remove-admin-section-from-search-results-if-user-doesnt-have-access.yml
new file mode 100644
index 00000000000..6d5baa8c10f
--- /dev/null
+++ b/changelogs/unreleased/19650-remove-admin-section-from-search-results-if-user-doesnt-have-access.yml
@@ -0,0 +1,5 @@
+---
+title: Hide admin link from default search results for non-admins
+merge_request: 14015
+author:
+type: fixed
diff --git a/changelogs/unreleased/34509-improves-markdown-rendering-performance-for-commits-list.yml b/changelogs/unreleased/34509-improves-markdown-rendering-performance-for-commits-list.yml
new file mode 100644
index 00000000000..a61d703bacd
--- /dev/null
+++ b/changelogs/unreleased/34509-improves-markdown-rendering-performance-for-commits-list.yml
@@ -0,0 +1,5 @@
+---
+title: Improves markdown rendering performance for commit lists.
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/35161_first_time_contributor_badge.yml b/changelogs/unreleased/35161_first_time_contributor_badge.yml
new file mode 100644
index 00000000000..f3ab2d9db31
--- /dev/null
+++ b/changelogs/unreleased/35161_first_time_contributor_badge.yml
@@ -0,0 +1,4 @@
+---
+title: "First-time contributor badge"
+merge_request: 13143
+author: Micaël Bergeron <micaelbergeron@gmail.com>
diff --git a/changelogs/unreleased/35441-fix-division-by-zero.yml b/changelogs/unreleased/35441-fix-division-by-zero.yml
new file mode 100644
index 00000000000..335b2d40494
--- /dev/null
+++ b/changelogs/unreleased/35441-fix-division-by-zero.yml
@@ -0,0 +1,5 @@
+---
+title: Fix division by zero error in blame age mapping
+merge_request: 13803
+author: Jeff Stubler
+type: fixed
diff --git a/changelogs/unreleased/35942-api-binary-encoding.yaml b/changelogs/unreleased/35942-api-binary-encoding.yaml
new file mode 100644
index 00000000000..4f7960d860e
--- /dev/null
+++ b/changelogs/unreleased/35942-api-binary-encoding.yaml
@@ -0,0 +1,3 @@
+---
+title: "Fix API to serve binary diffs that are treated as text."
+merge_request: 14038
diff --git a/changelogs/unreleased/36859-update-gpg-docs-with-gpg2.yml b/changelogs/unreleased/36859-update-gpg-docs-with-gpg2.yml
new file mode 100644
index 00000000000..e48a5704fdd
--- /dev/null
+++ b/changelogs/unreleased/36859-update-gpg-docs-with-gpg2.yml
@@ -0,0 +1,5 @@
+---
+title: Update gpg documentation with gpg2
+merge_request: 13851
+author: M M Arif
+type: other
diff --git a/changelogs/unreleased/36994-toggle-for-automatically-collapsing-outdated-diff-comments.yml b/changelogs/unreleased/36994-toggle-for-automatically-collapsing-outdated-diff-comments.yml
new file mode 100644
index 00000000000..83f6b2d21e1
--- /dev/null
+++ b/changelogs/unreleased/36994-toggle-for-automatically-collapsing-outdated-diff-comments.yml
@@ -0,0 +1,5 @@
+---
+title: Add repository toggle for automatically resolving outdated diff discussions
+merge_request: 14053
+author: AshleyDumaine
+type: added
diff --git a/changelogs/unreleased/collapsable-pipeline-settings.yml b/changelogs/unreleased/collapsable-pipeline-settings.yml
new file mode 100644
index 00000000000..d41959f8ab0
--- /dev/null
+++ b/changelogs/unreleased/collapsable-pipeline-settings.yml
@@ -0,0 +1,5 @@
+---
+title: Add collapsable sections for Pipeline Settings
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/feature-gb-download-single-job-artifact-using-api.yml b/changelogs/unreleased/feature-gb-download-single-job-artifact-using-api.yml
new file mode 100644
index 00000000000..920679ca166
--- /dev/null
+++ b/changelogs/unreleased/feature-gb-download-single-job-artifact-using-api.yml
@@ -0,0 +1,5 @@
+---
+title: Make it possible to download a single job artifact file using the API
+merge_request: 14027
+author:
+type: added
diff --git a/changelogs/unreleased/fix-import-export-performance.yml b/changelogs/unreleased/fix-import-export-performance.yml
new file mode 100644
index 00000000000..1f59c4eb179
--- /dev/null
+++ b/changelogs/unreleased/fix-import-export-performance.yml
@@ -0,0 +1,5 @@
+---
+title: Improve Import/Export memory usage
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix_wiki_toc_indent.yml b/changelogs/unreleased/fix_wiki_toc_indent.yml
new file mode 100644
index 00000000000..60da2e455f2
--- /dev/null
+++ b/changelogs/unreleased/fix_wiki_toc_indent.yml
@@ -0,0 +1,5 @@
+---
+title: Wiki table of contents are now properly nested to reflect header level
+merge_request: 13650
+author: Akihiro Nakashima
+type: fixed
diff --git a/changelogs/unreleased/url-sanitizer-fixes.yml b/changelogs/unreleased/url-sanitizer-fixes.yml
new file mode 100644
index 00000000000..769036c829c
--- /dev/null
+++ b/changelogs/unreleased/url-sanitizer-fixes.yml
@@ -0,0 +1,5 @@
+---
+title: Fix problems sanitizing URLs with empty passwords
+merge_request: 14083
+author:
+type: fixed
diff --git a/changelogs/unreleased/winh-dropdown-changelog-docs.yml b/changelogs/unreleased/winh-dropdown-changelog-docs.yml
new file mode 100644
index 00000000000..2f42b4dd9f9
--- /dev/null
+++ b/changelogs/unreleased/winh-dropdown-changelog-docs.yml
@@ -0,0 +1,5 @@
+---
+title: Restyle dropdown menus to make them look consistent
+merge_request:
+author:
+type: other
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index c5704ac5857..e9661090844 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -372,9 +372,16 @@ production: &base
# showing GitLab's sign-in page (default: show the GitLab sign-in page)
# auto_sign_in_with_provider: saml
- # Sync user's email address from the specified Omniauth provider every time the user logs
- # in (default: nil). And consequently make this field read-only.
- # sync_email_from_provider: cas3
+ # Sync user's profile from the specified Omniauth providers every time the user logs in (default: empty).
+ # Define the allowed providers using an array, e.g. ["cas3", "saml", "twitter"],
+ # or as true/false to allow all providers or none.
+ # sync_profile_from_provider: []
+
+ # Select which info to sync from the providers above. (default: email).
+ # Define the synced profile info using an array. Available options are "name", "email" and "location"
+ # e.g. ["name", "email", "location"] or as true to sync all available.
+ # This consequently will make the selected attributes read-only.
+ # sync_profile_attributes: true
# CAUTION!
# This allows users to login without having a user account first. Define the allowed providers
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 360b72cdea3..7c1ca05a57b 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -173,7 +173,20 @@ Settings.omniauth['external_providers'] = [] if Settings.omniauth['external_prov
Settings.omniauth['block_auto_created_users'] = true if Settings.omniauth['block_auto_created_users'].nil?
Settings.omniauth['auto_link_ldap_user'] = false if Settings.omniauth['auto_link_ldap_user'].nil?
Settings.omniauth['auto_link_saml_user'] = false if Settings.omniauth['auto_link_saml_user'].nil?
-Settings.omniauth['sync_email_from_provider'] ||= nil
+
+Settings.omniauth['sync_profile_from_provider'] = false if Settings.omniauth['sync_profile_from_provider'].nil?
+Settings.omniauth['sync_profile_attributes'] = ['email'] if Settings.omniauth['sync_profile_attributes'].nil?
+
+# Handle backwards compatibility with merge request 11268
+if Settings.omniauth['sync_email_from_provider']
+ if Settings.omniauth['sync_profile_from_provider'].is_a?(Array)
+ Settings.omniauth['sync_profile_from_provider'] |= [Settings.omniauth['sync_email_from_provider']]
+ elsif !Settings.omniauth['sync_profile_from_provider']
+ Settings.omniauth['sync_profile_from_provider'] = [Settings.omniauth['sync_email_from_provider']]
+ end
+
+ Settings.omniauth['sync_profile_attributes'] |= ['email'] unless Settings.omniauth['sync_profile_attributes'] == true
+end
Settings.omniauth['providers'] ||= []
Settings.omniauth['cas3'] ||= Settingslogic.new({})
diff --git a/config/initializers/8_metrics.rb b/config/initializers/8_metrics.rb
index 5b455a8065a..e1a59d8c152 100644
--- a/config/initializers/8_metrics.rb
+++ b/config/initializers/8_metrics.rb
@@ -114,9 +114,6 @@ def instrument_classes(instrumentation)
# This is a Rails scope so we have to instrument it manually.
instrumentation.instrument_method(Project, :visible_to_user)
- # Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/34509
- instrumentation.instrument_method(MarkupHelper, :link_to_gfm)
-
# Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/30224#note_32306159
instrumentation.instrument_instance_method(MergeRequestDiff, :load_commits)
diff --git a/db/migrate/20170820120108_create_user_synced_attributes_metadata.rb b/db/migrate/20170820120108_create_user_synced_attributes_metadata.rb
new file mode 100644
index 00000000000..79028e34987
--- /dev/null
+++ b/db/migrate/20170820120108_create_user_synced_attributes_metadata.rb
@@ -0,0 +1,15 @@
+class CreateUserSyncedAttributesMetadata < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ create_table :user_synced_attributes_metadata do |t|
+ t.boolean :name_synced, default: false
+ t.boolean :email_synced, default: false
+ t.boolean :location_synced, default: false
+ t.references :user, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
+ t.string :provider
+ end
+ end
+end
diff --git a/db/migrate/20170825104051_migrate_issues_to_ghost_user.rb b/db/migrate/20170825104051_migrate_issues_to_ghost_user.rb
index 294141e4fdb..c5fb5762d61 100644
--- a/db/migrate/20170825104051_migrate_issues_to_ghost_user.rb
+++ b/db/migrate/20170825104051_migrate_issues_to_ghost_user.rb
@@ -18,6 +18,7 @@ class MigrateIssuesToGhostUser < ActiveRecord::Migration
ActiveRecord::Base.clear_cache!
::User.reset_column_information
+ ::Namespace.reset_column_information
end
def up
diff --git a/db/migrate/20170825154015_resolve_outdated_diff_discussions.rb b/db/migrate/20170825154015_resolve_outdated_diff_discussions.rb
new file mode 100644
index 00000000000..235530bb1e6
--- /dev/null
+++ b/db/migrate/20170825154015_resolve_outdated_diff_discussions.rb
@@ -0,0 +1,9 @@
+class ResolveOutdatedDiffDiscussions < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ add_column(:projects, :resolve_outdated_diff_discussions, :boolean)
+ end
+end
diff --git a/db/migrate/20170828135939_migrate_user_external_mail_data.rb b/db/migrate/20170828135939_migrate_user_external_mail_data.rb
new file mode 100644
index 00000000000..592e141b7e6
--- /dev/null
+++ b/db/migrate/20170828135939_migrate_user_external_mail_data.rb
@@ -0,0 +1,57 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class MigrateUserExternalMailData < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class User < ActiveRecord::Base
+ self.table_name = 'users'
+
+ include EachBatch
+ end
+
+ class UserSyncedAttributesMetadata < ActiveRecord::Base
+ self.table_name = 'user_synced_attributes_metadata'
+
+ include EachBatch
+ end
+
+ def up
+ User.each_batch do |batch|
+ start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
+
+ execute <<-EOF
+ INSERT INTO user_synced_attributes_metadata (user_id, provider, email_synced)
+ SELECT id, email_provider, external_email
+ FROM users
+ WHERE external_email = TRUE
+ AND NOT EXISTS (
+ SELECT true
+ FROM user_synced_attributes_metadata
+ WHERE user_id = users.id
+ AND provider = users.email_provider
+ )
+ AND id BETWEEN #{start_id} AND #{end_id}
+ EOF
+ end
+ end
+
+ def down
+ UserSyncedAttributesMetadata.each_batch do |batch|
+ start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
+
+ execute <<-EOF
+ UPDATE users
+ SET users.email_provider = metadata.provider, users.external_email = metadata.email_synced
+ FROM user_synced_attributes_metadata as metadata, users
+ WHERE metadata.email_synced = TRUE
+ AND metadata.user_id = users.id
+ AND id BETWEEN #{start_id} AND #{end_id}
+ EOF
+ end
+ end
+end
diff --git a/db/migrate/20170905112933_add_resolved_by_push_to_notes.rb b/db/migrate/20170905112933_add_resolved_by_push_to_notes.rb
new file mode 100644
index 00000000000..ceb31ffb08a
--- /dev/null
+++ b/db/migrate/20170905112933_add_resolved_by_push_to_notes.rb
@@ -0,0 +1,9 @@
+class AddResolvedByPushToNotes < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ add_column :notes, :resolved_by_push, :boolean
+ end
+end
diff --git a/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb b/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb
new file mode 100644
index 00000000000..fefd931e5d2
--- /dev/null
+++ b/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb
@@ -0,0 +1,57 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class PostDeployMigrateUserExternalMailData < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class User < ActiveRecord::Base
+ self.table_name = 'users'
+
+ include EachBatch
+ end
+
+ class UserSyncedAttributesMetadata < ActiveRecord::Base
+ self.table_name = 'user_synced_attributes_metadata'
+
+ include EachBatch
+ end
+
+ def up
+ User.each_batch do |batch|
+ start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
+
+ execute <<-EOF
+ INSERT INTO user_synced_attributes_metadata (user_id, provider, email_synced)
+ SELECT id, email_provider, external_email
+ FROM users
+ WHERE external_email = TRUE
+ AND NOT EXISTS (
+ SELECT true
+ FROM user_synced_attributes_metadata
+ WHERE user_id = users.id
+ AND provider = users.email_provider
+ )
+ AND id BETWEEN #{start_id} AND #{end_id}
+ EOF
+ end
+ end
+
+ def down
+ UserSyncedAttributesMetadata.each_batch do |batch|
+ start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
+
+ execute <<-EOF
+ UPDATE users
+ SET users.email_provider = metadata.provider, users.external_email = metadata.email_synced
+ FROM user_synced_attributes_metadata as metadata, users
+ WHERE metadata.email_synced = TRUE
+ AND metadata.user_id = users.id
+ AND id BETWEEN #{start_id} AND #{end_id}
+ EOF
+ end
+ end
+end
diff --git a/db/post_migrate/20170828170513_remove_user_email_provider_column.rb b/db/post_migrate/20170828170513_remove_user_email_provider_column.rb
new file mode 100644
index 00000000000..570f2b3772a
--- /dev/null
+++ b/db/post_migrate/20170828170513_remove_user_email_provider_column.rb
@@ -0,0 +1,12 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveUserEmailProviderColumn < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ remove_column :users, :email_provider, :string
+ end
+end
diff --git a/db/post_migrate/20170828170516_remove_user_external_mail_columns.rb b/db/post_migrate/20170828170516_remove_user_external_mail_columns.rb
new file mode 100644
index 00000000000..bb81dc682b3
--- /dev/null
+++ b/db/post_migrate/20170828170516_remove_user_external_mail_columns.rb
@@ -0,0 +1,12 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveUserExternalMailColumns < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ remove_column :users, :external_email, :boolean
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f980667a38f..1c1a5e63bc4 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: 20170901071411) do
+ActiveRecord::Schema.define(version: 20170905112933) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -1002,6 +1002,7 @@ ActiveRecord::Schema.define(version: 20170901071411) do
t.text "note_html"
t.integer "cached_markdown_version"
t.text "change_position"
+ t.boolean "resolved_by_push"
end
add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
@@ -1219,6 +1220,7 @@ ActiveRecord::Schema.define(version: 20170901071411) do
t.string "ci_config_path"
t.text "delete_error"
t.integer "storage_version", limit: 2
+ t.boolean "resolve_outdated_diff_discussions"
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
@@ -1537,6 +1539,16 @@ ActiveRecord::Schema.define(version: 20170901071411) do
add_index "user_agent_details", ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree
+ create_table "user_synced_attributes_metadata", force: :cascade do |t|
+ t.boolean "name_synced", default: false
+ t.boolean "email_synced", default: false
+ t.boolean "location_synced", default: false
+ t.integer "user_id", null: false
+ t.string "provider"
+ end
+
+ add_index "user_synced_attributes_metadata", ["user_id"], name: "index_user_synced_attributes_metadata_on_user_id", unique: true, using: :btree
+
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
@@ -1602,8 +1614,6 @@ ActiveRecord::Schema.define(version: 20170901071411) do
t.boolean "notified_of_own_activity"
t.string "preferred_language"
t.string "rss_token"
- t.boolean "external_email", default: false, null: false
- t.string "email_provider"
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
@@ -1754,6 +1764,7 @@ ActiveRecord::Schema.define(version: 20170901071411) do
add_foreign_key "todos", "projects", name: "fk_45054f9c45", on_delete: :cascade
add_foreign_key "trending_projects", "projects", on_delete: :cascade
add_foreign_key "u2f_registrations", "users"
+ add_foreign_key "user_synced_attributes_metadata", "users", on_delete: :cascade
add_foreign_key "users_star_projects", "projects", name: "fk_22cd27ddfc", on_delete: :cascade
add_foreign_key "web_hook_logs", "web_hooks", on_delete: :cascade
add_foreign_key "web_hooks", "projects", name: "fk_0c8ca6d9d1", on_delete: :cascade
diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md
index ee680c7b258..68efe0aae5c 100644
--- a/doc/administration/monitoring/performance/performance_bar.md
+++ b/doc/administration/monitoring/performance/performance_bar.md
@@ -5,17 +5,17 @@ activated, it looks as follows:
![Performance Bar](img/performance_bar.png)
-It allows you to:
+It allows you to see (from left to right):
-- see the current host serving the page
-- see the timing of the page (backend, frontend)
-- the number of DB queries, the time it took, and the detail of these queries
+- the current host serving the page
+- the timing of the page (backend, frontend)
+- time taken and number of DB queries, click through for details of these queries
![SQL profiling using the Performance Bar](img/performance_bar_sql_queries.png)
-- the number of calls to Redis, and the time it took
-- the number of background jobs created by Sidekiq, and the time it took
-- the number of Ruby GC calls, and the time it took
-- profile the code used to generate the page, line by line
+- time taken and number of calls to Redis
+- time taken and number of background jobs created by Sidekiq
+- profile of the code used to generate the page, line by line for either _all_, _app & lib_ , or _views_. In the profile view, the numbers in the left panel represent wall time, cpu time, and number of calls (based on [rblineprof](https://github.com/tmm1/rblineprof)).
![Line profiling using the Performance Bar](img/performance_bar_line_profiling.png)
+- time taken and number of Ruby GC calls
## Enable the Performance Bar via the Admin panel
diff --git a/doc/api/README.md b/doc/api/README.md
index a947eed2db8..db61497db53 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -237,8 +237,8 @@ The following table gives an overview of how the API functions generally behave.
| ------------ | ----------- |
| `GET` | Access one or more resources and return the result as JSON. |
| `POST` | Return `201 Created` if the resource is successfully created and return the newly created resource as JSON. |
-| `GET` / `PUT` / `DELETE` | Return `200 OK` if the resource is accessed, modified or deleted successfully. The (modified) result is returned as JSON. |
-| `DELETE` | Designed to be idempotent, meaning a request to a resource still returns `200 OK` even it was deleted before or is not available. The reasoning behind this, is that the user is not really interested if the resource existed before or not. |
+| `GET` / `PUT` | Return `200 OK` if the resource is accessed or modified successfully. The (modified) result is returned as JSON. |
+| `DELETE` | Returns `204 No Content` if the resuource was deleted successfully. |
The following table shows the possible return codes for API requests.
diff --git a/doc/api/environments.md b/doc/api/environments.md
index 5ca766bf87d..e8deb3e07e9 100644
--- a/doc/api/environments.md
+++ b/doc/api/environments.md
@@ -94,7 +94,7 @@ Example response:
## Delete an environment
-It returns `200` if the environment was successfully deleted, and `404` if the environment does not exist.
+It returns `204` if the environment was successfully deleted, and `404` if the environment does not exist.
```
DELETE /projects/:id/environments/:environment_id
diff --git a/doc/api/jobs.md b/doc/api/jobs.md
index 297115e94ac..d60c7c12881 100644
--- a/doc/api/jobs.md
+++ b/doc/api/jobs.md
@@ -320,11 +320,11 @@ Response:
[ce-2893]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2893
-## Download the artifacts file
+## Download the artifacts archive
> [Introduced][ce-5347] in GitLab 8.10.
-Download the artifacts file from the given reference name and job provided the
+Download the artifacts archive from the given reference name and job provided the
job finished successfully.
```
@@ -354,6 +354,40 @@ Example response:
[ce-5347]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5347
+## Download a single artifact file
+
+> Introduced in GitLab 10.0
+
+Download a single artifact file from within the job's artifacts archive.
+
+Only a single file is going to be extracted from the archive and streamed to a client.
+
+```
+GET /projects/:id/jobs/:job_id/artifacts/*artifact_path
+```
+
+Parameters
+
+| Attribute | Type | Required | Description |
+|-----------------|---------|----------|-------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `job_id ` | integer | yes | The unique job identifier |
+| `artifact_path` | string | yes | Path to a file inside the artifacts archive |
+
+Example request:
+
+```
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/jobs/5/artifacts/some/release/file.pdf"
+```
+
+Example response:
+
+| Status | Description |
+|-----------|--------------------------------------|
+| 200 | Sends a single artifact file |
+| 400 | Invalid path provided |
+| 404 | Build not found or no file/artifacts |
+
## Get a trace file
Get a trace of a specific job of a project
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index 24c8ff5fa7a..ad2521230e6 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -95,8 +95,7 @@ Parameters:
## Delete snippet
-Deletes an existing project snippet. This is an idempotent function and deleting a non-existent
-snippet still returns a `200 OK` status code.
+Deletes an existing project snippet. This returns a `204 No Content` status code if the operation was successfully or `404` if the resource was not found.
```
DELETE /projects/:id/snippets/:snippet_id
diff --git a/doc/api/projects.md b/doc/api/projects.md
index d3f8e509612..3144220e588 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1,6 +1,6 @@
# Projects API
-### Project visibility level
+## Project visibility level
Project in GitLab can be either private, internal or public.
This is determined by the `visibility` field in the project.
@@ -16,16 +16,15 @@ Values for the project visibility level are:
* `public`:
The project can be cloned without any authentication.
-## List projects
+## List all projects
-Get a list of visible projects for authenticated user. When accessed without authentication, only public projects are returned.
+Get a list of all visible projects across GitLab for the authenticated user.
+When accessed without authentication, only public projects are returned.
```
GET /projects
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `archived` | boolean | no | Limit by archived status |
@@ -70,6 +69,7 @@ Parameters:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -137,6 +137,7 @@ Parameters:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -191,16 +192,15 @@ Parameters:
]
```
-### List a user's projects
+## List user projects
-Get a list of visible projects for the given user. When accessed without authentication, only public projects are returned.
+Get a list of visible projects for the given user. When accessed without
+authentication, only public projects are returned.
```
GET /users/:user_id/projects
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `user_id` | string | yes | The ID or username of the user |
@@ -246,6 +246,7 @@ Parameters:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -313,6 +314,7 @@ Parameters:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -367,7 +369,7 @@ Parameters:
]
```
-### Get single project
+## Get single project
Get a specific project. This endpoint can be accessed without authentication if
the project is publicly accessible.
@@ -376,8 +378,6 @@ the project is publicly accessible.
GET /projects/:id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -411,6 +411,7 @@ Parameters:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -480,17 +481,14 @@ Parameters:
Get the users list of a project.
-
-Parameters:
+```
+GET /projects/:id/users
+```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `search` | string | no | Search for specific users |
-```
-GET /projects/:id/users
-```
-
```json
[
{
@@ -512,11 +510,11 @@ GET /projects/:id/users
]
```
-### Get project events
+## Get project events
-Please refer to the [Events API documentation](events.md#list-a-projects-visible-events)
+Please refer to the [Events API documentation](events.md#list-a-projects-visible-events).
-### Create project
+## Create project
Creates a new project owned by the authenticated user.
@@ -524,8 +522,6 @@ Creates a new project owned by the authenticated user.
POST /projects
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `name` | string | yes if path is not provided | The name of the new project. Equals path if not provided. |
@@ -537,6 +533,7 @@ Parameters:
| `jobs_enabled` | boolean | no | Enable jobs for this project |
| `wiki_enabled` | boolean | no | Enable wiki for this project |
| `snippets_enabled` | boolean | no | Enable snippets for this project |
+| `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push |
| `container_registry_enabled` | boolean | no | Enable container registry for this project |
| `shared_runners_enabled` | boolean | no | Enable shared runners for this project |
| `visibility` | string | no | See [project visibility level](#project-visibility-level) |
@@ -551,7 +548,7 @@ Parameters:
| `printing_merge_request_link_enabled` | boolean | no | Show link to create/view merge request when pushing from the command line |
| `ci_config_path` | string | no | The path to CI config file |
-### Create project for user
+## Create project for user
Creates a new project owned by the specified user. Available only for admins.
@@ -559,8 +556,6 @@ Creates a new project owned by the specified user. Available only for admins.
POST /projects/user/:user_id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `user_id` | integer | yes | The user ID of the project owner |
@@ -574,6 +569,7 @@ Parameters:
| `jobs_enabled` | boolean | no | Enable jobs for this project |
| `wiki_enabled` | boolean | no | Enable wiki for this project |
| `snippets_enabled` | boolean | no | Enable snippets for this project |
+| `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push |
| `container_registry_enabled` | boolean | no | Enable container registry for this project |
| `shared_runners_enabled` | boolean | no | Enable shared runners for this project |
| `visibility` | string | no | See [project visibility level](#project-visibility-level) |
@@ -588,7 +584,7 @@ Parameters:
| `printing_merge_request_link_enabled` | boolean | no | Show link to create/view merge request when pushing from the command line |
| `ci_config_path` | string | no | The path to CI config file |
-### Edit project
+## Edit project
Updates an existing project.
@@ -596,8 +592,6 @@ Updates an existing project.
PUT /projects/:id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -610,6 +604,7 @@ Parameters:
| `jobs_enabled` | boolean | no | Enable jobs for this project |
| `wiki_enabled` | boolean | no | Enable wiki for this project |
| `snippets_enabled` | boolean | no | Enable snippets for this project |
+| `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push |
| `container_registry_enabled` | boolean | no | Enable container registry for this project |
| `shared_runners_enabled` | boolean | no | Enable shared runners for this project |
| `visibility` | string | no | See [project visibility level](#project-visibility-level) |
@@ -623,24 +618,24 @@ Parameters:
| `avatar` | mixed | no | Image file for avatar of the project |
| `ci_config_path` | string | no | The path to CI config file |
-### Fork project
+## Fork project
Forks a project into the user namespace of the authenticated user or the one provided.
-The forking operation for a project is asynchronous and is completed in a background job. The request will return immediately. To determine whether the fork of the project has completed, query the `import_status` for the new project.
+The forking operation for a project is asynchronous and is completed in a
+background job. The request will return immediately. To determine whether the
+fork of the project has completed, query the `import_status` for the new project.
```
POST /projects/:id/fork
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `namespace` | integer/string | yes | The ID or path of the namespace that the project will be forked to |
-### Star a project
+## Star a project
Stars a given project. Returns status code `304` if the project is already starred.
@@ -648,8 +643,6 @@ Stars a given project. Returns status code `304` if the project is already starr
POST /projects/:id/star
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -683,6 +676,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -717,7 +711,7 @@ Example response:
}
```
-### Unstar a project
+## Unstar a project
Unstars a given project. Returns status code `304` if the project is not starred.
@@ -758,6 +752,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -792,7 +787,7 @@ Example response:
}
```
-### Archive a project
+## Archive a project
Archives the project if the user is either admin or the project owner of this project. This action is
idempotent, thus archiving an already archived project will not change the project.
@@ -839,6 +834,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -885,7 +881,7 @@ Example response:
}
```
-### Unarchive a project
+## Unarchive a project
Unarchives the project if the user is either admin or the project owner of this project. This action is
idempotent, thus unarchiving an non-archived project will not change the project.
@@ -932,6 +928,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
@@ -978,7 +975,7 @@ Example response:
}
```
-### Remove project
+## Remove project
Removes a project including all associated resources (issues, merge requests etc.)
@@ -986,15 +983,11 @@ Removes a project including all associated resources (issues, merge requests etc
DELETE /projects/:id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
-## Uploads
-
-### Upload a file
+## Upload a file
Uploads a file to the specified project to be used in an issue or merge request description, or a comment.
@@ -1002,8 +995,6 @@ Uploads a file to the specified project to be used in an issue or merge request
POST /projects/:id/uploads
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1028,15 +1019,11 @@ Returned object:
}
```
-**Note**: The returned `url` is relative to the project path.
+>**Note**: The returned `url` is relative to the project path.
In Markdown contexts, the link is automatically expanded when the format in
`markdown` is used.
-## Project members
-
-Please consult the [Project Members](members.md) documentation.
-
-### Share project with group
+## Share project with group
Allow to share project with group.
@@ -1044,8 +1031,6 @@ Allow to share project with group.
POST /projects/:id/share
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1053,7 +1038,7 @@ Parameters:
| `group_access` | integer | yes | The permissions level to grant the group |
| `expires_at` | string | no | Share expiration date in ISO 8601 format: 2016-09-26 |
-### Delete a shared project link within a group
+## Delete a shared project link within a group
Unshare the project from the group. Returns `204` and no content on success.
@@ -1061,8 +1046,6 @@ Unshare the project from the group. Returns `204` and no content on success.
DELETE /projects/:id/share/:group_id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1085,8 +1068,6 @@ Get a list of project hooks.
GET /projects/:id/hooks
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1099,8 +1080,6 @@ Get a specific hook for a project.
GET /projects/:id/hooks/:hook_id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1132,8 +1111,6 @@ Adds a hook to a specified project.
POST /projects/:id/hooks
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1157,8 +1134,6 @@ Edits a hook for a specified project.
PUT /projects/:id/hooks/:hook_id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1184,8 +1159,6 @@ Either the hook is available or not.
DELETE /projects/:id/hooks/:hook_id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1194,126 +1167,16 @@ Parameters:
Note the JSON response differs if the hook is available or not. If the project hook
is available before it is returned in the JSON response or an empty response is returned.
-## Branches
-
-For more information please consult the [Branches](branches.md) documentation.
-
-### List branches
-
-Lists all branches of a project.
-
-```
-GET /projects/:id/repository/branches
-```
-
-Parameters:
-
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
-
-```json
-[
- {
- "name": "async",
- "commit": {
- "id": "a2b702edecdf41f07b42653eb1abe30ce98b9fca",
- "parent_ids": [
- "3f94fc7c85061973edc9906ae170cc269b07ca55"
- ],
- "message": "give Caolan credit where it's due (up top)",
- "author_name": "Jeremy Ashkenas",
- "author_email": "jashkenas@example.com",
- "authored_date": "2010-12-08T21:28:50+00:00",
- "committer_name": "Jeremy Ashkenas",
- "committer_email": "jashkenas@example.com",
- "committed_date": "2010-12-08T21:28:50+00:00"
- },
- "protected": false,
- "developers_can_push": false,
- "developers_can_merge": false
- },
- {
- "name": "gh-pages",
- "commit": {
- "id": "101c10a60019fe870d21868835f65c25d64968fc",
- "parent_ids": [
- "9c15d2e26945a665131af5d7b6d30a06ba338aaa"
- ],
- "message": "Underscore.js 1.5.2",
- "author_name": "Jeremy Ashkenas",
- "author_email": "jashkenas@example.com",
- "authored_date": "2013-09-07T12:58:21+00:00",
- "committer_name": "Jeremy Ashkenas",
- "committer_email": "jashkenas@example.com",
- "committed_date": "2013-09-07T12:58:21+00:00"
- },
- "protected": false,
- "developers_can_push": false,
- "developers_can_merge": false
- }
-]
-```
-
-### Single branch
-
-A specific branch of a project.
-
-```
-GET /projects/:id/repository/branches/:branch
-```
-
-Parameters:
-
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
-| `branch` | string | yes | The name of the branch |
-| `developers_can_push` | boolean | no | Flag if developers can push to the branch |
-| `developers_can_merge` | boolean | no | Flag if developers can merge to the branch |
-
-### Protect single branch
-
-Protects a single branch of a project.
-
-```
-PUT /projects/:id/repository/branches/:branch/protect
-```
-
-Parameters:
-
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
-| `branch` | string | yes | The name of the branch |
-
-### Unprotect single branch
-
-Unprotects a single branch of a project.
-
-```
-PUT /projects/:id/repository/branches/:branch/unprotect
-```
-
-Parameters:
-
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
-| `branch` | string | yes | The name of the branch |
-
## Admin fork relation
Allows modification of the forked relationship between existing projects. Available only for admins.
-### Create a forked from/to relation between existing projects.
+### Create a forked from/to relation between existing projects
```
POST /projects/:id/fork/:forked_from_id
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1325,8 +1188,6 @@ Parameters:
DELETE /projects/:id/fork
```
-Parameter:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
@@ -1341,8 +1202,6 @@ accessible.
GET /projects
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `search` | string | yes | A string contained in the project name |
@@ -1355,14 +1214,20 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/a
## Start the Housekeeping task for a Project
->**Note:** This feature was introduced in GitLab 9.0
+> Introduced in GitLab 9.0.
```
POST /projects/:id/housekeeping
```
-Parameters:
-
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID of the project or NAMESPACE/PROJECT_NAME |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+
+## Branches
+
+Read more in the [Branches](branches.md) documentation.
+
+## Project members
+
+Read more in the [Project members](members.md) documentation.
diff --git a/doc/api/users.md b/doc/api/users.md
index 57b4e117cf3..9f3e4caf2f4 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -299,10 +299,7 @@ e.g. when renaming the email address to some existing one.
## User deletion
Deletes a user. Available only for administrators.
-This is an idempotent function, calling this function for a non-existent user id
-still returns a status code `200 OK`.
-The JSON response differs if the user was actually deleted or not.
-In the former the user is returned and in the latter not.
+This returns a `204 No Content` status code if the operation was successfully or `404` if the resource was not found.
```
DELETE /users/:id
@@ -524,8 +521,7 @@ Parameters:
## Delete SSH key for current user
Deletes key owned by currently authenticated user.
-This is an idempotent function and calling it on a key that is already deleted
-or not available results in `200 OK`.
+This returns a `204 No Content` status code if the operation was successfully or `404` if the resource was not found.
```
DELETE /user/keys/:key_id
@@ -548,8 +544,6 @@ Parameters:
- `id` (required) - id of specified user
- `key_id` (required) - SSH key ID
-Will return `200 OK` on success, or `404 Not found` if either user or key cannot be found.
-
## List all GPG keys
Get a list of currently authenticated user's GPG keys.
@@ -865,8 +859,7 @@ Parameters:
## Delete email for current user
Deletes email owned by currently authenticated user.
-This is an idempotent function and calling it on a email that is already deleted
-or not available results in `200 OK`.
+This returns a `204 No Content` status code if the operation was successfully or `404` if the resource was not found.
```
DELETE /user/emails/:email_id
@@ -889,8 +882,6 @@ Parameters:
- `id` (required) - id of specified user
- `email_id` (required) - email ID
-Will return `200 OK` on success, or `404 Not found` if either user or email cannot be found.
-
## Block user
Blocks the specified user. Available only for admin.
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 6c11f46a70a..0e20b8096e9 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -224,3 +224,21 @@ By default Sign In is enabled via all the OAuth Providers that have been configu
In order to enable/disable an OmniAuth provider, go to Admin Area -> Settings -> Sign-in Restrictions section -> Enabled OAuth Sign-In sources and select the providers you want to enable or disable.
![Enabled OAuth Sign-In sources](img/enabled-oauth-sign-in-sources.png)
+
+
+## Keep OmniAuth user profiles up to date
+
+You can enable profile syncing from selected OmniAuth providers and for all or for specific user information.
+
+ ```ruby
+ gitlab_rails['sync_profile_from_provider'] = ['twitter', 'google_oauth2']
+ gitlab_rails['sync_profile_attributes'] = ['name', 'email', 'location']
+ ```
+
+ **For installations from source**
+
+ ```yaml
+ omniauth:
+ sync_profile_from_provider: ['twitter', 'google_oauth2']
+ sync_profile_claims_from_provider: ['email', 'location']
+ ``` \ No newline at end of file
diff --git a/doc/user/discussions/img/automatically_resolve_outdated_discussions.png b/doc/user/discussions/img/automatically_resolve_outdated_discussions.png
new file mode 100644
index 00000000000..9a798ddd178
--- /dev/null
+++ b/doc/user/discussions/img/automatically_resolve_outdated_discussions.png
Binary files differ
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 8b1d299484c..efea99eb120 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -116,6 +116,23 @@ are resolved.
![Only allow merge if all the discussions are resolved message](img/only_allow_merge_if_all_discussions_are_resolved_msg.png)
+### Automatically resolve merge request diff discussions when they become outdated
+
+> [Introduced][ce-14053] in GitLab 10.0.
+
+You can automatically resolve merge request diff discussions on lines modified
+with a new push.
+
+Navigate to your project's settings page, select the **Automatically resolve
+merge request diffs discussions on lines changed with a push** check box and hit
+**Save** for the changes to take effect.
+
+![Automatically resolve merge request diff discussions when they become outdated](img/automatically_resolve_outdated_discussions.png)
+
+From now on, any discussions on a diff will be resolved by default if a push
+makes that diff section outdated. Discussions on lines that don't change and
+top-level resolvable discussions are not automatically resolved.
+
## Threaded discussions
> [Introduced][ce-7527] in GitLab 9.1.
@@ -141,6 +158,7 @@ comments in greater detail.
[ce-7527]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7527
[ce-7180]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7180
[ce-8266]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8266
+[ce-14053]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14053
[resolve-discussion-button]: img/resolve_discussion_button.png
[resolve-comment-button]: img/resolve_comment_button.png
[discussion-view]: img/discussion_view.png
diff --git a/doc/user/project/import/cvs.md b/doc/user/project/import/cvs.md
new file mode 100644
index 00000000000..cabd0eef8d6
--- /dev/null
+++ b/doc/user/project/import/cvs.md
@@ -0,0 +1,68 @@
+# Migrating from CVS
+
+[CVS](https://savannah.nongnu.org/projects/cvs) is an old centralized version
+control system similar to [SVN](svn.md).
+
+## CVS vs Git
+
+The following list illustrates the main differences between CVS and Git:
+
+- **Git is distributed.** On the other hand, CVS is centralized using a client-server
+ architecture. This translates to Git having a more flexible workflow since
+ your working area is a copy of the entire repository. This decreases the
+ overhead when switching branches or merging for example, since you don't have
+ to communicate with a remote server.
+- **Atomic operations.** In Git all operations are
+ [atomic](https://en.wikipedia.org/wiki/Atomic_commit), either they succeed as
+ whole, or they fail without any changes. In CVS, commits (and other operations)
+ are not atomic. If an operation on the repository is interrupted in the middle,
+ the repository can be left in an inconsistent state.
+- **Storage method.** Changes in CVS are per file (changeset), while in Git
+ a committed file(s) is stored in its entirety (snapshot). That means that's
+ very easy in Git to revert or undo a whole change.
+- **Revision IDs.** The fact that in CVS changes are per files, the revision ID
+ is depicted by version numbers, for example `1.4` reflects how many time a
+ given file has been changed. In Git, each version of a project as a whole
+ (each commit) has its unique name given by SHA-1.
+- **Merge tracking.** Git uses a commit-before-merge approach rather than
+ merge-before-commit (or update-then-commit) like CVS. If while you were
+ preparing to create a new commit (new revision) somebody created a
+ new commit on the same branch and pushed to the central repository, CVS would
+ force you to first update your working directory and resolve conflicts before
+ allowing you to commit. This is not the case with Git. You first commit, save
+ your state in version control, then you merge the other developer's changes.
+ You can also ask the other developer to do the merge and resolve any conflicts
+ themselves.
+- **Signed commits.** Git supports signing your commits with GPG for additional
+ security and verification that the commit indeed came from its original author.
+ GitLab can [integrate with GPG](../repository/gpg_signed_commits/index.md)
+ and show whether a signed commit is correctly verified.
+
+_Some of the items above were taken from this great
+[Stack Overflow post](https://stackoverflow.com/a/824241/974710). For a more
+complete list of differences, consult the
+Wikipedia article on [comparing the different version control software](https://en.wikipedia.org/wiki/Comparison_of_version_control_software)._
+
+## Why migrate
+
+CVS is old with no new release since 2008. Git provides more tools to work
+with (`git bisect` for one) which makes for a more productive workflow.
+Migrating to Git/GitLab there is:
+
+- **Shorter learning curve**, Git has a big community and a vast number of
+ tutorials to get you started (see our [Git topic](../../../topics/git/index.md)).
+- **Integration with modern tools**, migrating to Git and GitLab you can have
+ an open source end-to-end software development platform with built-in version
+ control, issue tracking, code review, CI/CD, and more.
+- **Support for many network protocols**. Git supports SSH, HTTP/HTTPS and rsync
+ among others, whereas CVS supports only SSH and its own insecure pserver
+ protocol with no user authentication.
+
+## How to migrate
+
+Here's a few links to get you started with the migration:
+
+- [Migrate using the `cvs-fast-export` tool](http://www.catb.org/~esr/reposurgeon/dvcs-migration-guide.html) ([_source code_](https://gitlab.com/esr/cvs-fast-export))
+- [Stack Overflow post on importing the CVS repo](https://stackoverflow.com/a/11490134/974710)
+- [Convert a CVS repository to Git](http://www.techrepublic.com/blog/linux-and-open-source/convert-cvs-repositories-to-git/)
+- [Man page of the `git-cvsimport` tool](https://www.kernel.org/pub/software/scm/git/docs/git-cvsimport.html)
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index 67e856a97cd..8da6e2a8207 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -1,13 +1,15 @@
# Migrating projects to a GitLab instance
1. [From Bitbucket.org](bitbucket.md)
+1. [From ClearCase](clearcase.md)
+1. [From CVS](cvs.md)
+1. [From FogBugz](fogbugz.md)
1. [From GitHub.com of GitHub Enterprise](github.md)
1. [From GitLab.com](gitlab_com.md)
-1. [From FogBugz](fogbugz.md)
1. [From Gitea](gitea.md)
-1. [From SVN](svn.md)
-1. [From ClearCase](clearcase.md)
1. [From Perforce](perforce.md)
+1. [From SVN](svn.md)
+1. [From TFS](tfs.md)
In addition to the specific migration documentation above, you can import any
Git repository via HTTP from the New Project page. Be aware that if the
diff --git a/doc/user/project/import/tfs.md b/doc/user/project/import/tfs.md
new file mode 100644
index 00000000000..8727c2ff6c3
--- /dev/null
+++ b/doc/user/project/import/tfs.md
@@ -0,0 +1,42 @@
+# Migrating from TFS
+
+[TFS](https://www.visualstudio.com/tfs/) is a set of tools developed by Microsoft
+which also includes a centralized version control system (TFVC) similar to Git.
+
+In this document, we emphasize on the TFVC to Git migration.
+
+## TFVC vs Git
+
+The following list illustrates the main differences between TFVC and Git:
+
+- **Git is distributed** whereas TFVC is centralized using a client-server
+ architecture. This translates to Git having a more flexible workflow since
+ your working area is a copy of the entire repository. This decreases the
+ overhead when switching branches or merging for example, since you don't have
+ to communicate with a remote server.
+- **Storage method.** Changes in CVS are per file (changeset), while in Git
+ a committed file(s) is stored in its entirety (snapshot). That means that's
+ very easy in Git to revert or undo a whole change.
+
+_Check also Microsoft's documentation on the
+[comparison of Git and TFVC](https://www.visualstudio.com/en-us/docs/tfvc/comparison-git-tfvc)
+and the Wikipedia article on
+[comparing the different version control software](https://en.wikipedia.org/wiki/Comparison_of_version_control_software)._
+
+## Why migrate
+
+Migrating to Git/GitLab there is:
+
+- **No licensing costs**, Git is GPL while TFVC is proprietary.
+- **Shorter learning curve**, Git has a big community and a vast number of
+ tutorials to get you started (see our [Git topic](../../../topics/git/index.md)).
+- **Integration with modern tools**, migrating to Git and GitLab you can have
+ an open source end-to-end software development platform with built-in version
+ control, issue tracking, code review, CI/CD, and more.
+
+## How to migrate
+
+The best option to migrate from TFVC to Git is to use the
+[`git-tfs`](https://github.com/git-tfs/git-tfs) tool. A specific guide for the
+migration exists:
+[Migrate TFS to Git](https://github.com/git-tfs/git-tfs/blob/master/doc/usecases/migrate_tfs_to_git.md).
diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md
index eb8cd821ddc..9f0308d8111 100644
--- a/doc/user/project/integrations/prometheus_library/kubernetes.md
+++ b/doc/user/project/integrations/prometheus_library/kubernetes.md
@@ -23,4 +23,4 @@ Prometheus server up and running. You have two options here:
In order to isolate and only display relevant metrics for a given environment
however, GitLab needs a method to detect which labels are associated. To do this, GitLab will [look for an `environment` label](metrics.md#identifying-environments).
-If you are using [GitLab Auto-Deploy][autodeploy] and one of the two [provided Kubernetes monitoring solutions](../prometheus.md#getting-started-with-prometheus-monitoring), the `environment` label will be automatically added.
+If you are using [GitLab Auto-Deploy][../../../ci/autodeploy/index.md] and one of the two [provided Kubernetes monitoring solutions](../prometheus.md#getting-started-with-prometheus-monitoring), the `environment` label will be automatically added.
diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md
index afe8066d408..20aadb8f7ff 100644
--- a/doc/user/project/repository/gpg_signed_commits/index.md
+++ b/doc/user/project/repository/gpg_signed_commits/index.md
@@ -31,6 +31,16 @@ to be met:
## Generating a GPG key
+>**Notes:**
+- If your Operating System has `gpg2` installed, replace `gpg` with `gpg2` in
+ the following commands.
+- If Git is using `gpg` and you get errors like `secret key not available` or
+ `gpg: signing failed: secret key not available`, run the following command to
+ change to `gpg2`:
+ ```
+ git config --global gpg.program gpg2
+ ```
+
If you don't already have a GPG key, the following steps will help you get
started:
diff --git a/features/steps/explore/projects.rb b/features/steps/explore/projects.rb
index 8fb2ac34c32..962e39dde9a 100644
--- a/features/steps/explore/projects.rb
+++ b/features/steps/explore/projects.rb
@@ -36,13 +36,13 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
end
step 'I should see project "Community" home page' do
- page.within '.breadcrumbs .title' do
+ page.within '.breadcrumbs .breadcrumb-item-text' do
expect(page).to have_content 'Community'
end
end
step 'I should see project "Internal" home page' do
- page.within '.breadcrumbs .title' do
+ page.within '.breadcrumbs .breadcrumb-item-text' do
expect(page).to have_content 'Internal'
end
end
diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb
index 100e674abed..9ce86ca45d0 100644
--- a/features/steps/project/redirects.rb
+++ b/features/steps/project/redirects.rb
@@ -18,7 +18,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
step 'I should see project "Community" home page' do
Gitlab.config.gitlab.should_receive(:host).and_return("www.example.com")
- page.within '.breadcrumbs .title' do
+ page.within '.breadcrumbs .breadcrumb-item-text' do
expect(page).to have_content 'Community'
end
end
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 94df543853b..1405a5d0f0e 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -108,6 +108,7 @@ module API
mount ::API::Internal
mount ::API::Issues
mount ::API::Jobs
+ mount ::API::JobArtifacts
mount ::API::Keys
mount ::API::Labels
mount ::API::Lint
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index ea78737288a..4b8d248f5f7 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -104,7 +104,7 @@ module API
not_found! 'Commit' unless commit
- commit.raw_diffs.to_a
+ present commit.raw_diffs.to_a, with: Entities::RepoDiff
end
desc "Get a commit's comments" do
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 031dd02c6eb..1d224d7bc21 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -119,6 +119,7 @@ module API
expose :archived?, as: :archived
expose :visibility
expose :owner, using: Entities::UserBasic, unless: ->(project, options) { project.group }
+ expose :resolve_outdated_diff_discussions
expose :container_registry_enabled
# Expose old field names with the new permissions methods to keep API compatible
@@ -290,10 +291,11 @@ module API
end
class RepoDiff < Grape::Entity
- expose :old_path, :new_path, :a_mode, :b_mode, :diff
+ expose :old_path, :new_path, :a_mode, :b_mode
expose :new_file?, as: :new_file
expose :renamed_file?, as: :renamed_file
expose :deleted_file?, as: :deleted_file
+ expose :json_safe_diff, as: :diff
end
class ProtectedRefAccess < Grape::Entity
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 3d377fdb9eb..e646c63467a 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -128,6 +128,10 @@ module API
merge_request
end
+ def find_build!(id)
+ user_project.builds.find(id.to_i)
+ end
+
def authenticate!
unauthorized! unless current_user && can?(initial_current_user, :access_api)
end
@@ -160,6 +164,14 @@ module API
authorize! :admin_project, user_project
end
+ def authorize_read_builds!
+ authorize! :read_build, user_project
+ end
+
+ def authorize_update_builds!
+ authorize! :update_build, user_project
+ end
+
def require_gitlab_workhorse!
unless env['HTTP_GITLAB_WORKHORSE'].present?
forbidden!('Request should be executed via GitLab Workhorse')
@@ -210,7 +222,7 @@ module API
def bad_request!(attribute)
message = ["400 (Bad request)"]
- message << "\"" + attribute.to_s + "\" not given"
+ message << "\"" + attribute.to_s + "\" not given" if attribute
render_api_error!(message.join(' '), 400)
end
@@ -432,6 +444,10 @@ module API
header(*Gitlab::Workhorse.send_git_archive(repository, ref: ref, format: format))
end
+ def send_artifacts_entry(build, entry)
+ 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.
def define_params_for_grape_middleware
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index f57ff0f2632..4c0db4d42b1 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -46,6 +46,15 @@ module API
::MergeRequests::GetUrlsService.new(project).execute(params[:changes])
end
+ def redis_ping
+ result = Gitlab::Redis::SharedState.with { |redis| redis.ping }
+
+ result == 'PONG'
+ rescue => e
+ Rails.logger.warn("GitLab: An unexpected error occurred in pinging to Redis: #{e}")
+ false
+ end
+
private
def set_project
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 622bd9650e4..c0fef56378f 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -88,7 +88,8 @@ module API
{
api_version: API.version,
gitlab_version: Gitlab::VERSION,
- gitlab_rev: Gitlab::REVISION
+ gitlab_rev: Gitlab::REVISION,
+ redis: redis_ping
}
end
@@ -142,6 +143,14 @@ module API
{ success: true, recovery_codes: codes }
end
+ post '/pre_receive' do
+ status 200
+
+ reference_counter_increased = Gitlab::ReferenceCounter.new(params[:gl_repository]).increase
+
+ { reference_counter_increased: reference_counter_increased }
+ end
+
post "/notify_post_receive" do
status 200
diff --git a/lib/api/job_artifacts.rb b/lib/api/job_artifacts.rb
new file mode 100644
index 00000000000..2a8fa7659bf
--- /dev/null
+++ b/lib/api/job_artifacts.rb
@@ -0,0 +1,80 @@
+module API
+ class JobArtifacts < Grape::API
+ before { authenticate_non_get! }
+
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+ resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
+ desc 'Download the artifacts file from a job' do
+ detail 'This feature was introduced in GitLab 8.10'
+ end
+ params do
+ requires :ref_name, type: String, desc: 'The ref from repository'
+ requires :job, type: String, desc: 'The name for the job'
+ end
+ get ':id/jobs/artifacts/:ref_name/download',
+ requirements: { ref_name: /.+/ } do
+ authorize_read_builds!
+
+ builds = user_project.latest_successful_builds_for(params[:ref_name])
+ latest_build = builds.find_by!(name: params[:job])
+
+ present_artifacts!(latest_build.artifacts_file)
+ end
+
+ desc 'Download the artifacts file from a job' do
+ detail 'This feature was introduced in GitLab 8.5'
+ end
+ params do
+ requires :job_id, type: Integer, desc: 'The ID of a job'
+ end
+ get ':id/jobs/:job_id/artifacts' do
+ authorize_read_builds!
+
+ build = find_build!(params[:job_id])
+
+ present_artifacts!(build.artifacts_file)
+ end
+
+ desc 'Download a specific file from artifacts archive' do
+ detail 'This feature was introduced in GitLab 10.0'
+ end
+ params do
+ requires :job_id, type: Integer, desc: 'The ID of a job'
+ requires :artifact_path, type: String, desc: 'Artifact path'
+ end
+ get ':id/jobs/:job_id/artifacts/*artifact_path', format: false do
+ authorize_read_builds!
+
+ build = find_build!(params[:job_id])
+ not_found! unless build.artifacts?
+
+ path = Gitlab::Ci::Build::Artifacts::Path
+ .new(params[:artifact_path])
+ bad_request! unless path.valid?
+
+ send_artifacts_entry(build, path)
+ end
+
+ desc 'Keep the artifacts to prevent them from being deleted' do
+ success Entities::Job
+ end
+ params do
+ requires :job_id, type: Integer, desc: 'The ID of a job'
+ end
+ post ':id/jobs/:job_id/artifacts/keep' do
+ authorize_update_builds!
+
+ build = find_build!(params[:job_id])
+ authorize!(:update_build, build)
+ return not_found!(build) unless build.artifacts?
+
+ build.keep_artifacts!
+
+ status 200
+ present build, with: Entities::Job
+ end
+ end
+ end
+end
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index 5bab96398fd..3c1c412ba42 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -66,42 +66,11 @@ module API
get ':id/jobs/:job_id' do
authorize_read_builds!
- build = get_build!(params[:job_id])
+ build = find_build!(params[:job_id])
present build, with: Entities::Job
end
- desc 'Download the artifacts file from a job' do
- detail 'This feature was introduced in GitLab 8.5'
- end
- params do
- requires :job_id, type: Integer, desc: 'The ID of a job'
- end
- get ':id/jobs/:job_id/artifacts' do
- authorize_read_builds!
-
- build = get_build!(params[:job_id])
-
- present_artifacts!(build.artifacts_file)
- end
-
- desc 'Download the artifacts file from a job' do
- detail 'This feature was introduced in GitLab 8.10'
- end
- params do
- requires :ref_name, type: String, desc: 'The ref from repository'
- requires :job, type: String, desc: 'The name for the job'
- end
- get ':id/jobs/artifacts/:ref_name/download',
- requirements: { ref_name: /.+/ } do
- authorize_read_builds!
-
- builds = user_project.latest_successful_builds_for(params[:ref_name])
- latest_build = builds.find_by!(name: params[:job])
-
- present_artifacts!(latest_build.artifacts_file)
- end
-
# TODO: We should use `present_file!` and leave this implementation for backward compatibility (when build trace
# is saved in the DB instead of file). But before that, we need to consider how to replace the value of
# `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse.
@@ -112,7 +81,7 @@ module API
get ':id/jobs/:job_id/trace' do
authorize_read_builds!
- build = get_build!(params[:job_id])
+ build = find_build!(params[:job_id])
header 'Content-Disposition', "infile; filename=\"#{build.id}.log\""
content_type 'text/plain'
@@ -131,7 +100,7 @@ module API
post ':id/jobs/:job_id/cancel' do
authorize_update_builds!
- build = get_build!(params[:job_id])
+ build = find_build!(params[:job_id])
authorize!(:update_build, build)
build.cancel
@@ -148,7 +117,7 @@ module API
post ':id/jobs/:job_id/retry' do
authorize_update_builds!
- build = get_build!(params[:job_id])
+ build = find_build!(params[:job_id])
authorize!(:update_build, build)
return forbidden!('Job is not retryable') unless build.retryable?
@@ -166,7 +135,7 @@ module API
post ':id/jobs/:job_id/erase' do
authorize_update_builds!
- build = get_build!(params[:job_id])
+ build = find_build!(params[:job_id])
authorize!(:update_build, build)
return forbidden!('Job is not erasable!') unless build.erasable?
@@ -174,25 +143,6 @@ module API
present build, with: Entities::Job
end
- desc 'Keep the artifacts to prevent them from being deleted' do
- success Entities::Job
- end
- params do
- requires :job_id, type: Integer, desc: 'The ID of a job'
- end
- post ':id/jobs/:job_id/artifacts/keep' do
- authorize_update_builds!
-
- build = get_build!(params[:job_id])
- authorize!(:update_build, build)
- return not_found!(build) unless build.artifacts?
-
- build.keep_artifacts!
-
- status 200
- present build, with: Entities::Job
- end
-
desc 'Trigger a manual job' do
success Entities::Job
detail 'This feature was added in GitLab 8.11'
@@ -203,7 +153,7 @@ module API
post ":id/jobs/:job_id/play" do
authorize_read_builds!
- build = get_build!(params[:job_id])
+ build = find_build!(params[:job_id])
authorize!(:update_build, build)
bad_request!("Unplayable Job") unless build.playable?
@@ -216,14 +166,6 @@ module API
end
helpers do
- def find_build(id)
- user_project.builds.find_by(id: id.to_i)
- end
-
- def get_build!(id)
- find_build(id) || not_found!
- end
-
def filter_builds(builds, scope)
return builds if scope.nil? || scope.empty?
@@ -234,14 +176,6 @@ module API
builds.where(status: available_statuses && scope)
end
-
- def authorize_read_builds!
- authorize! :read_build, user_project
- end
-
- def authorize_update_builds!
- authorize! :update_build, user_project
- end
end
end
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 4845242a173..7dc19788462 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -16,6 +16,7 @@ module API
optional :jobs_enabled, type: Boolean, desc: 'Flag indication if jobs are enabled'
optional :snippets_enabled, type: Boolean, desc: 'Flag indication if snippets are enabled'
optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project'
+ optional :resolve_outdated_diff_discussions, type: Boolean, desc: 'Automatically resolve merge request diffs discussions on lines changed with a push'
optional :container_registry_enabled, type: Boolean, desc: 'Flag indication if the container registry is enabled for that project'
optional :lfs_enabled, type: Boolean, desc: 'Flag indication if Git LFS is enabled for that project'
optional :visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The visibility of the project.'
@@ -236,6 +237,7 @@ module API
at_least_one_of_ce =
[
:jobs_enabled,
+ :resolve_outdated_diff_discussions,
:container_registry_enabled,
:default_branch,
:description,
diff --git a/lib/api/v3/entities.rb b/lib/api/v3/entities.rb
index a9a35f2a4bd..ac47a713966 100644
--- a/lib/api/v3/entities.rb
+++ b/lib/api/v3/entities.rb
@@ -64,6 +64,7 @@ module API
expose :owner, using: ::API::Entities::UserBasic, unless: ->(project, options) { project.group }
expose :name, :name_with_namespace
expose :path, :path_with_namespace
+ expose :resolve_outdated_diff_discussions
expose :container_registry_enabled
# Expose old field names with the new permissions methods to keep API compatible
diff --git a/lib/api/v3/projects.rb b/lib/api/v3/projects.rb
index 449876c10d9..74df246bdfe 100644
--- a/lib/api/v3/projects.rb
+++ b/lib/api/v3/projects.rb
@@ -18,6 +18,7 @@ module API
optional :builds_enabled, type: Boolean, desc: 'Flag indication if builds are enabled'
optional :snippets_enabled, type: Boolean, desc: 'Flag indication if snippets are enabled'
optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project'
+ optional :resolve_outdated_diff_discussions, type: Boolean, desc: 'Automatically resolve merge request diffs discussions on lines changed with a push'
optional :container_registry_enabled, type: Boolean, desc: 'Flag indication if the container registry is enabled for that project'
optional :lfs_enabled, type: Boolean, desc: 'Flag indication if Git LFS is enabled for that project'
optional :public, type: Boolean, desc: 'Create a public project. The same as visibility_level = 20.'
@@ -296,9 +297,9 @@ module API
use :optional_params
at_least_one_of :name, :description, :issues_enabled, :merge_requests_enabled,
:wiki_enabled, :builds_enabled, :snippets_enabled,
- :shared_runners_enabled, :container_registry_enabled,
- :lfs_enabled, :public, :visibility_level, :public_builds,
- :request_access_enabled, :only_allow_merge_if_build_succeeds,
+ :shared_runners_enabled, :resolve_outdated_diff_discussions,
+ :container_registry_enabled, :lfs_enabled, :public, :visibility_level,
+ :public_builds, :request_access_enabled, :only_allow_merge_if_build_succeeds,
:only_allow_merge_if_all_discussions_are_resolved, :path,
:default_branch
end
diff --git a/lib/banzai/commit_renderer.rb b/lib/banzai/commit_renderer.rb
new file mode 100644
index 00000000000..f5ff95e3eb3
--- /dev/null
+++ b/lib/banzai/commit_renderer.rb
@@ -0,0 +1,11 @@
+module Banzai
+ module CommitRenderer
+ ATTRIBUTES = [:description, :title].freeze
+
+ def self.render(commits, project, user = nil)
+ obj_renderer = ObjectRenderer.new(project, user)
+
+ ATTRIBUTES.each { |attr| obj_renderer.render(commits, attr) }
+ end
+ end
+end
diff --git a/lib/banzai/filter/table_of_contents_filter.rb b/lib/banzai/filter/table_of_contents_filter.rb
index 8e7084f2543..47151626208 100644
--- a/lib/banzai/filter/table_of_contents_filter.rb
+++ b/lib/banzai/filter/table_of_contents_filter.rb
@@ -22,40 +22,94 @@ module Banzai
result[:toc] = ""
headers = Hash.new(0)
+ header_root = current_header = HeaderNode.new
doc.css('h1, h2, h3, h4, h5, h6').each do |node|
- text = node.text
+ if header_content = node.children.first
+ id = node
+ .text
+ .downcase
+ .gsub(PUNCTUATION_REGEXP, '') # remove punctuation
+ .tr(' ', '-') # replace spaces with dash
+ .squeeze('-') # replace multiple dashes with one
- id = text.downcase
- id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
- id.tr!(' ', '-') # replace spaces with dash
- id.squeeze!('-') # replace multiple dashes with one
+ uniq = headers[id] > 0 ? "-#{headers[id]}" : ''
+ headers[id] += 1
+ href = "#{id}#{uniq}"
- uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
- headers[id] += 1
+ current_header = HeaderNode.new(node: node, href: href, previous_header: current_header)
- if header_content = node.children.first
- # namespace detection will be automatically handled via javascript (see issue #22781)
- namespace = "user-content-"
- href = "#{id}#{uniq}"
- push_toc(href, text)
- header_content.add_previous_sibling(anchor_tag("#{namespace}#{href}", href))
+ header_content.add_previous_sibling(anchor_tag(href))
end
end
- result[:toc] = %Q{<ul class="section-nav">\n#{result[:toc]}</ul>} unless result[:toc].empty?
+ push_toc(header_root.children, root: true)
doc
end
private
- def anchor_tag(id, href)
- %Q{<a id="#{id}" class="anchor" href="##{href}" aria-hidden="true"></a>}
+ def anchor_tag(href)
+ %Q{<a id="user-content-#{href}" class="anchor" href="##{href}" aria-hidden="true"></a>}
end
- def push_toc(href, text)
- result[:toc] << %Q{<li><a href="##{href}">#{text}</a></li>\n}
+ def push_toc(children, root: false)
+ return if children.empty?
+
+ klass = ' class="section-nav"' if root
+
+ result[:toc] << "<ul#{klass}>"
+ children.each { |child| push_anchor(child) }
+ result[:toc] << '</ul>'
+ end
+
+ def push_anchor(header_node)
+ result[:toc] << %Q{<li><a href="##{header_node.href}">#{header_node.text}</a>}
+ push_toc(header_node.children)
+ result[:toc] << '</li>'
+ end
+
+ class HeaderNode
+ attr_reader :node, :href, :parent, :children
+
+ def initialize(node: nil, href: nil, previous_header: nil)
+ @node = node
+ @href = href
+ @children = []
+
+ @parent = find_parent(previous_header)
+ @parent.children.push(self) if @parent
+ end
+
+ def level
+ return 0 unless node
+
+ @level ||= node.name[1].to_i
+ end
+
+ def text
+ return '' unless node
+
+ @text ||= node.text
+ end
+
+ private
+
+ def find_parent(previous_header)
+ return unless previous_header
+
+ if level == previous_header.level
+ parent = previous_header.parent
+ elsif level > previous_header.level
+ parent = previous_header
+ else
+ parent = previous_header
+ parent = parent.parent while parent.level >= level
+ end
+
+ parent
+ end
end
end
end
diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb
index 2196a92474c..e40556e869c 100644
--- a/lib/banzai/object_renderer.rb
+++ b/lib/banzai/object_renderer.rb
@@ -38,7 +38,7 @@ module Banzai
objects.each_with_index do |object, index|
redacted_data = redacted[index]
object.__send__("redacted_#{attribute}_html=", redacted_data[:document].to_html.html_safe) # rubocop:disable GitlabSecurity/PublicSend
- object.user_visible_reference_count = redacted_data[:visible_reference_count]
+ object.user_visible_reference_count = redacted_data[:visible_reference_count] if object.respond_to?(:user_visible_reference_count)
end
end
diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb
index 95d82d17658..ceca9296851 100644
--- a/lib/banzai/renderer.rb
+++ b/lib/banzai/renderer.rb
@@ -36,6 +36,10 @@ module Banzai
# The context to use is managed by the object and cannot be changed.
# Use #render, passing it the field text, if a custom rendering is needed.
def self.render_field(object, field)
+ unless object.respond_to?(:cached_markdown_fields)
+ return cacheless_render_field(object, field)
+ end
+
object.refresh_markdown_cache!(do_update: update_object?(object)) unless object.cached_html_up_to_date?(field)
object.cached_html_for(field)
diff --git a/lib/github/representation/branch.rb b/lib/github/representation/branch.rb
index c6fa928d565..823e8e9a9c4 100644
--- a/lib/github/representation/branch.rb
+++ b/lib/github/representation/branch.rb
@@ -41,7 +41,7 @@ module Github
def remove!(name)
repository.delete_branch(name)
- rescue Rugged::ReferenceError => e
+ rescue Gitlab::Git::Repository::DeleteBranchError => e
Rails.logger.error("#{self.class.name}: Could not remove branch #{name}: #{e}")
end
diff --git a/lib/gitlab/access.rb b/lib/gitlab/access.rb
index 4714ab18cc1..b4012ebbb99 100644
--- a/lib/gitlab/access.rb
+++ b/lib/gitlab/access.rb
@@ -67,10 +67,14 @@ module Gitlab
def protection_values
protection_options.values
end
+
+ def human_access(access)
+ options_with_owner.key(access)
+ end
end
def human_access
- Gitlab::Access.options_with_owner.key(access_field)
+ Gitlab::Access.human_access(access_field)
end
def owner?
diff --git a/lib/gitlab/ci/build/artifacts/metadata/entry.rb b/lib/gitlab/ci/build/artifacts/metadata/entry.rb
index 2e073334abc..22941d48edf 100644
--- a/lib/gitlab/ci/build/artifacts/metadata/entry.rb
+++ b/lib/gitlab/ci/build/artifacts/metadata/entry.rb
@@ -1,129 +1,129 @@
module Gitlab
- module Ci::Build::Artifacts
- class Metadata
- ##
- # Class that represents an entry (path and metadata) to a file or
- # directory in GitLab CI Build Artifacts binary file / archive
- #
- # This is IO-operations safe class, that does similar job to
- # Ruby's Pathname but without the risk of accessing filesystem.
- #
- # This class is working only with UTF-8 encoded paths.
- #
- class Entry
- attr_reader :path, :entries
- attr_accessor :name
-
- def initialize(path, entries)
- @path = path.dup.force_encoding('UTF-8')
- @entries = entries
-
- if path.include?("\0")
- raise ArgumentError, 'Path contains zero byte character!'
- end
+ module Ci
+ module Build
+ module Artifacts
+ class Metadata
+ ##
+ # Class that represents an entry (path and metadata) to a file or
+ # directory in GitLab CI Build Artifacts binary file / archive
+ #
+ # This is IO-operations safe class, that does similar job to
+ # Ruby's Pathname but without the risk of accessing filesystem.
+ #
+ # This class is working only with UTF-8 encoded paths.
+ #
+ class Entry
+ attr_reader :entries
+ attr_accessor :name
+
+ def initialize(path, entries)
+ @entries = entries
+ @path = Artifacts::Path.new(path)
+ end
+
+ delegate :empty?, to: :children
+
+ def directory?
+ blank_node? || @path.directory?
+ end
+
+ def file?
+ !directory?
+ end
+
+ def blob
+ return unless file?
+
+ @blob ||= Blob.decorate(::Ci::ArtifactBlob.new(self), nil)
+ end
+
+ def has_parent?
+ nodes > 0
+ end
+
+ def parent
+ return nil unless has_parent?
+ self.class.new(@path.to_s.chomp(basename), @entries)
+ end
+
+ def basename
+ (directory? && !blank_node?) ? name + '/' : name
+ end
+
+ def name
+ @name || @path.name
+ end
+
+ def children
+ return [] unless directory?
+ return @children if @children
+
+ child_pattern = %r{^#{Regexp.escape(@path.to_s)}[^/]+/?$}
+ @children = select_entries { |path| path =~ child_pattern }
+ end
+
+ def directories(opts = {})
+ return [] unless directory?
+ dirs = children.select(&:directory?)
+ return dirs unless has_parent? && opts[:parent]
+
+ dotted_parent = parent
+ dotted_parent.name = '..'
+ dirs.prepend(dotted_parent)
+ end
+
+ def files
+ return [] unless directory?
+ children.select(&:file?)
+ end
+
+ def metadata
+ @entries[@path.to_s] || {}
+ end
+
+ def nodes
+ @path.nodes + (file? ? 1 : 0)
+ end
+
+ def blank_node?
+ @path.to_s.empty? # "" is considered to be './'
+ end
+
+ def exists?
+ blank_node? || @entries.include?(@path.to_s)
+ end
+
+ def total_size
+ descendant_pattern = %r{^#{Regexp.escape(@path.to_s)}}
+ entries.sum do |path, entry|
+ (entry[:size] if path =~ descendant_pattern).to_i
+ end
+ end
+
+ def path
+ @path.to_s
+ end
+
+ def to_s
+ @path.to_s
+ end
+
+ def ==(other)
+ path == other.path && @entries == other.entries
+ end
+
+ def inspect
+ "#{self.class.name}: #{self}"
+ end
- unless path.valid_encoding?
- raise ArgumentError, 'Path contains non-UTF-8 byte sequence!'
+ private
+
+ def select_entries
+ selected = @entries.select { |path, _metadata| yield path }
+ selected.map { |path, _metadata| self.class.new(path, @entries) }
+ end
end
end
-
- delegate :empty?, to: :children
-
- def directory?
- blank_node? || @path.end_with?('/')
- end
-
- def file?
- !directory?
- end
-
- def blob
- return unless file?
-
- @blob ||= Blob.decorate(::Ci::ArtifactBlob.new(self), nil)
- end
-
- def has_parent?
- nodes > 0
- end
-
- def parent
- return nil unless has_parent?
- self.class.new(@path.chomp(basename), @entries)
- end
-
- def basename
- (directory? && !blank_node?) ? name + '/' : name
- end
-
- def name
- @name || @path.split('/').last.to_s
- end
-
- def children
- return [] unless directory?
- return @children if @children
-
- child_pattern = %r{^#{Regexp.escape(@path)}[^/]+/?$}
- @children = select_entries { |path| path =~ child_pattern }
- end
-
- def directories(opts = {})
- return [] unless directory?
- dirs = children.select(&:directory?)
- return dirs unless has_parent? && opts[:parent]
-
- dotted_parent = parent
- dotted_parent.name = '..'
- dirs.prepend(dotted_parent)
- end
-
- def files
- return [] unless directory?
- children.select(&:file?)
- end
-
- def metadata
- @entries[@path] || {}
- end
-
- def nodes
- @path.count('/') + (file? ? 1 : 0)
- end
-
- def blank_node?
- @path.empty? # "" is considered to be './'
- end
-
- def exists?
- blank_node? || @entries.include?(@path)
- end
-
- def total_size
- descendant_pattern = %r{^#{Regexp.escape(@path)}}
- entries.sum do |path, entry|
- (entry[:size] if path =~ descendant_pattern).to_i
- end
- end
-
- def to_s
- @path
- end
-
- def ==(other)
- @path == other.path && @entries == other.entries
- end
-
- def inspect
- "#{self.class.name}: #{@path}"
- end
-
- private
-
- def select_entries
- selected = @entries.select { |path, _metadata| yield path }
- selected.map { |path, _metadata| self.class.new(path, @entries) }
- end
end
end
end
diff --git a/lib/gitlab/ci/build/artifacts/path.rb b/lib/gitlab/ci/build/artifacts/path.rb
new file mode 100644
index 00000000000..9cd9b36c5f8
--- /dev/null
+++ b/lib/gitlab/ci/build/artifacts/path.rb
@@ -0,0 +1,51 @@
+module Gitlab
+ module Ci
+ module Build
+ module Artifacts
+ class Path
+ def initialize(path)
+ @path = path.dup.force_encoding('UTF-8')
+ end
+
+ def valid?
+ nonzero? && utf8?
+ end
+
+ def directory?
+ @path.end_with?('/')
+ end
+
+ def name
+ @path.split('/').last.to_s
+ end
+
+ def nodes
+ @path.count('/')
+ end
+
+ def to_s
+ @path.tap do |path|
+ unless nonzero?
+ raise ArgumentError, 'Path contains zero byte character!'
+ end
+
+ unless utf8?
+ raise ArgumentError, 'Path contains non-UTF-8 byte sequence!'
+ end
+ end
+ end
+
+ private
+
+ def nonzero?
+ @path.exclude?("\0")
+ end
+
+ def utf8?
+ @path.valid_encoding?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/encoding_helper.rb b/lib/gitlab/encoding_helper.rb
index 8ddc91e341d..7b3483a7f96 100644
--- a/lib/gitlab/encoding_helper.rb
+++ b/lib/gitlab/encoding_helper.rb
@@ -22,10 +22,10 @@ module Gitlab
# return message if message type is binary
detect = CharlockHolmes::EncodingDetector.detect(message)
- return message.force_encoding("BINARY") if detect && detect[:type] == :binary
+ return message.force_encoding("BINARY") if detect_binary?(message, detect)
- # force detected encoding if we have sufficient confidence.
if detect && detect[:encoding] && detect[:confidence] > ENCODING_CONFIDENCE_THRESHOLD
+ # force detected encoding if we have sufficient confidence.
message.force_encoding(detect[:encoding])
end
@@ -36,6 +36,19 @@ module Gitlab
"--broken encoding: #{encoding}"
end
+ def detect_binary?(data, detect = nil)
+ detect ||= CharlockHolmes::EncodingDetector.detect(data)
+ detect && detect[:type] == :binary && detect[:confidence] == 100
+ end
+
+ def detect_libgit2_binary?(data)
+ # EncodingDetector checks the first 1024 * 1024 bytes for NUL byte, libgit2 checks
+ # only the first 8000 (https://github.com/libgit2/libgit2/blob/2ed855a9e8f9af211e7274021c2264e600c0f86b/src/filter.h#L15),
+ # which is what we use below to keep a consistent behavior.
+ detect = CharlockHolmes::EncodingDetector.new(8000).detect(data)
+ detect && detect[:type] == :binary
+ end
+
def encode_utf8(message)
detect = CharlockHolmes::EncodingDetector.detect(message)
if detect && detect[:encoding]
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index 7780f4e4d4f..8d96826f6ee 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -42,14 +42,6 @@ module Gitlab
end
end
- def binary?(data)
- # EncodingDetector checks the first 1024 * 1024 bytes for NUL byte, libgit2 checks
- # only the first 8000 (https://github.com/libgit2/libgit2/blob/2ed855a9e8f9af211e7274021c2264e600c0f86b/src/filter.h#L15),
- # which is what we use below to keep a consistent behavior.
- detect = CharlockHolmes::EncodingDetector.new(8000).detect(data)
- detect && detect[:type] == :binary
- end
-
# Returns an array of Blob instances, specified in blob_references as
# [[commit_sha, path], [commit_sha, path], ...]. If blob_size_limit < 0 then the
# full blob contents are returned. If blob_size_limit >= 0 then each blob will
@@ -65,6 +57,10 @@ module Gitlab
end
end
+ def binary?(data)
+ EncodingHelper.detect_libgit2_binary?(data)
+ end
+
private
# Recursive search of blob id by path
diff --git a/lib/gitlab/git/diff.rb b/lib/gitlab/git/diff.rb
index ce3d65062e8..a23c8cf0dd1 100644
--- a/lib/gitlab/git/diff.rb
+++ b/lib/gitlab/git/diff.rb
@@ -116,6 +116,15 @@ module Gitlab
filtered_opts
end
+
+ # Return a binary diff message like:
+ #
+ # "Binary files a/file/path and b/file/path differ\n"
+ # This is used when we detect that a diff is binary
+ # using CharlockHolmes when Rugged treats it as text.
+ def binary_message(old_path, new_path)
+ "Binary files #{old_path} and #{new_path} differ\n"
+ end
end
def initialize(raw_diff, expanded: true)
@@ -190,6 +199,13 @@ module Gitlab
@collapsed = true
end
+ def json_safe_diff
+ return @diff unless detect_binary?(@diff)
+
+ # the diff is binary, let's make a message for it
+ Diff.binary_message(@old_path, @new_path)
+ end
+
private
def init_from_rugged(rugged)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 75d4efc0bc5..efa13590a2c 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -18,6 +18,7 @@ module Gitlab
InvalidBlobName = Class.new(StandardError)
InvalidRef = Class.new(StandardError)
GitError = Class.new(StandardError)
+ DeleteBranchError = Class.new(StandardError)
class << self
# Unlike `new`, `create` takes the storage path, not the storage name
@@ -653,10 +654,16 @@ module Gitlab
end
# Delete the specified branch from the repository
- #
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/476
def delete_branch(branch_name)
- rugged.branches.delete(branch_name)
+ gitaly_migrate(:delete_branch) do |is_enabled|
+ if is_enabled
+ gitaly_ref_client.delete_branch(branch_name)
+ else
+ rugged.branches.delete(branch_name)
+ end
+ end
+ rescue Rugged::ReferenceError, CommandError => e
+ raise DeleteBranchError, e
end
def delete_refs(*ref_names)
@@ -681,15 +688,14 @@ module Gitlab
# Examples:
# create_branch("feature")
# create_branch("other-feature", "master")
- #
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/476
def create_branch(ref, start_point = "HEAD")
- rugged_ref = rugged.branches.create(ref, start_point)
- target_commit = Gitlab::Git::Commit.find(self, rugged_ref.target)
- Gitlab::Git::Branch.new(self, rugged_ref.name, rugged_ref.target, target_commit)
- rescue Rugged::ReferenceError => e
- raise InvalidRef.new("Branch #{ref} already exists") if e.to_s =~ /'refs\/heads\/#{ref}'/
- raise InvalidRef.new("Invalid reference #{start_point}")
+ gitaly_migrate(:create_branch) do |is_enabled|
+ if is_enabled
+ gitaly_ref_client.create_branch(ref, start_point)
+ else
+ rugged_create_branch(ref, start_point)
+ end
+ end
end
# Delete the specified remote from this repository.
@@ -1226,6 +1232,15 @@ module Gitlab
false
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)
+ Gitlab::Git::Branch.new(self, rugged_ref.name, rugged_ref.target, target_commit)
+ rescue Rugged::ReferenceError => e
+ raise InvalidRef.new("Branch #{ref} already exists") if e.to_s =~ /'refs\/heads\/#{ref}'/
+ raise InvalidRef.new("Invalid reference #{start_point}")
+ end
+
def gitaly_copy_gitattributes(revision)
gitaly_repository_client.apply_gitattributes(revision)
end
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index a1a25cf2079..8ef873d5848 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -79,7 +79,7 @@ module Gitlab
end
def find_branch(branch_name)
- request = Gitaly::DeleteBranchRequest.new(
+ request = Gitaly::FindBranchRequest.new(
repository: @gitaly_repo,
name: GitalyClient.encode(branch_name)
)
@@ -92,6 +92,40 @@ module Gitlab
Gitlab::Git::Branch.new(@repository, encode!(branch.name.dup), branch.target_commit.id, target_commit)
end
+ def create_branch(ref, start_point)
+ request = Gitaly::CreateBranchRequest.new(
+ repository: @gitaly_repo,
+ name: GitalyClient.encode(ref),
+ start_point: GitalyClient.encode(start_point)
+ )
+
+ response = GitalyClient.call(@repository.storage, :ref_service, :create_branch, request)
+
+ case response.status
+ when :OK
+ branch = response.branch
+ target_commit = Gitlab::Git::Commit.decorate(@repository, branch.target_commit)
+ Gitlab::Git::Branch.new(@repository, branch.name, branch.target_commit.id, target_commit)
+ when :ERR_INVALID
+ invalid_ref!("Invalid ref name")
+ when :ERR_EXISTS
+ invalid_ref!("Branch #{ref} already exists")
+ when :ERR_INVALID_START_POINT
+ invalid_ref!("Invalid reference #{start_point}")
+ else
+ raise "Unknown response status: #{response.status}"
+ end
+ end
+
+ def delete_branch(branch_name)
+ request = Gitaly::DeleteBranchRequest.new(
+ repository: @gitaly_repo,
+ name: GitalyClient.encode(branch_name)
+ )
+
+ GitalyClient.call(@repository.storage, :ref_service, :delete_branch, request)
+ end
+
private
def consume_refs_response(response)
@@ -163,6 +197,10 @@ module Gitlab
Gitlab::Git::Commit.decorate(@repository, hash)
end
+
+ def invalid_ref!(message)
+ raise Gitlab::Git::Repository::InvalidRef.new(message)
+ end
end
end
end
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index 373062b354b..b8c07460ebb 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -166,7 +166,7 @@ module Gitlab
def remove_branch(name)
project.repository.delete_branch(name)
- rescue Rugged::ReferenceError
+ rescue Gitlab::Git::Repository::DeleteBranchFailed
errors << { type: :remove_branch, name: name }
end
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 78795dd3d92..ec73846d844 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -116,6 +116,7 @@ excluded_attributes:
statuses:
- :trace
- :token
+ - :when
push_event_payload:
- :event_id
diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb
index cbc8d170936..3bc095a99a9 100644
--- a/lib/gitlab/import_export/project_tree_restorer.rb
+++ b/lib/gitlab/import_export/project_tree_restorer.rb
@@ -9,6 +9,8 @@ module Gitlab
@user = user
@shared = shared
@project = project
+ @project_id = project.id
+ @saved = true
end
def restore
@@ -22,8 +24,10 @@ module Gitlab
@project_members = @tree_hash.delete('project_members')
- ActiveRecord::Base.no_touching do
- create_relations
+ ActiveRecord::Base.uncached do
+ ActiveRecord::Base.no_touching do
+ create_relations
+ end
end
rescue => e
@shared.error(e)
@@ -48,21 +52,24 @@ module Gitlab
# the configuration yaml file too.
# Finally, it updates each attribute in the newly imported project.
def create_relations
- saved = []
default_relation_list.each do |relation|
- next unless relation.is_a?(Hash) || @tree_hash[relation.to_s].present?
+ if relation.is_a?(Hash)
+ create_sub_relations(relation, @tree_hash)
+ elsif @tree_hash[relation.to_s].present?
+ save_relation_hash(@tree_hash[relation.to_s], relation)
+ end
+ end
- create_sub_relations(relation, @tree_hash) if relation.is_a?(Hash)
+ @saved
+ end
- relation_key = relation.is_a?(Hash) ? relation.keys.first : relation
- relation_hash_list = @tree_hash[relation_key.to_s]
+ def save_relation_hash(relation_hash_batch, relation_key)
+ relation_hash = create_relation(relation_key, relation_hash_batch)
- next unless relation_hash_list
+ @saved = false unless restored_project.append_or_update_attribute(relation_key, relation_hash)
- relation_hash = create_relation(relation_key, relation_hash_list)
- saved << restored_project.append_or_update_attribute(relation_key, relation_hash)
- end
- saved.all?
+ # Restore the project again, extra query that skips holding the AR objects in memory
+ @restored_project = Project.find(@project_id)
end
def default_relation_list
@@ -93,20 +100,42 @@ module Gitlab
# issue, finds any subrelations such as notes, creates them and assign them back to the hash
#
# Recursively calls this method if the sub-relation is a hash containing more sub-relations
- def create_sub_relations(relation, tree_hash)
+ def create_sub_relations(relation, tree_hash, save: true)
relation_key = relation.keys.first.to_s
return if tree_hash[relation_key].blank?
- [tree_hash[relation_key]].flatten.each do |relation_item|
- relation.values.flatten.each do |sub_relation|
- # We just use author to get the user ID, do not attempt to create an instance.
- next if sub_relation == :author
+ tree_array = [tree_hash[relation_key]].flatten
+
+ # Avoid keeping a possible heavy object in memory once we are done with it
+ while relation_item = tree_array.shift
+ # The transaction at this level is less speedy than one single transaction
+ # But we can't have it in the upper level or GC won't get rid of the AR objects
+ # after we save the batch.
+ Project.transaction do
+ process_sub_relation(relation, relation_item)
+
+ # For every subrelation that hangs from Project, save the associated records alltogether
+ # This effectively batches all records per subrelation item, only keeping those in memory
+ # We have to keep in mind that more batch granularity << Memory, but >> Slowness
+ if save
+ save_relation_hash([relation_item], relation_key)
+ tree_hash[relation_key].delete(relation_item)
+ end
+ end
+ end
+
+ tree_hash.delete(relation_key) if save
+ end
+
+ def process_sub_relation(relation, relation_item)
+ relation.values.flatten.each do |sub_relation|
+ # We just use author to get the user ID, do not attempt to create an instance.
+ next if sub_relation == :author
- create_sub_relations(sub_relation, relation_item) if sub_relation.is_a?(Hash)
+ create_sub_relations(sub_relation, relation_item, save: false) if sub_relation.is_a?(Hash)
- relation_hash, sub_relation = assign_relation_hash(relation_item, sub_relation)
- relation_item[sub_relation.to_s] = create_relation(sub_relation, relation_hash) unless relation_hash.blank?
- end
+ relation_hash, sub_relation = assign_relation_hash(relation_item, sub_relation)
+ relation_item[sub_relation.to_s] = create_relation(sub_relation, relation_hash) unless relation_hash.blank?
end
end
@@ -121,14 +150,12 @@ module Gitlab
end
def create_relation(relation, relation_hash_list)
- relation_type = relation.to_sym
-
relation_array = [relation_hash_list].flatten.map do |relation_hash|
- Gitlab::ImportExport::RelationFactory.create(relation_sym: relation_type,
- relation_hash: parsed_relation_hash(relation_hash, relation_type),
+ Gitlab::ImportExport::RelationFactory.create(relation_sym: relation.to_sym,
+ relation_hash: parsed_relation_hash(relation_hash, relation.to_sym),
members_mapper: members_mapper,
user: @user,
- project: restored_project)
+ project: @restored_project)
end.compact
relation_hash_list.is_a?(Array) ? relation_array : relation_array.first
diff --git a/lib/gitlab/import_export/shared.rb b/lib/gitlab/import_export/shared.rb
index 5d6de8bc475..9fd0b709ef2 100644
--- a/lib/gitlab/import_export/shared.rb
+++ b/lib/gitlab/import_export/shared.rb
@@ -16,7 +16,7 @@ module Gitlab
error_out(error.message, caller[0].dup)
@errors << error.message
# Debug:
- Rails.logger.error(error.backtrace)
+ Rails.logger.error(error.backtrace.join("\n"))
end
private
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index 39180dc17d9..3bf27b37ae6 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -36,7 +36,7 @@ module Gitlab
end
def find_by_email
- ::User.find_by(email: auth_hash.email.downcase) if auth_hash.has_email?
+ ::User.find_by(email: auth_hash.email.downcase) if auth_hash.has_attribute?(:email)
end
def update_user_attributes
@@ -60,7 +60,7 @@ module Gitlab
ldap_config.block_auto_created_users
end
- def sync_email_from_provider?
+ def sync_profile_from_provider?
true
end
diff --git a/lib/gitlab/o_auth/auth_hash.rb b/lib/gitlab/o_auth/auth_hash.rb
index 7d6911a1ab3..1f331b1e91d 100644
--- a/lib/gitlab/o_auth/auth_hash.rb
+++ b/lib/gitlab/o_auth/auth_hash.rb
@@ -32,8 +32,21 @@ module Gitlab
@password ||= Gitlab::Utils.force_utf8(Devise.friendly_token[0, 8].downcase)
end
- def has_email?
- get_info(:email).present?
+ def location
+ location = get_info(:address)
+ if location.is_a?(Hash)
+ [location.locality.presence, location.country.presence].compact.join(', ')
+ else
+ location
+ end
+ end
+
+ def has_attribute?(attribute)
+ if attribute == :location
+ get_info(:address).present?
+ else
+ get_info(attribute).present?
+ end
end
private
diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb
index e8330917e91..7704bf715e4 100644
--- a/lib/gitlab/o_auth/user.rb
+++ b/lib/gitlab/o_auth/user.rb
@@ -12,7 +12,7 @@ module Gitlab
def initialize(auth_hash)
self.auth_hash = auth_hash
- update_email
+ update_profile if sync_profile_from_provider?
end
def persisted?
@@ -184,20 +184,30 @@ module Gitlab
}
end
- def sync_email_from_provider?
- auth_hash.provider.to_s == Gitlab.config.omniauth.sync_email_from_provider.to_s
+ def sync_profile_from_provider?
+ providers = Gitlab.config.omniauth.sync_profile_from_provider
+
+ if providers.is_a?(Array)
+ providers.include?(auth_hash.provider)
+ else
+ providers
+ end
end
- def update_email
- if auth_hash.has_email? && sync_email_from_provider?
- if persisted?
- gl_user.skip_reconfirmation!
- gl_user.email = auth_hash.email
- end
+ def update_profile
+ user_synced_attributes_metadata = gl_user.user_synced_attributes_metadata || gl_user.build_user_synced_attributes_metadata
- gl_user.external_email = true
- gl_user.email_provider = auth_hash.provider
+ UserSyncedAttributesMetadata::SYNCABLE_ATTRIBUTES.each do |key|
+ if auth_hash.has_attribute?(key) && gl_user.sync_attribute?(key)
+ gl_user[key] = auth_hash.public_send(key) # rubocop:disable GitlabSecurity/PublicSend
+ user_synced_attributes_metadata.set_attribute_synced(key, true)
+ else
+ user_synced_attributes_metadata.set_attribute_synced(key, false)
+ end
end
+
+ user_synced_attributes_metadata.provider = auth_hash.provider
+ gl_user.user_synced_attributes_metadata = user_synced_attributes_metadata
end
def log
diff --git a/lib/gitlab/saml/user.rb b/lib/gitlab/saml/user.rb
index 8a7cc690046..0f323a9e8b2 100644
--- a/lib/gitlab/saml/user.rb
+++ b/lib/gitlab/saml/user.rb
@@ -40,7 +40,7 @@ module Gitlab
end
def find_by_email
- if auth_hash.has_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
diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb
index c81dc7e30d0..703adae12cb 100644
--- a/lib/gitlab/url_sanitizer.rb
+++ b/lib/gitlab/url_sanitizer.rb
@@ -9,7 +9,7 @@ module Gitlab
end
def self.valid?(url)
- return false unless url
+ return false unless url.present?
Addressable::URI.parse(url.strip)
@@ -19,7 +19,12 @@ module Gitlab
end
def initialize(url, credentials: nil)
- @url = Addressable::URI.parse(url.strip)
+ @url = Addressable::URI.parse(url.to_s.strip)
+
+ %i[user password].each do |symbol|
+ credentials[symbol] = credentials[symbol].presence if credentials&.key?(symbol)
+ end
+
@credentials = credentials
end
@@ -29,13 +34,13 @@ module Gitlab
def masked_url
url = @url.dup
- url.password = "*****" unless url.password.nil?
- url.user = "*****" unless url.user.nil?
+ url.password = "*****" if url.password.present?
+ url.user = "*****" if url.user.present?
url.to_s
end
def credentials
- @credentials ||= { user: @url.user, password: @url.password }
+ @credentials ||= { user: @url.user.presence, password: @url.password.presence }
end
def full_url
@@ -47,8 +52,10 @@ module Gitlab
def generate_full_url
return @url unless valid_credentials?
@full_url = @url.dup
- @full_url.user = credentials[:user]
+
@full_url.password = credentials[:password]
+ @full_url.user = credentials[:user]
+
@full_url
end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index e5ad9b5a40c..7a94af2f8f1 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -121,10 +121,10 @@ module Gitlab
]
end
- def send_artifacts_entry(build, entry)
+ def send_artifacts_entry(build, path)
params = {
'Archive' => build.artifacts_file.path,
- 'Entry' => Base64.encode64(entry.path)
+ 'Entry' => Base64.encode64(path.to_s)
}
[
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index d8ab1f253e8..fcd4aa29834 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 10:02-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Bulgarian\n"
"Language: bg_BG\n"
@@ -57,9 +57,18 @@ msgstr "Ðабор от графики отноÑно непрекъÑнатат
msgid "About auto deploy"
msgstr "ОтноÑно автоматичното внедрÑване"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "Ðктивно"
@@ -84,6 +93,12 @@ msgstr "ДобавÑне на нова папка"
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Ðрхивиран проект! Хранилището е Ñамо за четене"
@@ -105,6 +120,63 @@ msgstr ""
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Прикачете файл чрез влачене и пуÑкане или %{upload_link}"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Клон"
@@ -137,6 +209,9 @@ msgstr "Разглеждане на файловете"
msgid "ByAuthor|by"
msgstr "от"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð½Ð° непрекъÑната интеграциÑ"
@@ -164,6 +239,9 @@ msgstr "СпиÑък Ñ Ð¿Ñ€Ð¾Ð¼ÐµÐ½Ð¸"
msgid "Charts"
msgstr "Графики"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Подбиране на това подаване"
@@ -259,12 +337,18 @@ msgstr "Подадено от"
msgid "Compare"
msgstr "Сравнение"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "РъководÑтво за ÑътрудничеÑтво"
msgid "Contributors"
msgstr "Сътрудници"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "Копиране на адреÑа в буфера за обмен"
@@ -351,6 +435,9 @@ msgid_plural "Deploys"
msgstr[0] "ВнедрÑване"
msgstr[1] "ВнедрÑваниÑ"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "ОпиÑание"
@@ -399,6 +486,9 @@ msgstr "Редактиране"
msgid "Edit Pipeline Schedule %{id}"
msgstr "Редактиране на плана %{id} за Ñхема"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -464,6 +554,12 @@ msgstr "От Ñъздаването на проблема до внедрÑваÐ
msgid "From merge request merge until deploy to production"
msgstr "От прилагането на заÑвката за Ñливане до внедрÑването в крайната верÑиÑ"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -476,6 +572,9 @@ msgstr "Към Вашето разклонение"
msgid "GoToYourFork|Fork"
msgstr "Разклонение"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -497,6 +596,9 @@ msgstr ""
msgid "Home"
msgstr "Ðачало"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "ОÑвежаването започна уÑпешно"
@@ -515,14 +617,8 @@ msgstr "ПредÑтавÑме Ви анализа на циклите"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "Задачи за поÑÐ»ÐµÐ´Ð½Ð¸Ñ Ð¼ÐµÑец"
-
-msgid "Jobs for last week"
-msgstr "Задачи за поÑледната Ñедмица"
-
-msgid "Jobs for last year"
-msgstr "Задачи за поÑледната година"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "Изключено"
@@ -530,6 +626,9 @@ msgstr "Изключено"
msgid "LFSStatus|Enabled"
msgstr "Включено"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "ПоÑÐ»ÐµÐ´Ð½Ð¸Ñ %d ден"
@@ -562,20 +661,38 @@ msgstr "ÐапуÑкане на групата"
msgid "Leave project"
msgstr "ÐапуÑкане на проекта"
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "Ограничено до показване на най-много %d Ñъбитие"
msgstr[1] "Ограничено до показване на най-много %d ÑъбитиÑ"
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr "Медиана"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "добавите SSH ключ"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -677,6 +794,9 @@ msgstr "УчаÑтие"
msgid "NotificationLevel|Watch"
msgstr "Ðаблюдение"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Филтър"
@@ -686,9 +806,15 @@ msgstr "Отворен"
msgid "Options"
msgstr "Опции"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "СобÑтвеник"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "Схема"
@@ -701,6 +827,9 @@ msgstr "План за Ñхема"
msgid "Pipeline Schedules"
msgstr "Планове за Ñхема"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "ÐеуÑпешни:"
@@ -764,6 +893,15 @@ msgstr "Схеми"
msgid "Pipelines charts"
msgstr "Графики за Ñхемите"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "вÑички"
@@ -776,6 +914,12 @@ msgstr "Ñ ÐµÑ‚Ð°Ð¿"
msgid "Pipeline|with stages"
msgstr "Ñ ÐµÑ‚Ð°Ð¿Ð¸"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -812,6 +956,9 @@ msgstr "ИзнаÑÑнето на проекта започна. Ще получ
msgid "Project home"
msgstr "Ðачална Ñтраница на проекта"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -836,6 +983,9 @@ msgstr "Етап"
msgid "ProjectNetworkGraph|Graph"
msgstr "Графика"
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -896,6 +1046,9 @@ msgstr "ОтмÑна на това подаване"
msgid "Revert this merge request"
msgstr "ОтмÑна на тази заÑвка за Ñливане"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "Запазване на плана за Ñхема"
@@ -920,6 +1073,9 @@ msgstr ""
msgid "Select target branch"
msgstr "Изберете целеви клон"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Задайте парола на профила Ñи, за да можете да изтеглÑте и изпращате промени чрез %{protocol}."
@@ -935,14 +1091,23 @@ msgstr "ÐаÑтройка на авт. внедрÑване"
msgid "SetPasswordToCloneLink|set a password"
msgstr "зададете парола"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Показване на %d Ñъбитие"
msgstr[1] "Показване на %d ÑъбитиÑ"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "Изходен код"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1219,6 +1384,9 @@ msgstr "ИÑкате ли да видите данните? Помолете аÐ
msgid "We don't have enough data to show this stage."
msgstr "ÐÑма доÑтатъчно данни за този етап."
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "ОттеглÑне на заÑвката за доÑтъп"
@@ -1284,4 +1452,5 @@ msgstr "извеÑÑ‚Ð¸Ñ Ð¿Ð¾ е-поща"
msgid "parent"
msgid_plural "parents"
msgstr[0] "родител"
-msgstr[1] "родители" \ No newline at end of file
+msgstr[1] "родители"
+
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index 3cefb26d234..86deb620f0b 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:29-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: German\n"
"Language: de_DE\n"
@@ -23,20 +23,20 @@ msgstr[1] ""
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%s zusätzlicher Commit wurde ausgelassen um Leistungsprobleme zu verhindern."
+msgstr[1] "%s zusätzliche Commits wurden ausgelassen um Leistungsprobleme zu verhindern."
msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr ""
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
-msgstr ""
+msgstr "%{number_of_failures} von %{maximum_failures} Fehlschlägen. GitLab wird den Zugriff beim nächsten Versuch zulassen."
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will block access for %{number_of_seconds} seconds."
-msgstr ""
+msgstr "%{number_of_failures} von %{maximum_failures} Fehlschlägen. GitLab wird den Zugriff für %{number_of_seconds} Sekunden blockieren."
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} von %{maximum_failures} Fehlschlägen. GitLab wird es nicht weiter versuchen. Setze die Speicherinformation nach Behebung des Problems zurück."
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
@@ -44,7 +44,7 @@ msgstr[0] ""
msgstr[1] ""
msgid "(checkout the %{link} for information on how to install it)."
-msgstr ""
+msgstr "(beachte die Informationen zur Installation auf %{link})."
msgid "1 pipeline"
msgid_plural "%d pipelines"
@@ -52,12 +52,21 @@ msgstr[0] ""
msgstr[1] ""
msgid "A collection of graphs regarding Continuous Integration"
-msgstr ""
+msgstr "Eine Sammlung von Graphen bezüglich kontinuierlicher Integration"
msgid "About auto deploy"
+msgstr "Ãœber automatische Bereitstellung "
+
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
msgstr ""
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
+msgstr "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 ""
msgid "Active"
@@ -67,42 +76,105 @@ msgid "Activity"
msgstr ""
msgid "Add Changelog"
-msgstr ""
+msgstr "Änderungsliste hinzufügen "
msgid "Add Contribution guide"
-msgstr ""
+msgstr "Mitarbeitsanleitung hinzufügen"
msgid "Add License"
msgstr ""
msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr ""
+msgstr "Füge einen SSH Schlüssel zu deinem Profil hinzu, um mittels SSH zu übertragen (push) oder abzurufen (pull)."
msgid "Add new directory"
-msgstr ""
+msgstr "Erstelle eine neues Verzeichnis"
msgid "All"
+msgstr "Alle"
+
+msgid "Appearances"
msgstr ""
-msgid "Archived project! Repository is read-only"
+msgid "Applications"
msgstr ""
+msgid "Archived project! Repository is read-only"
+msgstr "Archiviertes Projekt! Repository ist nicht änderbar."
+
msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
+msgstr "Bist Du sicher, dass Du diesen Pipeline-Zeitplan löschen möchtest?"
msgid "Are you sure you want to discard your changes?"
-msgstr ""
+msgstr "Bist Du sicher, dass Du alle Änderungen zurücksetzen willst?"
msgid "Are you sure you want to reset registration token?"
-msgstr ""
+msgstr "Bist Du sicher, dass Du den Registrierungstoken zurücksetzen willst?"
msgid "Are you sure you want to reset the health check token?"
-msgstr ""
+msgstr "Bist Du sicher, dass Du den Systemüberwachungstoken zurücksetzen willst?"
msgid "Are you sure?"
-msgstr ""
+msgstr "Bist Du sicher?"
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"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
msgstr ""
msgid "Branch"
@@ -111,31 +183,34 @@ msgstr[0] ""
msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
-msgstr ""
+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}"
msgid "BranchSwitcherPlaceholder|Search branches"
-msgstr ""
+msgstr "Branches durchsuchen"
msgid "BranchSwitcherTitle|Switch branch"
-msgstr ""
+msgstr "Branch wechseln"
msgid "Branches"
msgstr ""
msgid "Browse Directory"
-msgstr ""
+msgstr "Verzeichnisse durchsuchen"
msgid "Browse File"
-msgstr ""
+msgstr "Datei durchsuchen"
msgid "Browse Files"
-msgstr ""
+msgstr "Dateien durchsuchen"
msgid "Browse files"
-msgstr ""
+msgstr "Dateien durchsuchen"
msgid "ByAuthor|by"
-msgstr "Von"
+msgstr "von"
+
+msgid "CI / CD"
+msgstr ""
msgid "CI configuration"
msgstr ""
@@ -144,88 +219,91 @@ msgid "Cancel"
msgstr ""
msgid "Cancel edit"
-msgstr ""
+msgstr "Bearbeitung abbrechen"
msgid "ChangeTypeActionLabel|Pick into branch"
-msgstr ""
+msgstr "In dem Branch wählen"
msgid "ChangeTypeActionLabel|Revert in branch"
-msgstr ""
+msgstr "Im Branch wiederherstellen"
msgid "ChangeTypeAction|Cherry-pick"
-msgstr ""
+msgstr "Herauspicken"
msgid "ChangeTypeAction|Revert"
-msgstr ""
+msgstr "Wiederherstellen "
msgid "Changelog"
-msgstr ""
+msgstr "Änderungsliste "
msgid "Charts"
+msgstr "Diagramme"
+
+msgid "Chat"
msgstr ""
msgid "Cherry-pick this commit"
-msgstr ""
+msgstr "Diesen Commit herauspicken "
msgid "Cherry-pick this merge request"
-msgstr ""
+msgstr "Diesen Merge Request herauspicken"
msgid "CiStatusLabel|canceled"
-msgstr ""
+msgstr "abgebrochen"
msgid "CiStatusLabel|created"
-msgstr ""
+msgstr "erstellt"
msgid "CiStatusLabel|failed"
-msgstr ""
+msgstr "fehlgeschlagen"
msgid "CiStatusLabel|manual action"
-msgstr ""
+msgstr "manuelles Eingreifen"
msgid "CiStatusLabel|passed"
-msgstr ""
+msgstr "absolviert"
msgid "CiStatusLabel|passed with warnings"
-msgstr ""
+msgstr "mit Warnungen absolviert"
msgid "CiStatusLabel|pending"
-msgstr ""
+msgstr "ausstehend"
msgid "CiStatusLabel|skipped"
-msgstr ""
+msgstr "übersprungen"
msgid "CiStatusLabel|waiting for manual action"
-msgstr ""
+msgstr "wartet auf manuelles Eingreifen"
msgid "CiStatusText|blocked"
-msgstr ""
+msgstr "blockiert"
msgid "CiStatusText|canceled"
-msgstr ""
+msgstr "abgebrochen"
msgid "CiStatusText|created"
-msgstr ""
+msgstr "erstellt"
msgid "CiStatusText|failed"
-msgstr ""
+msgstr "fehlgeschlagen"
msgid "CiStatusText|manual"
-msgstr ""
+msgstr "manuell"
msgid "CiStatusText|passed"
-msgstr ""
+msgstr "absolviert"
msgid "CiStatusText|pending"
-msgstr ""
+msgstr "ausstehend"
msgid "CiStatusText|skipped"
-msgstr ""
+msgstr "übersprungen"
msgid "CiStatus|running"
-msgstr ""
+msgstr "laufend"
msgid "Comments"
-msgstr ""
+msgstr "Kommentare"
msgid "Commit"
msgid_plural "Commits"
@@ -233,106 +311,112 @@ msgstr[0] ""
msgstr[1] ""
msgid "Commit duration in minutes for last 30 commits"
-msgstr ""
+msgstr "Dauer der Commits in Minuten für die letzten 30 Commits"
msgid "Commit message"
-msgstr ""
+msgstr "Commit Nachricht"
msgid "CommitBoxTitle|Commit"
-msgstr ""
+msgstr "Commit"
msgid "CommitMessage|Add %{file_name}"
-msgstr ""
+msgstr "%{file_name} hinzufügen"
msgid "Commits"
msgstr ""
msgid "Commits feed"
-msgstr ""
+msgstr "Liste der Commits"
msgid "Commits|History"
-msgstr ""
+msgstr "Verlauf"
msgid "Committed by"
-msgstr ""
+msgstr "Committed von"
msgid "Compare"
+msgstr "Vergleichen"
+
+msgid "Container Registry"
msgstr ""
msgid "Contribution guide"
-msgstr ""
+msgstr "Mitarbeitsanleitung"
msgid "Contributors"
+msgstr "Mitarbeiter"
+
+msgid "Copy SSH public key to clipboard"
msgstr ""
msgid "Copy URL to clipboard"
-msgstr ""
+msgstr "Kopiere URL in die Zwischenablage"
msgid "Copy commit SHA to clipboard"
-msgstr ""
+msgstr "Kopiere Commit SHA in die Zwischenablage"
msgid "Create New Directory"
-msgstr ""
+msgstr "Erstelle neues Verzeichnis"
msgid "Create a new branch"
-msgstr ""
+msgstr "Erstelle einen neuen Branch"
msgid "Create a personal access token on your account to pull or push via %{protocol}."
-msgstr ""
+msgstr "Erstelle einen persönlichen Zugriffstoken in Deinem Konto um mittels %{protocol} zu übertragen (push) oder abzurufen (pull)."
msgid "Create directory"
-msgstr ""
+msgstr "Erstelle Verzeichnis"
msgid "Create empty bare repository"
-msgstr ""
+msgstr "Erstelle leeres Repository"
msgid "Create merge request"
-msgstr ""
+msgstr "Erstelle Merge Request"
msgid "Create new..."
-msgstr ""
+msgstr "Erstelle neues..."
msgid "CreateNewFork|Fork"
-msgstr ""
+msgstr "Ableger"
msgid "CreateTag|Tag"
-msgstr ""
+msgstr "Tag "
msgid "CreateTokenToCloneLink|create a personal access token"
-msgstr ""
+msgstr "Erstelle einen persönlichen Zugriffstoken"
msgid "Cron Timezone"
-msgstr ""
+msgstr "Cron Zeitzone"
msgid "Cron syntax"
-msgstr ""
+msgstr "Cron Syntax"
msgid "Custom notification events"
-msgstr ""
+msgstr "Individuelle Benachrichtigungsereignisse"
msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}."
-msgstr ""
+msgstr "Individuelle Benachrichtigungsstufen sind identisch mit den Beteiligungsstufen. Mit individuellen Benachrichtigungsstufen erhältst Du ebenfalls Mitteilungen für ausgewählte Ereignisse. Für weitere Informationen lies %{notification_link}. "
msgid "Cycle Analytics"
-msgstr ""
+msgstr "Arbeitsablaufsanalysen"
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
-msgstr "Cycle Analytics liefern einen Überblick darüber, wie viel Zeit in Ihrem Projekt von einer Idee bis zum Produktivdeployment vergeht."
+msgstr "Arbeitsablaufsanalysen verschaffen einen Überblick, welche Zeit Dein Projekt von der Idee zur Realisierung benötigt."
msgid "CycleAnalyticsStage|Code"
-msgstr "Code"
+msgstr "Entwicklung"
msgid "CycleAnalyticsStage|Issue"
-msgstr "Issue"
+msgstr "Ticket"
msgid "CycleAnalyticsStage|Plan"
msgstr "Planung"
msgid "CycleAnalyticsStage|Production"
-msgstr "Produktiv"
+msgstr "Produktion"
msgid "CycleAnalyticsStage|Review"
-msgstr "Review"
+msgstr "Überprüfung"
msgid "CycleAnalyticsStage|Staging"
msgstr "Staging"
@@ -341,281 +425,314 @@ msgid "CycleAnalyticsStage|Test"
msgstr "Test"
msgid "Define a custom pattern with cron syntax"
-msgstr ""
+msgstr "Erstelle ein individuelles Muster mittels Cron Syntax"
msgid "Delete"
-msgstr ""
+msgstr "Löschen"
msgid "Deploy"
msgid_plural "Deploys"
-msgstr[0] "Deployment"
-msgstr[1] "Deployments"
+msgstr[0] "Bereitstellung"
+msgstr[1] "Bereitstellungen"
-msgid "Description"
+msgid "Deploy Keys"
msgstr ""
+msgid "Description"
+msgstr "Beschreibung"
+
msgid "Details"
msgstr ""
msgid "Directory name"
-msgstr ""
+msgstr "Verzeichnisname"
msgid "Discard changes"
-msgstr ""
+msgstr "Änderungen verwerfen"
msgid "Don't show again"
-msgstr ""
+msgstr "Nicht erneut anzeigen"
msgid "Download"
-msgstr ""
+msgstr "Herunterladen"
msgid "Download tar"
-msgstr ""
+msgstr "TAR-Datei herunterladen"
msgid "Download tar.bz2"
-msgstr ""
+msgstr "TAR.BZ2-Datei herunterladen"
msgid "Download tar.gz"
-msgstr ""
+msgstr "TAR.GZ-Datei herunterladen"
msgid "Download zip"
-msgstr ""
+msgstr "ZIP-Datei herunterladen"
msgid "DownloadArtifacts|Download"
-msgstr ""
+msgstr "Herunterladen"
msgid "DownloadCommit|Email Patches"
-msgstr ""
+msgstr "E-Mail Patch"
msgid "DownloadCommit|Plain Diff"
-msgstr ""
+msgstr "Unterschiede"
msgid "DownloadSource|Download"
-msgstr ""
+msgstr "Herunterladen"
msgid "Edit"
-msgstr ""
+msgstr "Bearbeiten"
msgid "Edit Pipeline Schedule %{id}"
+msgstr "Pipeline Zeitplan bearbeiten %{id}"
+
+msgid "Emails"
msgstr ""
msgid "EventFilterBy|Filter by all"
-msgstr ""
+msgstr "Filtere alle"
msgid "EventFilterBy|Filter by comments"
-msgstr ""
+msgstr "Filtere nach Kommentaren"
msgid "EventFilterBy|Filter by issue events"
-msgstr ""
+msgstr "Filtere nach Tickets"
msgid "EventFilterBy|Filter by merge events"
-msgstr ""
+msgstr "Filtere nach Merge Requests"
msgid "EventFilterBy|Filter by push events"
-msgstr ""
+msgstr "Filtere nach Ãœbertragungen"
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "Filtere nach Teams"
msgid "Every day (at 4:00am)"
-msgstr ""
+msgstr "Täglich (um 4:00 Uhr)"
msgid "Every month (on the 1st at 4:00am)"
-msgstr ""
+msgstr "Monatlich (am Ersten um 4:00 Uhr)"
msgid "Every week (Sundays at 4:00am)"
-msgstr ""
+msgstr "Wöchentlich (Sonntags um 4:00 Uhr)"
msgid "Failed to change the owner"
-msgstr ""
+msgstr "Wechsel des Besitzers fehlgeschlagen"
msgid "Failed to remove the pipeline schedule"
-msgstr ""
+msgstr "Entfernung der Pipelineplanung fehlgeschlagen"
msgid "Files"
-msgstr ""
+msgstr "Dateien"
msgid "Filter by commit message"
-msgstr ""
+msgstr "Filter nach Commit Nachricht"
msgid "Find by path"
-msgstr ""
+msgstr "Finde über den Pfad"
msgid "Find file"
-msgstr ""
+msgstr "Finde Datei"
msgid "FirstPushedBy|First"
msgstr "Erster"
msgid "FirstPushedBy|pushed by"
-msgstr "gepusht von"
+msgstr "übertragen von"
msgid "Fork"
msgid_plural "Forks"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Ableger"
+msgstr[1] "Ableger"
msgid "ForkedFromProjectPath|Forked from"
-msgstr ""
+msgstr "Ableger von"
msgid "From issue creation until deploy to production"
-msgstr "Vom Anlegen des Issues bis zum Produktivdeployment"
+msgstr "Von der Ticketbeschreibung bis zur Bereitstellung"
msgid "From merge request merge until deploy to production"
-msgstr "Vom Merge Request bis zum Produktivdeployment"
+msgstr "Vom Umsetzen des Merge Request bis zur Bereitstellung auf dem Produktivsystem"
-msgid "Git storage health information has been reset"
+msgid "GPG Keys"
msgstr ""
-msgid "GitLab Runner section"
+msgid "Geo Nodes"
msgstr ""
+msgid "Git storage health information has been reset"
+msgstr "Informationen über den Speicherzustand von Gitlab wurden zurückgesetzt."
+
+msgid "GitLab Runner section"
+msgstr "GitLab Runner Bereich"
+
msgid "Go to your fork"
-msgstr ""
+msgstr "Gehe zu Deinem Ableger"
msgid "GoToYourFork|Fork"
+msgstr "Ableger"
+
+msgid "Group overview"
msgstr ""
msgid "Health Check"
-msgstr ""
+msgstr "Systemzustand"
msgid "Health information can be retrieved from the following endpoints. More information is available"
-msgstr ""
+msgstr "Informationen über den Systemzustand können von folgenden Endpunkten erhalten werden. Mehr Informationen gibt es"
msgid "HealthCheck|Access token is"
-msgstr ""
+msgstr "Zugriffstoken ist"
msgid "HealthCheck|Healthy"
-msgstr ""
+msgstr "OK"
msgid "HealthCheck|No Health Problems Detected"
-msgstr ""
+msgstr "Keine Probleme erkannt"
msgid "HealthCheck|Unhealthy"
-msgstr ""
+msgstr "Problematisch"
msgid "Home"
+msgstr "Startseite"
+
+msgid "Hooks"
msgstr ""
msgid "Housekeeping successfully started"
-msgstr ""
+msgstr "Aufräumen erfolgreich gestartet"
msgid "Import repository"
-msgstr ""
+msgstr "Repository importieren"
msgid "Install a Runner compatible with GitLab CI"
-msgstr ""
+msgstr "Installiere einen Runner der mit GitLab CI kompatibel ist"
msgid "Interval Pattern"
-msgstr ""
+msgstr "Intervallmuster"
msgid "Introducing Cycle Analytics"
-msgstr "Was sind Cycle Analytics?"
+msgstr "Arbeitsablaufsanalysen vorgestellt"
msgid "Issue events"
-msgstr ""
-
-msgid "Jobs for last month"
-msgstr ""
+msgstr "Ticketereignisse"
-msgid "Jobs for last week"
-msgstr ""
-
-msgid "Jobs for last year"
+msgid "Issues"
msgstr ""
msgid "LFSStatus|Disabled"
-msgstr ""
+msgstr "Deaktiviert"
msgid "LFSStatus|Enabled"
+msgstr "Aktiviert"
+
+msgid "Labels"
msgstr ""
msgid "Last %d day"
msgid_plural "Last %d days"
-msgstr[0] "Letzter %d Tag"
+msgstr[0] "Letzten %d Tag"
msgstr[1] "Letzten %d Tage"
msgid "Last Pipeline"
-msgstr ""
+msgstr "Letzte Pipeline"
msgid "Last Update"
-msgstr ""
+msgstr "Letzte Aktualisierung"
msgid "Last commit"
-msgstr ""
+msgstr "Letzter Commit"
msgid "LastPushEvent|You pushed to"
-msgstr ""
+msgstr "Du übertrugst an"
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "am"
msgid "Learn more in the"
-msgstr ""
+msgstr "Erfahre mehr in den"
msgid "Learn more in the|pipeline schedules documentation"
-msgstr ""
+msgstr "Pipelineplanungsdokumentation"
msgid "Leave group"
-msgstr ""
+msgstr "Verlasse die Gruppe"
msgid "Leave project"
+msgstr "Verlasse das Projekt"
+
+msgid "License"
msgstr ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
-msgstr[0] "Eingeschränkt auf maximal %d Ereignis"
-msgstr[1] "Eingeschränkt auf maximal %d Ereignisse"
+msgstr[0] "Limitiere die Anzeige auf höchstens %d Ereignis"
+msgstr[1] "Limitiere die Anzeige auf höchstens %d Ereignisse"
+
+msgid "Locked Files"
+msgstr ""
msgid "Median"
msgstr ""
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
+msgstr "Ereignisse zusammenführen"
+
+msgid "Messages"
msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
+msgstr "einen SSH Schlüssel hinzufügst"
+
+msgid "Monitoring"
msgstr ""
msgid "More information is available|here"
-msgstr ""
+msgstr "hier"
msgid "New Issue"
msgid_plural "New Issues"
-msgstr[0] "Neues Issue"
-msgstr[1] "Neue Issues"
+msgstr[0] "Neues Ticket"
+msgstr[1] "Neue Tickets"
msgid "New Pipeline Schedule"
-msgstr ""
+msgstr "Neuer Pipeline Zeitplan"
msgid "New branch"
-msgstr ""
+msgstr "Neuer Branch"
msgid "New directory"
-msgstr ""
+msgstr "Neues Verzeichnis"
msgid "New file"
-msgstr ""
+msgstr "Neue Datei"
msgid "New issue"
-msgstr ""
+msgstr "Neues Ticket"
msgid "New merge request"
-msgstr ""
+msgstr "Neuer Merge Request"
msgid "New schedule"
-msgstr ""
+msgstr "Neuer Zeitplan"
msgid "New snippet"
-msgstr ""
+msgstr "Neuer Schnipsel"
msgid "New tag"
-msgstr ""
+msgstr "Neuer Tag"
msgid "No repository"
-msgstr ""
+msgstr "Kein Repository"
msgid "No schedules"
-msgstr ""
+msgstr "Keine Zeitpläne"
msgid "Not available"
msgstr "Nicht verfügbar"
@@ -624,241 +741,274 @@ msgid "Not enough data"
msgstr "Nicht genügend Daten"
msgid "Notification events"
-msgstr ""
+msgstr "Benachrichtigungsereignisse"
msgid "NotificationEvent|Close issue"
-msgstr ""
+msgstr "Ticket abschließen"
msgid "NotificationEvent|Close merge request"
-msgstr ""
+msgstr "Merge Request abschließen"
msgid "NotificationEvent|Failed pipeline"
-msgstr ""
+msgstr "Fehlgeschlagene Pipeline"
msgid "NotificationEvent|Merge merge request"
-msgstr ""
+msgstr "Merge Request umsetzen"
msgid "NotificationEvent|New issue"
-msgstr ""
+msgstr "Neues Ticket"
msgid "NotificationEvent|New merge request"
-msgstr ""
+msgstr "Neuer Merge Request"
msgid "NotificationEvent|New note"
-msgstr ""
+msgstr "Neue Notiz"
msgid "NotificationEvent|Reassign issue"
-msgstr ""
+msgstr "Ticket neu zuweisen"
msgid "NotificationEvent|Reassign merge request"
-msgstr ""
+msgstr "Merge Request neu zuweisen"
msgid "NotificationEvent|Reopen issue"
-msgstr ""
+msgstr "Ticket wieder öffnen"
msgid "NotificationEvent|Successful pipeline"
-msgstr ""
+msgstr "Erfolgreiche Pipeline"
msgid "NotificationLevel|Custom"
-msgstr ""
+msgstr "Individuell"
msgid "NotificationLevel|Disabled"
-msgstr ""
+msgstr "Deaktiviert"
msgid "NotificationLevel|Global"
-msgstr ""
+msgstr "Global"
msgid "NotificationLevel|On mention"
-msgstr ""
+msgstr "Zum Vermerk"
msgid "NotificationLevel|Participate"
-msgstr ""
+msgstr "Teilnehmen"
msgid "NotificationLevel|Watch"
+msgstr "Beobachten"
+
+msgid "Notifications"
msgstr ""
msgid "OfSearchInADropdown|Filter"
-msgstr ""
+msgstr "Filter"
msgid "OpenedNDaysAgo|Opened"
-msgstr "Erstellt"
+msgstr "Ungelöst"
msgid "Options"
+msgstr "Optionen"
+
+msgid "Overview"
msgstr ""
msgid "Owner"
+msgstr "Besitzer"
+
+msgid "Password"
msgstr ""
msgid "Pipeline"
msgstr ""
msgid "Pipeline Health"
-msgstr "Pipeline Kennzahlen"
+msgstr "Zustand der Pipeline"
msgid "Pipeline Schedule"
-msgstr ""
+msgstr "Zeitplan der Pipeline"
msgid "Pipeline Schedules"
+msgstr "Zustände der Pipeline"
+
+msgid "Pipeline quota"
msgstr ""
msgid "PipelineCharts|Failed:"
-msgstr ""
+msgstr "Fehlgeschlagen:"
msgid "PipelineCharts|Overall statistics"
-msgstr ""
+msgstr "Gesamte Statisktiken"
msgid "PipelineCharts|Success ratio:"
-msgstr ""
+msgstr "Erfolgsverhältnis:"
msgid "PipelineCharts|Successful:"
-msgstr ""
+msgstr "Erfolgreich:"
msgid "PipelineCharts|Total:"
-msgstr ""
+msgstr "Insgesamt:"
msgid "PipelineSchedules|Activated"
-msgstr ""
+msgstr "Aktiviert"
msgid "PipelineSchedules|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "PipelineSchedules|All"
-msgstr ""
+msgstr "Alle"
msgid "PipelineSchedules|Inactive"
-msgstr ""
+msgstr "Inaktiv"
msgid "PipelineSchedules|Input variable key"
-msgstr ""
+msgstr "Schlüssel der Eingangsvariable"
msgid "PipelineSchedules|Input variable value"
-msgstr ""
+msgstr "Wert der Eingangsvariable"
msgid "PipelineSchedules|Next Run"
-msgstr ""
+msgstr "Nächste Durchführung"
msgid "PipelineSchedules|None"
-msgstr ""
+msgstr "Nichts"
msgid "PipelineSchedules|Provide a short description for this pipeline"
-msgstr ""
+msgstr "Beschreibe diese Pipeline"
msgid "PipelineSchedules|Remove variable row"
-msgstr ""
+msgstr "Entferne Variablenreihe"
msgid "PipelineSchedules|Take ownership"
-msgstr ""
+msgstr "Eigentümer werden"
msgid "PipelineSchedules|Target"
-msgstr ""
+msgstr "Ziel"
msgid "PipelineSchedules|Variables"
-msgstr ""
+msgstr "Variablen"
msgid "PipelineSheduleIntervalPattern|Custom"
-msgstr ""
+msgstr "Individuell"
msgid "Pipelines"
msgstr ""
msgid "Pipelines charts"
+msgstr "Pipelinediagramme"
+
+msgid "Pipelines for last month"
msgstr ""
-msgid "Pipeline|all"
+msgid "Pipelines for last week"
msgstr ""
-msgid "Pipeline|success"
+msgid "Pipelines for last year"
msgstr ""
+msgid "Pipeline|all"
+msgstr "Alle"
+
+msgid "Pipeline|success"
+msgstr "Erfolg"
+
msgid "Pipeline|with stage"
-msgstr ""
+msgstr "mit Stage"
msgid "Pipeline|with stages"
+msgstr "mit Stages"
+
+msgid "Preferences"
msgstr ""
-msgid "Project"
+msgid "Profile Settings"
msgstr ""
+msgid "Project"
+msgstr "Projekt"
+
msgid "Project '%{project_name}' queued for deletion."
-msgstr ""
+msgstr "Das Projekt '%{project_name}' wurde zur Löschung eingeplant."
msgid "Project '%{project_name}' was successfully created."
-msgstr ""
+msgstr "Das Projekt '%{project_name}' wurde erfolgreich erstellt."
msgid "Project '%{project_name}' was successfully updated."
-msgstr ""
+msgstr "Das Projekt '%{project_name}' wurde erfolgreich aktualisiert."
msgid "Project '%{project_name}' will be deleted."
-msgstr ""
+msgstr "Das Projekt '%{project_name}' wird gelöscht."
msgid "Project access must be granted explicitly to each user."
-msgstr ""
+msgstr "Jedem Nutzer muss explizit der Zugriff auf das Projekt gewährt werden."
msgid "Project details"
-msgstr ""
+msgstr "Projektdetails"
msgid "Project export could not be deleted."
-msgstr ""
+msgstr "Der Export des Projekts konnte nich gelöscht werden."
msgid "Project export has been deleted."
-msgstr ""
+msgstr "Der Export des Projekts wurde gelöscht."
msgid "Project export link has expired. Please generate a new export from your project settings."
-msgstr ""
+msgstr "Der Link für den Export des Projektes ist abgelaufen. Bitte generiere einen neuen Export in den Projekteinstellungen."
msgid "Project export started. A download link will be sent by email."
-msgstr ""
+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 ""
+msgstr "Abonnieren"
msgid "ProjectFeature|Disabled"
-msgstr ""
+msgstr "Dekativiert"
msgid "ProjectFeature|Everyone with access"
-msgstr ""
+msgstr "Jeder mit Zugriff"
msgid "ProjectFeature|Only team members"
-msgstr ""
+msgstr "Nur Teammitglieder"
msgid "ProjectFileTree|Name"
-msgstr ""
+msgstr "Name"
msgid "ProjectLastActivity|Never"
-msgstr ""
+msgstr "Niemals"
msgid "ProjectLifecycle|Stage"
-msgstr "Phase"
+msgstr "Stage"
msgid "ProjectNetworkGraph|Graph"
+msgstr "Diagramm"
+
+msgid "Push Rules"
msgstr ""
msgid "Push events"
-msgstr ""
+msgstr "Ãœbertragungsereignisse"
msgid "Read more"
-msgstr "Mehr"
+msgstr "Mehr lesen"
msgid "Readme"
-msgstr ""
+msgstr "Lies mich"
msgid "RefSwitcher|Branches"
-msgstr ""
+msgstr "Branches"
msgid "RefSwitcher|Tags"
-msgstr ""
+msgstr "Tags"
msgid "Related Commits"
msgstr "Zugehörige Commits"
msgid "Related Deployed Jobs"
-msgstr "Zugehörige Deploymentjobs"
+msgstr "Zugehörige ausgelieferte Jobs"
msgid "Related Issues"
-msgstr "Zugehörige Issues"
+msgstr "Zugehörige Tickets"
msgid "Related Jobs"
msgstr "Zugehörige Jobs"
@@ -867,72 +1017,81 @@ msgid "Related Merge Requests"
msgstr "Zugehörige Merge Requests"
msgid "Related Merged Requests"
-msgstr "Zugehörige abgeschlossene Merge Requests"
+msgstr "Zugehörige umgesetzte Merge Requests"
msgid "Remind later"
-msgstr ""
+msgstr "Später erinnern"
msgid "Remove project"
-msgstr ""
+msgstr "Projekt entfernen"
msgid "Repository"
msgstr ""
msgid "Request Access"
-msgstr ""
+msgstr "Anfrage auf Zugriff"
msgid "Reset git storage health information"
-msgstr ""
+msgstr "Informationen über Speicherzustand zurücksetzen"
msgid "Reset health check access token"
-msgstr ""
+msgstr "Zugriffstoken für Systemzustand zurücksetzen"
msgid "Reset runners registration token"
-msgstr ""
+msgstr "Registrierungstoken für Runner zurücksetzen"
msgid "Revert this commit"
-msgstr ""
+msgstr "Commit zurücksetzen"
msgid "Revert this merge request"
+msgstr "Merge Request zurücksetzen"
+
+msgid "SSH Keys"
msgstr ""
msgid "Save pipeline schedule"
-msgstr ""
+msgstr "Zeitplan der Pipeline speichern"
msgid "Schedule a new pipeline"
-msgstr ""
+msgstr "Plane eine neue Pipeline"
msgid "Scheduling Pipelines"
-msgstr ""
+msgstr "Pipelines planen"
msgid "Search branches and tags"
-msgstr ""
+msgstr "Suche nach Branches und Tags"
msgid "Select Archive Format"
-msgstr ""
+msgstr "Archivierungsformat auswählen"
msgid "Select a timezone"
-msgstr ""
+msgstr "Zeitzone auswählen"
msgid "Select existing branch"
-msgstr ""
+msgstr "Existierenden Branch auswählen"
msgid "Select target branch"
+msgstr "Zielbranch auswählen"
+
+msgid "Service Templates"
msgstr ""
msgid "Set a password on your account to pull or push via %{protocol}."
-msgstr ""
+msgstr "Lege ein Passwort für dein Konto fest, um mittels %{protocol} zu übertragen (push) oder abzurufen (pull)."
msgid "Set up CI"
-msgstr ""
+msgstr "CI einrichten"
msgid "Set up Koding"
-msgstr ""
+msgstr "Koding einrichten"
msgid "Set up auto deploy"
-msgstr ""
+msgstr "Automatische Bereitstellung einrichten"
msgid "SetPasswordToCloneLink|set a password"
+msgstr "ein Passwort festlegst"
+
+msgid "Settings"
msgstr ""
msgid "Showing %d event"
@@ -940,23 +1099,29 @@ msgid_plural "Showing %d events"
msgstr[0] "Zeige %d Ereignis"
msgstr[1] "Zeige %d Ereignisse"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
+msgstr "Quellcode"
+
+msgid "Spam Logs"
msgstr ""
msgid "Specify the following URL during the Runner setup:"
-msgstr ""
+msgstr "Lege die folgende URL während des Runner Setups fest:"
msgid "StarProject|Star"
-msgstr ""
+msgstr "Favorisieren"
msgid "Start a %{new_merge_request} with these changes"
-msgstr ""
+msgstr "Beginne einen %{new_merge_request} mit diesen Änderungen"
msgid "Start the Runner!"
-msgstr ""
+msgstr "Starte den Runner!"
msgid "Switch branch/tag"
-msgstr ""
+msgstr "Zu Branch/Tag wechseln"
msgid "Tag"
msgid_plural "Tags"
@@ -967,308 +1132,311 @@ msgid "Tags"
msgstr ""
msgid "Target Branch"
-msgstr ""
+msgstr "Zielbranch"
msgid "Team"
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 "Die Code-Phase stellt die Zeit vom ersten Commit bis zum Erstellen eines Merge Requests dar. Sobald Sie Ihren ersten Merge Request anlegen, werden dessen Daten automatisch ergänzt."
+msgstr "Die Entwicklungsphase stellt die Zeit vom ersten Commit bis zum Erstellen eines Merge Requests dar. Sobald Du Deinen ersten Merge Request anlegst, werden dessen Daten automatisch ergänzt."
msgid "The collection of events added to the data gathered for that stage."
msgstr "Ereignisse, die für diese Phase ausgewertet wurden."
msgid "The fork relationship has been removed."
-msgstr ""
+msgstr "Die Beziehung des Ablegers wurde entfernt."
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
-msgstr "Die Issue-Phase stellt die Zeit vom Anlegen eines Issues bis zum Zuweisen eines Meilensteins oder Hinzufügen zum Issue Board dar. Erstellen Sie einen Issue, damit dessen Daten hier erscheinen."
+msgstr "Die Ticketphase stellt die Zeit vom Anlegen eines Tickets bis zum Zuweisen eines Meilensteins oder Hinzufügen zur Aufgabentafel dar. Erstelle einen Ticket, damit dessen Daten hier erscheinen."
msgid "The phase of the development lifecycle."
-msgstr "Die Phase im Entwicklungsprozess."
+msgstr "Die Phase des Entwicklungslebenszyklus."
msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
-msgstr ""
+msgstr "Die Pipelinezeitpläne starten Pipelines in der Zukunft, wiederholend, für bestimmte Branches oder Tags. Diese geplanten Pipelines haben denselben begrenzten Zugriff auf das Projekt, wie der zugeordnete Nutzer."
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
-msgstr "Die Planungsphase stellt die Zeit von der vorherigen Phase bis zum Pushen des ersten Commits dar. Sobald Sie den ersten Commit pushen, werden dessen Daten hier erscheinen."
+msgstr "Die Planungsphase stellt die Zeit von der vorherigen Phase bis zum Übertragen des ersten Commits dar. Sobald Du den ersten Commit überträgst, werden dessen Daten hier erscheinen."
msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "Die Produktiv-Phase stellt die Gesamtzeit vom Anlegen eines Issues bis zum Deployment auf dem Produktivsystem dar. Sobald Sie den vollständigen Entwicklungszyklus von einer Idee bis zum Produktivdeployment durchlaufen haben, erscheinen die zugehörigen Daten hier."
+msgstr "Die Produktionsphase stellt die Gesamtzeit vom Anlegen eines Tickets bis zur Bereitstellung des Codes auf dem Produktivsystem dar. Sobald Du den vollständigen Entwicklungszyklus, von einer Idee bis zur Fertigstellung, durchlaufen hast, erscheinen die zugehörigen Daten hier."
msgid "The project can be accessed by any logged in user."
-msgstr ""
+msgstr "Auf das Projekt kann jeder angemeldete Nutzer zugreifen."
msgid "The project can be accessed without any authentication."
-msgstr ""
+msgstr "Auf das Projekt kann ohne Authentifizierung zugegriffen werden."
msgid "The repository for this project does not exist."
-msgstr ""
+msgstr "Das Repository für das Projekt existiert nicht."
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
-msgstr "Die Review-Phase stellt die Zeit vom Anlegen eines Merge Requests bis zum Mergen dar. Sobald Sie Ihren ersten Merge Request abschließen, werden dessen Daten hier automatisch angezeigt."
+msgstr "Die Überprüfungsphase stellt die Zeit vom Anlegen eines Merge Requests bis dessen Umsetzung dar. Sobald Du Deinen ersten Merge Request abschließt, werden dessen Daten hier automatisch angezeigt."
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
-msgstr "Die Staging-Phase stellt die Zeit zwischen Mergen eines Merge Requests und dem Produktivdeployment dar. Sobald Sie das erste Produktivdeployment durchgeführt haben, werden dessen Daten hier automatisch angezeigt."
+msgstr "Die Staging-Phase stellt die Zeit zwischen der Umsetzung eines Merge Requests und der Bereitstellung des Codes auf dem Produktivsystem dar. Sobald Du das erste Mal auf das Produktivsystem ausgeliefert hast, werden dessen Daten hier automatisch angezeigt."
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
-msgstr "Die Test-Phase stellt die Zeit dar, die GitLab CI benötigt um die Pipelines von Merge Requests abzuarbeiten. Sobald die erste Pipeline abgeschlossen ist, werden deren Daten hier automatisch angezeigt."
+msgstr "Die Testphase stellt die Zeit dar, die GitLab CI benötigt um die Pipelines von zugehörigen Merge Requests abzuarbeiten. Sobald die erste Pipeline abgeschlossen ist, werden deren Daten hier automatisch angezeigt."
msgid "The time taken by each data entry gathered by that stage."
-msgstr "Zeit die für das jeweilige Ereignis in der Phase ermittelt wurde."
+msgstr "Zeit, die für das jeweilige Ereignis in der Phase ermittelt wurde."
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr "Der mittlere aller erfassten Werte. Zum Beispiel ist für 3, 5, 9 der Median 5. Bei 3, 5, 7, 8 ist der Median (5+7)/2 = 6."
msgid "There are problems accessing Git storage: "
-msgstr ""
+msgstr "Es gibt ein Problem beim Zugriff auf den Gitspeicher:"
msgid "This means you can not push code until you create an empty repository or import existing one."
-msgstr ""
+msgstr "Dies bedeutet, dass Du keinen Code übertragen kannst, bevor Du kein leeres Repositorium erstellt oder ein Existierendes importiert hast."
msgid "Time before an issue gets scheduled"
-msgstr "Zeit bis ein Issue geplant wird"
+msgstr "Zeit bis ein Ticket geplant wird"
msgid "Time before an issue starts implementation"
-msgstr "Zeit bis die Implementierung für ein Issue beginnt"
+msgstr "Zeit bis die Implementierung für ein Ticket beginnt"
msgid "Time between merge request creation and merge/close"
-msgstr "Zeit zwischen Anlegen und Mergen/Schließen eines Merge Requests"
+msgstr "Zeit zwischen einem Merge Request und dessen Umsetzung / Schließung"
msgid "Time until first merge request"
msgstr "Zeit bis zum ersten Merge Request"
msgid "Timeago|%s days ago"
-msgstr ""
+msgstr "seit %s Tagen"
msgid "Timeago|%s days remaining"
-msgstr ""
+msgstr "%s Tage verbleibend"
msgid "Timeago|%s hours remaining"
-msgstr ""
+msgstr "%s Stunden verbleibend"
msgid "Timeago|%s minutes ago"
-msgstr ""
+msgstr "seit %s Minuten "
msgid "Timeago|%s minutes remaining"
-msgstr ""
+msgstr "%s Minuten verbleibend"
msgid "Timeago|%s months ago"
-msgstr ""
+msgstr "seit %s Monaten"
msgid "Timeago|%s months remaining"
-msgstr ""
+msgstr "%s Monate verbleibend"
msgid "Timeago|%s seconds remaining"
-msgstr ""
+msgstr "%s Sekunden verbleibend"
msgid "Timeago|%s weeks ago"
-msgstr ""
+msgstr "seit %s Wochen"
msgid "Timeago|%s weeks remaining"
-msgstr ""
+msgstr "%s Wochen verbleibend"
msgid "Timeago|%s years ago"
-msgstr ""
+msgstr "seit %s Jahren"
msgid "Timeago|%s years remaining"
-msgstr ""
+msgstr "%s Jahre verbleibend"
msgid "Timeago|1 day remaining"
-msgstr ""
+msgstr "1 Tag verbleibend"
msgid "Timeago|1 hour remaining"
-msgstr ""
+msgstr "1 Stunde verbleibend"
msgid "Timeago|1 minute remaining"
-msgstr ""
+msgstr "1 Minute verbleibend"
msgid "Timeago|1 month remaining"
-msgstr ""
+msgstr "1 Monat verbleibend"
msgid "Timeago|1 week remaining"
-msgstr ""
+msgstr "1 Woche verbleibend"
msgid "Timeago|1 year remaining"
-msgstr ""
+msgstr "1 Jahr verbleibend"
msgid "Timeago|Past due"
-msgstr ""
+msgstr "Fällig"
msgid "Timeago|a day ago"
-msgstr ""
+msgstr "vor einem Tag"
msgid "Timeago|a month ago"
-msgstr ""
+msgstr "vor einem Monat"
msgid "Timeago|a week ago"
-msgstr ""
+msgstr "vor einer Woche"
msgid "Timeago|a while"
-msgstr ""
+msgstr "eine Weile"
msgid "Timeago|a year ago"
-msgstr ""
+msgstr "vor einem Jahr"
msgid "Timeago|about %s hours ago"
-msgstr ""
+msgstr "vor ungefähr %s Stunden"
msgid "Timeago|about a minute ago"
-msgstr ""
+msgstr "vor ungefähr einer Minute"
msgid "Timeago|about an hour ago"
-msgstr ""
+msgstr "vor ungefähr einer Stunde"
msgid "Timeago|in %s days"
-msgstr ""
+msgstr "in %s Tagen"
msgid "Timeago|in %s hours"
-msgstr ""
+msgstr "in %s Stunden"
msgid "Timeago|in %s minutes"
-msgstr ""
+msgstr "in %s Minuten"
msgid "Timeago|in %s months"
-msgstr ""
+msgstr "in %s Monaten"
msgid "Timeago|in %s seconds"
-msgstr ""
+msgstr "in %s Sekunden"
msgid "Timeago|in %s weeks"
-msgstr ""
+msgstr "in %s Wochen"
msgid "Timeago|in %s years"
-msgstr ""
+msgstr "in %s Jahren"
msgid "Timeago|in 1 day"
-msgstr ""
+msgstr "in 1 Tag"
msgid "Timeago|in 1 hour"
-msgstr ""
+msgstr "in 1 Stunde"
msgid "Timeago|in 1 minute"
-msgstr ""
+msgstr "in 1 Minute"
msgid "Timeago|in 1 month"
-msgstr ""
+msgstr "in 1 Monat"
msgid "Timeago|in 1 week"
-msgstr ""
+msgstr "in 1 Woche"
msgid "Timeago|in 1 year"
-msgstr ""
+msgstr "in 1 Jahr"
msgid "Timeago|less than a minute ago"
-msgstr ""
+msgstr "vor weniger als einer Minute"
msgid "Time|hr"
msgid_plural "Time|hrs"
-msgstr[0] "h"
-msgstr[1] "h"
+msgstr[0] "Std."
+msgstr[1] "Stdn."
msgid "Time|min"
msgid_plural "Time|mins"
-msgstr[0] "min"
-msgstr[1] "min"
+msgstr[0] "Min."
+msgstr[1] "Min."
msgid "Time|s"
-msgstr "s"
+msgstr "Sek."
msgid "Total Time"
msgstr "Gesamtzeit"
msgid "Total test time for all commits/merges"
-msgstr "Gesamte Testlaufzeit für alle Commits/Merges"
+msgstr "Gesamte Testzeit für alle Commits/Merges"
msgid "Unstar"
-msgstr ""
+msgstr "Entfavorisieren"
msgid "Upload New File"
-msgstr ""
+msgstr "Eine Neue Datei hochladen"
msgid "Upload file"
-msgstr ""
+msgstr "Eine Datei hochladen"
msgid "UploadLink|click to upload"
-msgstr ""
+msgstr "Zum Upload klicken"
msgid "Use the following registration token during setup:"
-msgstr ""
+msgstr "Benutze den folgenden Registrierungstoken während des Setups:"
msgid "Use your global notification setting"
-msgstr ""
+msgstr "Benutze Deine globalen Benachrichtigungseinstellungen"
msgid "View open merge request"
-msgstr ""
+msgstr "Zeige offene Merge Requests."
msgid "VisibilityLevel|Internal"
-msgstr ""
+msgstr "Intern"
msgid "VisibilityLevel|Private"
-msgstr ""
+msgstr "Privat"
msgid "VisibilityLevel|Public"
-msgstr ""
+msgstr "Öffentlich"
msgid "VisibilityLevel|Unknown"
-msgstr ""
+msgstr "Unbekannt"
msgid "Want to see the data? Please ask an administrator for access."
-msgstr "Um diese Daten einsehen zu können, wenden Sie sich bitte an Ihren Administrator."
+msgstr "Du möchtest diese Daten sehen? Bitte frage einen Administrator nach dem Zugang."
msgid "We don't have enough data to show this stage."
msgstr "Es liegen nicht genügend Daten vor, um diese Phase anzuzeigen."
-msgid "Withdraw Access Request"
+msgid "Wiki"
msgstr ""
+msgid "Withdraw Access Request"
+msgstr "Zugriffsanfrage widerrufen"
+
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
-msgstr ""
+msgstr "Du bist dabei %{group_name} zu entfernen. Entfernte Gruppen können NICHT wiederhergestellt werden! Bist Du dir WIRKLICH sicher?"
msgid "You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
-msgstr ""
+msgstr "Du bist dabei %{project_name_with_namespace} zu entfernen. Entfernte Projekte können NICHT wiederhergestellt werden! Bist Du dir WIRKLICH sicher?"
msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
-msgstr ""
+msgstr "Du bist dabei, die Beziehung des Ablegers zum Ursprungsprojekt %{forked_from_project}, zu entfernen. Bist Du dir WIRKLICH sicher?"
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
-msgstr ""
+msgstr "Du bist dabei %{project_name_with_namespace} einem andere Besitzer zu übergeben. Bist Du dir WIRKLICH sicher?"
msgid "You can only add files when you are on a branch"
-msgstr ""
+msgstr "Du kannst Dateien nur hinzufügen, wenn Du dich auf einem Branch befindest."
msgid "You have reached your project limit"
-msgstr ""
+msgstr "Du hast die Projektbegrenzung erreicht."
msgid "You must sign in to star a project"
-msgstr ""
+msgstr "Du musst angemeldet sein, um ein Projekt zu favorisieren."
msgid "You need permission."
-msgstr "Sie benötigen Zugriffsrechte."
+msgstr "Du brauchst eine Genehmigung."
msgid "You will not get any notifications via email"
-msgstr ""
+msgstr "Du wirst keine Benachrichtigungen per E-Mail erhalten."
msgid "You will only receive notifications for the events you choose"
-msgstr ""
+msgstr "Du wirst nur Benachrichtigungen für, von Dir ausgewählte, Ereignisse erhalten."
msgid "You will only receive notifications for threads you have participated in"
-msgstr ""
+msgstr "Du wirst nur Benachrichtigungen für Unterhaltungen, an denen Du teilgenommen hast, erhalten."
msgid "You will receive notifications for any activity"
-msgstr ""
+msgstr "Du wirst bei jeder Aktivität Benachrichtigungen erhalten."
msgid "You will receive notifications only for comments in which you were @mentioned"
-msgstr ""
+msgstr "Du wirst nur Benachrichtigungen für Kommentare erhalten, in denen du @erwähnt wurdest."
msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
-msgstr ""
+msgstr "Du kannst erst mittels '%{protocol}' übertragen (push) oder abrufen (pull), nachdem Du für dein Konto '%{set_password_link}'."
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
-msgstr ""
+msgstr "Du kannst erst mittels SSH übertragen (push) oder abrufen (pull), nachdem Du Deinem Konto '%{add_ssh_key_link}'."
msgid "Your name"
-msgstr ""
+msgstr "Dein Name"
msgid "day"
msgid_plural "days"
@@ -1276,12 +1444,13 @@ msgstr[0] "Tag"
msgstr[1] "Tage"
msgid "new merge request"
-msgstr ""
+msgstr "Neuer Merge Request"
msgid "notification emails"
-msgstr ""
+msgstr "Benachrichtungsemail"
msgid "parent"
msgid_plural "parents"
-msgstr[0] ""
-msgstr[1] "" \ No newline at end of file
+msgstr[0] "Vorgänger"
+msgstr[1] "Vorgänger"
+
diff --git a/locale/en/gitlab.po b/locale/en/gitlab.po
index 84232be601e..0ac591d4927 100644
--- a/locale/en/gitlab.po
+++ b/locale/en/gitlab.po
@@ -82,9 +82,6 @@ msgstr ""
msgid "Add new directory"
msgstr ""
-msgid "All"
-msgstr ""
-
msgid "Archived project! Repository is read-only"
msgstr ""
@@ -225,9 +222,6 @@ msgstr ""
msgid "CiStatus|running"
msgstr ""
-msgid "Comments"
-msgstr ""
-
msgid "Commit"
msgid_plural "Commits"
msgstr[0] ""
@@ -400,24 +394,6 @@ msgstr ""
msgid "Edit Pipeline Schedule %{id}"
msgstr ""
-msgid "EventFilterBy|Filter by all"
-msgstr ""
-
-msgid "EventFilterBy|Filter by comments"
-msgstr ""
-
-msgid "EventFilterBy|Filter by issue events"
-msgstr ""
-
-msgid "EventFilterBy|Filter by merge events"
-msgstr ""
-
-msgid "EventFilterBy|Filter by push events"
-msgstr ""
-
-msgid "EventFilterBy|Filter by team"
-msgstr ""
-
msgid "Every day (at 4:00am)"
msgstr ""
@@ -513,9 +489,6 @@ msgstr ""
msgid "Introducing Cycle Analytics"
msgstr ""
-msgid "Issue events"
-msgstr ""
-
msgid "Jobs for last month"
msgstr ""
@@ -545,12 +518,6 @@ msgstr ""
msgid "Last commit"
msgstr ""
-msgid "LastPushEvent|You pushed to"
-msgstr ""
-
-msgid "LastPushEvent|at"
-msgstr ""
-
msgid "Learn more in the"
msgstr ""
@@ -571,9 +538,6 @@ msgstr[1] ""
msgid "Median"
msgstr ""
-msgid "Merge events"
-msgstr ""
-
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr ""
@@ -777,9 +741,6 @@ msgstr ""
msgid "Pipeline|with stages"
msgstr ""
-msgid "Project"
-msgstr ""
-
msgid "Project '%{project_name}' queued for deletion."
msgstr ""
@@ -813,9 +774,6 @@ msgstr ""
msgid "Project home"
msgstr ""
-msgid "ProjectActivityRSS|Subscribe"
-msgstr ""
-
msgid "ProjectFeature|Disabled"
msgstr ""
@@ -837,9 +795,6 @@ msgstr ""
msgid "ProjectNetworkGraph|Graph"
msgstr ""
-msgid "Push events"
-msgstr ""
-
msgid "Read more"
msgstr ""
@@ -970,9 +925,6 @@ msgstr ""
msgid "Target Branch"
msgstr ""
-msgid "Team"
-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 ""
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index 4617de25a7c..8f25c893ecd 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:53-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:21-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Esperanto\n"
"Language: eo_UY\n"
@@ -57,9 +57,18 @@ msgstr "Aro da diagramoj pri la seninterrompa integrado"
msgid "About auto deploy"
msgstr "Pri la aÅ­tomata disponigado"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "Aktiva"
@@ -84,6 +93,12 @@ msgstr "Aldoni novan dosierujon"
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Arkivita projekto! La deponejo permesas nur legadon"
@@ -105,6 +120,63 @@ msgstr ""
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Alkroĉu dosieron per Åovmetado aÅ­ %{upload_link}"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Branĉo"
@@ -137,6 +209,9 @@ msgstr "Elekti dosierojn"
msgid "ByAuthor|by"
msgstr "de"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "Agordoj de seninterrompa integrado"
@@ -164,6 +239,9 @@ msgstr "Listo de ÅanÄoj"
msgid "Charts"
msgstr "Diagramoj"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Precize elekti ĉi tiun kunmetadon"
@@ -259,12 +337,18 @@ msgstr "Enmetita de"
msgid "Compare"
msgstr "Kompari"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "Gvidlinioj por kontribuado"
msgid "Contributors"
msgstr "Kontribuantoj"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "Kopii la adreson en la kopibufron"
@@ -351,6 +435,9 @@ msgid_plural "Deploys"
msgstr[0] "Disponigado"
msgstr[1] "Disponigadoj"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "Priskribo"
@@ -399,6 +486,9 @@ msgstr "Redakti"
msgid "Edit Pipeline Schedule %{id}"
msgstr "Redakti ĉenstablan planon %{id}"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -464,6 +554,12 @@ msgstr "De la kreado de la problemo Äis la disponigado en la publika versio"
msgid "From merge request merge until deploy to production"
msgstr "De la kunfandado de la peto pri kunfando Äis la disponigado en la publika versio"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -476,6 +572,9 @@ msgstr "Al via disbranĉigo"
msgid "GoToYourFork|Fork"
msgstr "Disbranĉigo"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -497,6 +596,9 @@ msgstr ""
msgid "Home"
msgstr "Hejmo"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "La refreÅigo komenciÄis sukcese"
@@ -515,14 +617,8 @@ msgstr "Ni prezentas al vi la ciklan analizon"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "Taskoj po la lasta monato"
-
-msgid "Jobs for last week"
-msgstr "Taskoj po la lasta semajno"
-
-msgid "Jobs for last year"
-msgstr "Taskoj po la lasta jaro"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "MalÅaltita"
@@ -530,6 +626,9 @@ msgstr "MalÅaltita"
msgid "LFSStatus|Enabled"
msgstr "Åœaltita"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "La lasta %d tago"
@@ -562,20 +661,38 @@ msgstr "Forlasi la grupon"
msgid "Leave project"
msgstr "Forlasi la projekton"
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "Limigita al montrado de ne pli ol %d evento"
msgstr[1] "Limigita al montrado de ne pli ol %d eventoj"
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr "Mediano"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "aldonos SSH-Ålosilon"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -677,6 +794,9 @@ msgstr "Partoprenado"
msgid "NotificationLevel|Watch"
msgstr "Rigardado"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtrilo"
@@ -686,9 +806,15 @@ msgstr "Malfermita"
msgid "Options"
msgstr "Opcioj"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "Posedanto"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "Ĉenstablo"
@@ -701,6 +827,9 @@ msgstr "Ĉenstabla plano"
msgid "Pipeline Schedules"
msgstr "Ĉenstablaj planoj"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "Malsukcesaj:"
@@ -764,6 +893,15 @@ msgstr "Ĉenstabloj"
msgid "Pipelines charts"
msgstr "Ĉenstablaj diagramoj"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "ĉiuj"
@@ -776,6 +914,12 @@ msgstr "kun etapo"
msgid "Pipeline|with stages"
msgstr "kun etapoj"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -812,6 +956,9 @@ msgstr "La elporto de la projekto komenciÄis. Vi ricevos ligilon per retpoÅto
msgid "Project home"
msgstr "Hejmo de la projekto"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -836,6 +983,9 @@ msgstr "Etapo"
msgid "ProjectNetworkGraph|Graph"
msgstr "Grafeo"
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -896,6 +1046,9 @@ msgstr "Malfari ĉi tiun enmetadon"
msgid "Revert this merge request"
msgstr "Malfari ĉi tiun peton pri kunfando"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "Konservi ĉenstablan planon"
@@ -920,6 +1073,9 @@ msgstr ""
msgid "Select target branch"
msgstr "Elektu celan branĉon"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Kreu pasvorton por via konto por ebligi al vi eltiri kaj alpuÅi per %{protocol}."
@@ -935,14 +1091,23 @@ msgstr "Agordi aÅ­tomatan disponigadon"
msgid "SetPasswordToCloneLink|set a password"
msgstr "kreos pasvorton"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Estas montrata %d evento"
msgstr[1] "Estas montrataj %d eventoj"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "Kodo"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1219,6 +1384,9 @@ msgstr "Ĉu vi volas vidi la datenojn? Bonvolu peti atingeblon de administranto.
msgid "We don't have enough data to show this stage."
msgstr "Ne estas sufiĉe da datenoj por montri ĉi tiun etapon."
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Nuligi la peton pri atingeblo"
@@ -1284,4 +1452,5 @@ msgstr "sciigoj per retpoÅto"
msgid "parent"
msgid_plural "parents"
msgstr[0] "patro"
-msgstr[1] "patroj" \ No newline at end of file
+msgstr[1] "patroj"
+
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index 8158bd275bd..eee720d5ba2 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:37-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Spanish\n"
"Language: es_ES\n"
@@ -57,9 +57,18 @@ msgstr "Una colección de gráficos sobre Integración Continua"
msgid "About auto deploy"
msgstr "Acerca del auto despliegue"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "Activo"
@@ -84,6 +93,12 @@ msgstr "Agregar nuevo directorio"
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "¡Proyecto archivado! El repositorio es de solo lectura"
@@ -105,6 +120,63 @@ 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"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Rama"
@@ -137,6 +209,9 @@ msgstr "Examinar archivos"
msgid "ByAuthor|by"
msgstr "por"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "Configuración de CI"
@@ -164,6 +239,9 @@ msgstr ""
msgid "Charts"
msgstr "Gráficos"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Escoger este cambio"
@@ -259,12 +337,18 @@ msgstr "Enviado por"
msgid "Compare"
msgstr "Comparar"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "Guía de contribución"
msgid "Contributors"
msgstr "Contribuidores"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "Copiar URL al portapapeles"
@@ -351,6 +435,9 @@ msgid_plural "Deploys"
msgstr[0] "Despliegue"
msgstr[1] "Despliegues"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "Descripción"
@@ -399,6 +486,9 @@ msgstr "Editar"
msgid "Edit Pipeline Schedule %{id}"
msgstr "Editar Programación del Pipeline %{id}"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -464,6 +554,12 @@ msgstr "Desde la creación de la incidencia hasta el despliegue a producción"
msgid "From merge request merge until deploy to production"
msgstr "Desde la integración de la solicitud de fusión hasta el despliegue a producción"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -476,6 +572,9 @@ msgstr "Ir a tu bifurcación"
msgid "GoToYourFork|Fork"
msgstr "Bifurcación"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -497,6 +596,9 @@ msgstr ""
msgid "Home"
msgstr "Inicio"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "Servicio de limpieza iniciado con éxito"
@@ -515,14 +617,8 @@ msgstr "Introducción a Cycle Analytics"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "Trabajos del mes pasado"
-
-msgid "Jobs for last week"
-msgstr "Trabajos de la semana pasada"
-
-msgid "Jobs for last year"
-msgstr "Trabajos del año pasado"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "Deshabilitado"
@@ -530,6 +626,9 @@ msgstr "Deshabilitado"
msgid "LFSStatus|Enabled"
msgstr "Habilitado"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "Último %d día"
@@ -562,20 +661,38 @@ msgstr "Abandonar grupo"
msgid "Leave project"
msgstr "Abandonar proyecto"
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "Limitado a mostrar máximo %d evento"
msgstr[1] "Limitado a mostrar máximo %d eventos"
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr "Mediana"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "agregar una clave SSH"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -677,6 +794,9 @@ msgstr "Participación"
msgid "NotificationLevel|Watch"
msgstr "Vigilancia"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtrar"
@@ -686,9 +806,15 @@ msgstr "Abierto"
msgid "Options"
msgstr "Opciones"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "Propietario"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr ""
@@ -701,6 +827,9 @@ msgstr "Programación del Pipeline"
msgid "Pipeline Schedules"
msgstr "Programaciones de los Pipelines"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "Fallidos:"
@@ -764,6 +893,15 @@ msgstr ""
msgid "Pipelines charts"
msgstr "Gráficos de los pipelines"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "todos"
@@ -776,6 +914,12 @@ msgstr "con etapa"
msgid "Pipeline|with stages"
msgstr "con etapas"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -812,6 +956,9 @@ msgstr "Se inició la exportación del proyecto. Se enviará un enlace de descar
msgid "Project home"
msgstr "Inicio del proyecto"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -836,6 +983,9 @@ msgstr "Etapa"
msgid "ProjectNetworkGraph|Graph"
msgstr "Historial gráfico"
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -896,6 +1046,9 @@ msgstr "Revertir este cambio"
msgid "Revert this merge request"
msgstr "Revertir esta solicitud de fusión"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "Guardar programación del pipeline"
@@ -920,6 +1073,9 @@ msgstr ""
msgid "Select target branch"
msgstr "Selecciona una rama de destino"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Establezca una contraseña en su cuenta para actualizar o enviar a través de %{protocol}."
@@ -935,14 +1091,23 @@ msgstr "Configurar auto despliegue"
msgid "SetPasswordToCloneLink|set a password"
msgstr "establecer una contraseña"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Mostrando %d evento"
msgstr[1] "Mostrando %d eventos"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "Código fuente"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1219,6 +1384,9 @@ msgstr "¿Quieres ver los datos? Por favor pide acceso al administrador."
msgid "We don't have enough data to show this stage."
msgstr "No hay suficientes datos para mostrar en esta etapa."
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Retirar Solicitud de Acceso"
@@ -1284,4 +1452,5 @@ msgstr "correos electrónicos de notificación"
msgid "parent"
msgid_plural "parents"
msgstr[0] "padre"
-msgstr[1] "padres" \ No newline at end of file
+msgstr[1] "padres"
+
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index 3daff3f5c19..43e66d8dea4 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:53-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: French\n"
"Language: fr_FR\n"
@@ -57,9 +57,18 @@ msgstr "Un ensemble de graphiques concernant l’Intégration Continue (CI)"
msgid "About auto deploy"
msgstr "A propos de l'auto-déploiement"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "Actif"
@@ -84,6 +93,12 @@ msgstr "Ajouter un nouveau dossier"
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Projet archivé ! Le dépôt est en lecture seule"
@@ -105,6 +120,63 @@ 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"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] ""
@@ -137,6 +209,9 @@ msgstr "Parcourir les fichiers"
msgid "ByAuthor|by"
msgstr "par"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "Configuration de l'intégration continue (CI)"
@@ -164,6 +239,9 @@ msgstr "Journal des modifications"
msgid "Charts"
msgstr "Graphiques"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Sélectionner cette validation"
@@ -259,12 +337,18 @@ msgstr "Validé par"
msgid "Compare"
msgstr "Comparer"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "Guilde de contribution"
msgid "Contributors"
msgstr "Contributeurs"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "Copier l'URL dans le presse-papier"
@@ -351,6 +435,9 @@ msgid_plural "Deploys"
msgstr[0] "Déploiement"
msgstr[1] "Déploiements"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr ""
@@ -399,6 +486,9 @@ msgstr "Éditer"
msgid "Edit Pipeline Schedule %{id}"
msgstr "Éditer le pipeline programmé %{id}"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -464,6 +554,12 @@ msgstr "Depuis la création de l'incident jusqu'au déploiement en production"
msgid "From merge request merge until deploy to production"
msgstr "Depuis la fusion de la demande de fusion jusqu'au déploiement en production"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -476,6 +572,9 @@ msgstr "Aller à votre fourche"
msgid "GoToYourFork|Fork"
msgstr "Fourche"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -497,6 +596,9 @@ msgstr ""
msgid "Home"
msgstr "Accueil"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "Maintenance démarrée avec succès"
@@ -515,14 +617,8 @@ msgstr "Introduction à l'analyseur de cycle"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "Tâches pour le mois dernier"
-
-msgid "Jobs for last week"
-msgstr "Tâches pour la semaine dernière"
-
-msgid "Jobs for last year"
-msgstr "Tâches pour l'année dernière"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "Désactivé"
@@ -530,6 +626,9 @@ msgstr "Désactivé"
msgid "LFSStatus|Enabled"
msgstr "Activé"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "Le dernier %d jour"
@@ -562,20 +661,38 @@ msgstr "Quitter le groupe"
msgid "Leave project"
msgstr "Quitter le projet"
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "Limiter l'affichage au plus à %d évènement"
msgstr[1] "Limiter l'affichage au plus à %d évènements"
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr "Médian"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "ajouter une clef SSH"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -677,6 +794,9 @@ msgstr "Participation"
msgid "NotificationLevel|Watch"
msgstr "Surveillé"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtre"
@@ -686,9 +806,15 @@ msgstr "Ouvert"
msgid "Options"
msgstr ""
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "Propriétaire"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr ""
@@ -701,6 +827,9 @@ msgstr "Programmation de pipeline"
msgid "Pipeline Schedules"
msgstr "Programmations de pipeline"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "Échecs : "
@@ -764,6 +893,15 @@ msgstr ""
msgid "Pipelines charts"
msgstr "Graphique des pipelines"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "Tous"
@@ -776,6 +914,12 @@ msgstr "avec l'étape"
msgid "Pipeline|with stages"
msgstr "avec les étapes"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -812,6 +956,9 @@ msgstr "L'export du projet a débuté. Un lien de téléchargement sera envoyé
msgid "Project home"
msgstr "Accueil du projet"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -836,6 +983,9 @@ msgstr "Étape"
msgid "ProjectNetworkGraph|Graph"
msgstr "Graphique "
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -896,6 +1046,9 @@ msgstr "Annuler cette validation"
msgid "Revert this merge request"
msgstr "Annuler cette demande de fusion"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "Sauvegarder le pipeline programmé"
@@ -920,6 +1073,9 @@ msgstr ""
msgid "Select target branch"
msgstr "Sélectionnez une branche cible"
+msgid "Service Templates"
+msgstr ""
+
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}."
@@ -935,14 +1091,23 @@ msgstr "Mettre en place l’auto-déploiement"
msgid "SetPasswordToCloneLink|set a password"
msgstr "définir un mot de passe"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Affichage de %d évènement"
msgstr[1] "Affichage de %d évènements"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "Code source"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1219,6 +1384,9 @@ msgstr "Vous voulez voir les données ? Merci de contacter un administrateur pou
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 ""
+
msgid "Withdraw Access Request"
msgstr "Retirer la demande d'accès"
@@ -1284,4 +1452,5 @@ msgstr "courriels de notification"
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
-msgstr[1] "" \ No newline at end of file
+msgstr[1] ""
+
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 97bc3d80642..e5cf2aeb513 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-08-31 17:34+0530\n"
-"PO-Revision-Date: 2017-08-31 17:34+0530\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 08:32+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
@@ -58,9 +58,18 @@ msgstr ""
msgid "About auto deploy"
msgstr ""
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr ""
@@ -85,6 +94,12 @@ msgstr ""
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr ""
@@ -106,6 +121,63 @@ msgstr ""
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr ""
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] ""
@@ -138,6 +210,9 @@ msgstr ""
msgid "ByAuthor|by"
msgstr ""
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr ""
@@ -165,6 +240,9 @@ msgstr ""
msgid "Charts"
msgstr ""
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr ""
@@ -260,12 +338,18 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr ""
msgid "Contributors"
msgstr ""
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr ""
@@ -352,6 +436,9 @@ msgid_plural "Deploys"
msgstr[0] ""
msgstr[1] ""
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr ""
@@ -400,6 +487,9 @@ msgstr ""
msgid "Edit Pipeline Schedule %{id}"
msgstr ""
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -427,9 +517,6 @@ msgstr ""
msgid "Every week (Sundays at 4:00am)"
msgstr ""
-msgid "Explore projects"
-msgstr ""
-
msgid "Failed to change the owner"
msgstr ""
@@ -468,6 +555,12 @@ msgstr ""
msgid "From merge request merge until deploy to production"
msgstr ""
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -480,6 +573,9 @@ msgstr ""
msgid "GoToYourFork|Fork"
msgstr ""
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -501,6 +597,9 @@ msgstr ""
msgid "Home"
msgstr ""
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr ""
@@ -519,12 +618,18 @@ msgstr ""
msgid "Issue events"
msgstr ""
+msgid "Issues"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr ""
msgid "LFSStatus|Enabled"
msgstr ""
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
@@ -557,20 +662,38 @@ msgstr ""
msgid "Leave project"
msgstr ""
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] ""
msgstr[1] ""
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr ""
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr ""
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -672,6 +795,9 @@ msgstr ""
msgid "NotificationLevel|Watch"
msgstr ""
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr ""
@@ -681,9 +807,15 @@ msgstr ""
msgid "Options"
msgstr ""
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr ""
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr ""
@@ -696,6 +828,9 @@ msgstr ""
msgid "Pipeline Schedules"
msgstr ""
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr ""
@@ -780,6 +915,12 @@ msgstr ""
msgid "Pipeline|with stages"
msgstr ""
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -816,6 +957,9 @@ msgstr ""
msgid "Project home"
msgstr ""
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -840,25 +984,7 @@ msgstr ""
msgid "ProjectNetworkGraph|Graph"
msgstr ""
-msgid "ProjectsDropdown|Frequently visited"
-msgstr ""
-
-msgid "ProjectsDropdown|Loading projects"
-msgstr ""
-
-msgid "ProjectsDropdown|No projects matched your query"
-msgstr ""
-
-msgid "ProjectsDropdown|Projects you visit often will appear here"
-msgstr ""
-
-msgid "ProjectsDropdown|Search projects"
-msgstr ""
-
-msgid "ProjectsDropdown|Something went wrong on our end."
-msgstr ""
-
-msgid "ProjectsDropdown|This feature requires browser localStorage support"
+msgid "Push Rules"
msgstr ""
msgid "Push events"
@@ -921,6 +1047,9 @@ msgstr ""
msgid "Revert this merge request"
msgstr ""
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr ""
@@ -945,6 +1074,9 @@ msgstr ""
msgid "Select target branch"
msgstr ""
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr ""
@@ -960,21 +1092,27 @@ msgstr ""
msgid "SetPasswordToCloneLink|set a password"
msgstr ""
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr ""
-msgid "Specify the following URL during the Runner setup:"
+msgid "Spam Logs"
msgstr ""
-msgid "StarProject|Star"
+msgid "Specify the following URL during the Runner setup:"
msgstr ""
-msgid "Starred projects"
+msgid "StarProject|Star"
msgstr ""
msgid "Start a %{new_merge_request} with these changes"
@@ -1247,6 +1385,9 @@ msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -1298,9 +1439,6 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your projects"
-msgstr ""
-
msgid "day"
msgid_plural "days"
msgstr[0] ""
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index 7b8bea46e26..46b3e12f97c 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 10:25-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@@ -57,9 +57,18 @@ msgstr "Un insieme di grafici riguardo la Continuous Integration"
msgid "About auto deploy"
msgstr "Riguardo il rilascio automatico"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "Attivo"
@@ -84,6 +93,12 @@ msgstr "Aggiungi una directory (cartella)"
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Progetto archiviato! La Repository è sola-lettura"
@@ -105,6 +120,63 @@ 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"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] ""
@@ -137,6 +209,9 @@ msgstr "Guarda i files"
msgid "ByAuthor|by"
msgstr "per"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "Configurazione CI (Integrazione Continua)"
@@ -164,6 +239,9 @@ msgstr ""
msgid "Charts"
msgstr "Grafici"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr ""
@@ -259,12 +337,18 @@ msgstr "Committato da "
msgid "Compare"
msgstr "Confronta"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "Guida per contribuire"
msgid "Contributors"
msgstr "Collaboratori"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "Copia URL negli appunti"
@@ -351,6 +435,9 @@ msgid_plural "Deploys"
msgstr[0] "Rilascio"
msgstr[1] "Rilasci"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "Descrizione"
@@ -399,6 +486,9 @@ msgstr "Modifica"
msgid "Edit Pipeline Schedule %{id}"
msgstr "Cambia programmazione della pipeline %{id}"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -464,6 +554,12 @@ msgstr "Dalla creazione di un issue fino al rilascio in produzione"
msgid "From merge request merge until deploy to production"
msgstr "Dalla richiesta di merge fino effettua il merge fino al rilascio in produzione"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -476,6 +572,9 @@ msgstr "Vai il tuo fork"
msgid "GoToYourFork|Fork"
msgstr "Fork"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -497,6 +596,9 @@ msgstr ""
msgid "Home"
msgstr ""
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "Housekeeping iniziato con successo"
@@ -515,14 +617,8 @@ msgstr "Introduzione delle Analisi Cicliche"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "Jobs dell'ultimo mese"
-
-msgid "Jobs for last week"
-msgstr "Jobs dell'ultima settimana"
-
-msgid "Jobs for last year"
-msgstr "Jobs dell'ultimo anno"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "Disabilitato"
@@ -530,6 +626,9 @@ msgstr "Disabilitato"
msgid "LFSStatus|Enabled"
msgstr "Abilitato"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "L'ultimo %d giorno"
@@ -562,20 +661,38 @@ msgstr "Abbandona il gruppo"
msgid "Leave project"
msgstr "Abbandona il progetto"
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "Limita visualizzazione %d d'evento"
msgstr[1] "Limita visualizzazione %d di eventi"
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr "Mediano"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "aggiungi una chiave SSH"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -677,6 +794,9 @@ msgstr "Partecipa"
msgid "NotificationLevel|Watch"
msgstr "Osserva"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtra"
@@ -686,9 +806,15 @@ msgstr "Aperto"
msgid "Options"
msgstr "Opzioni"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr ""
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr ""
@@ -701,6 +827,9 @@ msgstr "Pianificazione Pipeline"
msgid "Pipeline Schedules"
msgstr "Pianificazione multipla Pipeline"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "Fallita:"
@@ -764,6 +893,15 @@ msgstr "Pipeline"
msgid "Pipelines charts"
msgstr "Grafici pipeline"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "tutto"
@@ -776,6 +914,12 @@ msgstr "con stadio"
msgid "Pipeline|with stages"
msgstr "con più stadi"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -812,6 +956,9 @@ msgstr "Esportazione del progetto iniziata. Un link di download sarà inviato vi
msgid "Project home"
msgstr "Home di progetto"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -836,6 +983,9 @@ msgstr "Stadio"
msgid "ProjectNetworkGraph|Graph"
msgstr "Grafico"
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -896,6 +1046,9 @@ msgstr "Ripristina questo commit"
msgid "Revert this merge request"
msgstr "Ripristina questa richiesta di merge"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "Salva pianificazione pipeline"
@@ -920,6 +1073,9 @@ msgstr ""
msgid "Select target branch"
msgstr "Seleziona una branch di destinazione"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Establezca una contraseña en su cuenta para actualizar o enviar a través de %{protocol}."
@@ -935,14 +1091,23 @@ msgstr "Configura il rilascio automatico"
msgid "SetPasswordToCloneLink|set a password"
msgstr "imposta una password"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Visualizza %d evento"
msgstr[1] "Visualizza %d eventi"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "Codice Sorgente"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1219,6 +1384,9 @@ msgstr "Vuoi visualizzare i dati? Richiedi l'accesso ad un amministratore, grazi
msgid "We don't have enough data to show this stage."
msgstr "Non ci sono sufficienti dati da mostrare su questo stadio"
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Ritira richiesta d'accesso"
@@ -1284,4 +1452,5 @@ msgstr "Notifiche via email"
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
-msgstr[1] "" \ No newline at end of file
+msgstr[1] ""
+
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index 670ac2d9684..bc25b69c80a 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 10:14-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Japanese\n"
"Language: ja_JP\n"
@@ -53,9 +53,18 @@ msgstr "CIã«ã¤ã„ã¦ã®ã‚°ãƒ©ãƒ•"
msgid "About auto deploy"
msgstr "自動デプロイã«ã¤ã„ã¦"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "有効"
@@ -80,6 +89,12 @@ msgstr "æ–°è¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’追加"
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "アーカイブ済ã¿ãƒ—ロジェクトï¼ï¼ˆãƒ¬ãƒã‚¸ãƒˆãƒªãƒ¼ã¯èª­ã¿å–り専用ã§ã™ï¼‰"
@@ -101,6 +116,63 @@ msgstr ""
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "ドラッグ&ドロップã¾ãŸã¯ %{upload_link} ã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’添付"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "ブランãƒ"
@@ -132,6 +204,9 @@ msgstr "ファイルを表示"
msgid "ByAuthor|by"
msgstr "作者"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "CI 設定"
@@ -159,6 +234,9 @@ msgstr "変更履歴"
msgid "Charts"
msgstr "ãƒãƒ£ãƒ¼ãƒˆ"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "ã“ã®ã‚³ãƒŸãƒƒãƒˆã‚’ãƒã‚§ãƒªãƒ¼ãƒ”ック"
@@ -253,12 +331,18 @@ msgstr "コミット担当者: "
msgid "Compare"
msgstr "比較"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "貢献者å‘ã‘ガイド"
msgid "Contributors"
msgstr "貢献者"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "クリップボードã«URLをコピー"
@@ -344,6 +428,9 @@ msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] "デプロイ"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "説明"
@@ -392,6 +479,9 @@ msgstr "編集"
msgid "Edit Pipeline Schedule %{id}"
msgstr "パイプラインスケジュール %{id} を編集"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -456,6 +546,12 @@ msgstr "課題ãŒç™»éŒ²ã•ã‚Œã¦ã‹ã‚‰ãƒ—ロダクションã«ãƒ‡ãƒ—ロイã•ã‚Œ
msgid "From merge request merge until deploy to production"
msgstr "マージリクエストãŒãƒžãƒ¼ã‚¸ã•ã‚Œã¦ã‹ã‚‰ãƒ—ロダクションã«ãƒ‡ãƒ—ロイã•ã‚Œã‚‹ã¾ã§"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -468,6 +564,9 @@ msgstr "自分ã®ãƒ•ã‚©ãƒ¼ã‚¯ã¸ç§»å‹•"
msgid "GoToYourFork|Fork"
msgstr "フォーク"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -489,6 +588,9 @@ msgstr ""
msgid "Home"
msgstr "ホーム"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "ãƒã‚¦ã‚¹ã‚­ãƒ¼ãƒ”ングã¯æ­£å¸¸ã«èµ·å‹•ã—ã¾ã—ãŸã€‚"
@@ -507,14 +609,8 @@ msgstr "サイクル分æžã®ã”紹介"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "先月ã®ã‚¸ãƒ§ãƒ–"
-
-msgid "Jobs for last week"
-msgstr "先週ã®ã‚¸ãƒ§ãƒ–"
-
-msgid "Jobs for last year"
-msgstr "昨年ã®ã‚¸ãƒ§ãƒ–"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "無効"
@@ -522,6 +618,9 @@ msgstr "無効"
msgid "LFSStatus|Enabled"
msgstr "有効"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "éŽåŽ»%d日間"
@@ -553,19 +652,37 @@ msgstr "グループを離脱"
msgid "Leave project"
msgstr "プロジェクトを離脱"
+msgid "License"
+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 ""
+
msgid "Median"
msgstr "中央値"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "SSH éµã‚’追加"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -666,6 +783,9 @@ msgstr "å‚加"
msgid "NotificationLevel|Watch"
msgstr "ã™ã¹ã¦é€šçŸ¥"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "フィルター"
@@ -675,9 +795,15 @@ msgstr "オープンã•ã‚ŒãŸã®ã¯"
msgid "Options"
msgstr "オプション"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "オーナー"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "パイプライン"
@@ -690,6 +816,9 @@ msgstr "パイプラインスケジュール"
msgid "Pipeline Schedules"
msgstr "パイプラインスケジュール"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "失敗:"
@@ -753,6 +882,15 @@ msgstr "パイプライン"
msgid "Pipelines charts"
msgstr "パイプラインãƒãƒ£ãƒ¼ãƒˆ"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "全件"
@@ -765,6 +903,12 @@ msgstr "ステージã‚ã‚Š"
msgid "Pipeline|with stages"
msgstr "ステージã‚ã‚Š"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -801,6 +945,9 @@ msgstr "プロジェクトã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã‚’開始ã—ã¾ã—ãŸã€‚ダウン
msgid "Project home"
msgstr "プロジェクトホーム"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -825,6 +972,9 @@ msgstr "ステージ"
msgid "ProjectNetworkGraph|Graph"
msgstr "ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚°ãƒ©ãƒ•"
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -885,6 +1035,9 @@ msgstr "ã“ã®ã‚³ãƒŸãƒƒãƒˆã‚’リãƒãƒ¼ãƒˆ"
msgid "Revert this merge request"
msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’リãƒãƒ¼ãƒˆ"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "パイプラインスケジュールをä¿å­˜"
@@ -909,6 +1062,9 @@ msgstr ""
msgid "Select target branch"
msgstr "ターゲットブランãƒã‚’é¸æŠž"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "%{protocol} プロコトル経由ã§ãƒ—ルã€ãƒ—ッシュã™ã‚‹ãŸã‚ã«ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®ãƒ‘スワードを設定。"
@@ -924,13 +1080,22 @@ msgstr "自動デプロイを設定"
msgid "SetPasswordToCloneLink|set a password"
msgstr "パスワードを設定"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "%d ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’表示中"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "ソースコード"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1204,6 +1369,9 @@ msgstr "ã“ã®ãƒ‡ãƒ¼ã‚¿ã‚’å‚ç…§ã—ãŸã„ã§ã™ã‹ï¼Ÿã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã«ã¯ç®¡
msgid "We don't have enough data to show this stage."
msgstr "データä¸è¶³ã®ãŸã‚ã€ã“ã®ã‚¹ãƒ†ãƒ¼ã‚¸ã®è¡¨ç¤ºã¯ã§ãã¾ã›ã‚“。"
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "アクセスリクエストをå–り消ã™"
@@ -1267,4 +1435,5 @@ msgstr "メール通知"
msgid "parent"
msgid_plural "parents"
-msgstr[0] "親" \ No newline at end of file
+msgstr[0] "親"
+
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index df850115222..4baefdb9a3e 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 10:05-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Korean\n"
"Language: ko_KR\n"
@@ -28,20 +28,20 @@ msgid "%{commit_author_link} committed %{commit_timeago}"
msgstr "%{commit_timeago} ì— %{commit_author_link} ë‹˜ì´ ì»¤ë°‹í•˜ì˜€ìŠµë‹ˆë‹¤. "
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
-msgstr ""
+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] ""
msgid "(checkout the %{link} for information on how to install it)."
-msgstr ""
+msgstr "설치 ë°©ë²•ì— ëŒ€í•œ 정보를 얻기 위해 %{link} 를 ì²´í¬ì•„웃하세요."
msgid "1 pipeline"
msgid_plural "%d pipelines"
@@ -53,7 +53,16 @@ msgstr "지ì†ì ì¸ í†µí•©ì— ê´€í•œ 그래프 모ìŒ"
msgid "About auto deploy"
msgstr "ìžë™ ë°°í¬ ì •ë³´"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
+msgstr "오ë™ìž‘ì¤‘ì¸ ì €ìž¥ê³µê°„ì— ëŒ€í•œ ì ‘ê·¼ì´ ë³µêµ¬ ìž‘ì—…ì„ ìœ„í•´ 마운트할 수 있ë„ë¡ ìž„ì‹œë¡œ 허용ë˜ì—ˆìŠµë‹ˆë‹¤. 문제가 í•´ê²°ëœ í›„ 다시 ì ‘ê·¼ì„ í—ˆìš©í•  수 있게 저장공간 정보를 리셋 해주세요."
+
+msgid "Account"
msgstr ""
msgid "Active"
@@ -78,6 +87,12 @@ msgid "Add new directory"
msgstr "새 디렉토리 추가"
msgid "All"
+msgstr "ì „ì²´"
+
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
msgstr ""
msgid "Archived project! Repository is read-only"
@@ -87,20 +102,77 @@ msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "ì´ íŒŒì´í”„ë¼ì¸ ìŠ¤ì¼€ì¥´ì„ ì‚­ì œ 하시겠습니까?"
msgid "Are you sure you want to discard your changes?"
-msgstr ""
+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 ""
+msgstr "확실합니까?"
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "드래그 &amp; 드롭 ë˜ëŠ” %{upload_link}"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "브랜치"
@@ -132,6 +204,9 @@ msgstr "íŒŒì¼ ì°¾ì•„ë³´ê¸°"
msgid "ByAuthor|by"
msgstr "작성ìž"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "CI 설정"
@@ -159,6 +234,9 @@ msgstr "변경사항"
msgid "Charts"
msgstr "차트"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "ì´ ì»¤ë°‹ì„ Cherry-pick"
@@ -253,12 +331,18 @@ msgstr "커밋한 사용ìž"
msgid "Compare"
msgstr "비êµ"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "ê¸°ì—¬ì— ëŒ€í•œ 안내"
msgid "Contributors"
msgstr "기여해 주신 분들"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "URLì„ í´ë¦½ë³´ë“œì— 복사"
@@ -269,7 +353,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}ì„ (를) 통해 Pull 하거나 Push í•  ê°œì¸ ì•¡ì„¸ìŠ¤ 토í°ì„ 만드십시오."
@@ -344,17 +428,20 @@ msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] "ë°°í¬"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "설명"
msgid "Details"
-msgstr ""
+msgstr "ìƒì„¸"
msgid "Directory name"
msgstr "디렉토리 ì´ë¦„"
msgid "Discard changes"
-msgstr ""
+msgstr "변경 내용 취소"
msgid "Don't show again"
msgstr "다시 표시하지 ì•ŠìŒ"
@@ -392,23 +479,26 @@ msgstr "편집"
msgid "Edit Pipeline Schedule %{id}"
msgstr "파ì´í”„ë¼ì¸ 스케줄 편집 %{id}"
-msgid "EventFilterBy|Filter by all"
+msgid "Emails"
msgstr ""
+msgid "EventFilterBy|Filter by all"
+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ì‹œì—)"
@@ -456,39 +546,51 @@ msgstr "ì´ìŠˆ ìƒì„±ì—ì„œ 프로ë•ì…˜ ë°°í¬ê¹Œì§€"
msgid "From merge request merge until deploy to production"
msgstr "머지 리퀘스트 머지ì—ì„œ 프로ë•ì…˜ í™˜ê²½ì— ë°°í¬ê¹Œì§€"
-msgid "Git storage health information has been reset"
+msgid "GPG Keys"
msgstr ""
-msgid "GitLab Runner section"
+msgid "Geo Nodes"
msgstr ""
+msgid "Git storage health information has been reset"
+msgstr "git storage ìƒíƒœ ì •ë³´ê°€ 초기화ë˜ì—ˆìŠµë‹ˆë‹¤."
+
+msgid "GitLab Runner section"
+msgstr "GitLab Runner 섹션"
+
msgid "Go to your fork"
msgstr "ë‹¹ì‹ ì˜ í¬í¬ë¡œ ì´ë™í•˜ì„¸ìš”"
msgid "GoToYourFork|Fork"
msgstr "í¬í¬"
-msgid "Health Check"
+msgid "Group overview"
msgstr ""
+msgid "Health Check"
+msgstr "헬스 ì²´í¬"
+
msgid "Health information can be retrieved from the following endpoints. More information is available"
-msgstr ""
+msgstr "헬스 정보는 다ìŒì˜ 경로를 통해 조회할 수 있습니다. ë” ë§Žì€ ì •ë³´ë¥¼ ì´ìš©í•  수 있습니다."
msgid "HealthCheck|Access token is"
-msgstr ""
+msgstr "엑세스 토í°: "
msgid "HealthCheck|Healthy"
-msgstr ""
+msgstr "ê±´ê°•ë„"
msgid "HealthCheck|No Health Problems Detected"
-msgstr ""
+msgstr " 헬스 문제가 발견ë˜ì§€ 않았습니다."
msgid "HealthCheck|Unhealthy"
-msgstr ""
+msgstr "비정ìƒ"
msgid "Home"
msgstr "홈"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "Housekeepingì´ ì„±ê³µì ìœ¼ë¡œ 시작ë˜ì—ˆìŠµë‹ˆë‹¤"
@@ -496,7 +598,7 @@ msgid "Import repository"
msgstr "저장소 가져 오기"
msgid "Install a Runner compatible with GitLab CI"
-msgstr ""
+msgstr "GitLab CI 와 호환ë˜ëŠ” Runner 설치"
msgid "Interval Pattern"
msgstr "주기 패턴"
@@ -505,16 +607,10 @@ msgid "Introducing Cycle Analytics"
msgstr "Cycle Analytics 소개"
msgid "Issue events"
-msgstr ""
-
-msgid "Jobs for last month"
-msgstr "지난달 Jobs"
+msgstr "ì´ìŠˆ ì´ë²¤íŠ¸"
-msgid "Jobs for last week"
-msgstr "지난주 Jobs"
-
-msgid "Jobs for last year"
-msgstr "지난해 Jobs"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "Disabled"
@@ -522,6 +618,9 @@ msgstr "Disabled"
msgid "LFSStatus|Enabled"
msgstr "Enabled"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "최근 %d ì¼"
@@ -530,16 +629,16 @@ msgid "Last Pipeline"
msgstr "최근 파ì´í”„ë¼ì¸"
msgid "Last Update"
-msgstr "최근 ì—…ë°ì´íŠ¸:"
+msgstr "최근 ì—…ë°ì´íŠ¸"
msgid "Last commit"
msgstr "최근 커밋"
msgid "LastPushEvent|You pushed to"
-msgstr ""
+msgstr "푸쉬: "
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "at"
msgid "Learn more in the"
msgstr "ë” ìžì„¸ížˆ 알아보기"
@@ -553,22 +652,40 @@ msgstr "그룹 떠나기"
msgid "Leave project"
msgstr "프로ì íŠ¸ì—ì„œ 나가기"
+msgid "License"
+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 ""
+
msgid "Median"
msgstr "중앙값"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
+msgstr "머지 ì´ë²¤íŠ¸"
+
+msgid "Messages"
msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "SSH 키 추가"
-msgid "More information is available|here"
+msgid "Monitoring"
msgstr ""
+msgid "More information is available|here"
+msgstr "여기"
+
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] "새 ì´ìŠˆ"
@@ -649,7 +766,7 @@ msgid "NotificationEvent|Successful pipeline"
msgstr "성공ì ì¸ 파ì´í”„ë¼ì¸"
msgid "NotificationLevel|Custom"
-msgstr "커스텀"
+msgstr "ì‚¬ìš©ìž ì •ì˜"
msgid "NotificationLevel|Disabled"
msgstr "사용 안 함"
@@ -666,6 +783,9 @@ msgstr "참여"
msgid "NotificationLevel|Watch"
msgstr "Watch"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "í•„í„°"
@@ -675,9 +795,15 @@ msgstr "열린"
msgid "Options"
msgstr "옵션 "
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "소유ìž"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "파ì´í”„ë¼ì¸"
@@ -690,6 +816,9 @@ msgstr "파ì´í”„ë¼ì¸ 스케쥴"
msgid "Pipeline Schedules"
msgstr "파ì´í”„ë¼ì¸ 스케쥴"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "실패 :"
@@ -753,6 +882,15 @@ msgstr "파ì´í”„ë¼ì¸"
msgid "Pipelines charts"
msgstr "파ì´í”„ë¼ì¸ 차트"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "모ë‘"
@@ -765,6 +903,12 @@ msgstr "스테ì´ì§•"
msgid "Pipeline|with stages"
msgstr "스테ì´ì§•"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -784,7 +928,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 "프로ì íŠ¸ 내보내기를 삭제할 수 없습니다."
@@ -801,9 +945,12 @@ msgstr "프로ì íŠ¸ 내보내기가 시작ë˜ì—ˆìŠµë‹ˆë‹¤. 다운로드 ë§í¬ë
msgid "Project home"
msgstr "프로ì íŠ¸ 홈"
-msgid "ProjectActivityRSS|Subscribe"
+msgid "Project overview"
msgstr ""
+msgid "ProjectActivityRSS|Subscribe"
+msgstr "구ë…"
+
msgid "ProjectFeature|Disabled"
msgstr "사용 안 함"
@@ -825,9 +972,12 @@ msgstr "스테ì´ì§•"
msgid "ProjectNetworkGraph|Graph"
msgstr "그래프"
-msgid "Push events"
+msgid "Push Rules"
msgstr ""
+msgid "Push events"
+msgstr "푸쉬 ì´ë²¤íŠ¸"
+
msgid "Read more"
msgstr "ë” ì½ê¸°"
@@ -871,13 +1021,13 @@ msgid "Request Access"
msgstr "액세스 요청"
msgid "Reset git storage health information"
-msgstr ""
+msgstr "git storage 헬스 정보 초기화"
msgid "Reset health check access token"
-msgstr ""
+msgstr "헬스 ì²´í¬ ì ‘ê·¼ í† í° ì´ˆê¸°í™”"
msgid "Reset runners registration token"
-msgstr ""
+msgstr "runner ë“±ë¡ í† í° ì´ˆê¸°í™”"
msgid "Revert this commit"
msgstr "ì´ ì»¤ë°‹ ë˜ëŒë¦¬ê¸°"
@@ -885,6 +1035,9 @@ msgstr "ì´ ì»¤ë°‹ ë˜ëŒë¦¬ê¸°"
msgid "Revert this merge request"
msgstr "ì´ ë¨¸ì§€ 리퀘스트 ë˜ëŒë¦¬ê¸°"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "파ì´í”„ë¼ì¸ 스케줄 저장"
@@ -909,6 +1062,9 @@ msgstr ""
msgid "Select target branch"
msgstr "ëŒ€ìƒ ë¸Œëžœì¹˜ ì„ íƒ"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "%{protocol} í”„ë¡œí† ì½œì„ í†µí•´ Pull 하거나 Push하려면 ê³„ì •ì— íŒ¨ìŠ¤ì›Œë“œë¥¼ 설정하십시오."
@@ -924,16 +1080,25 @@ msgstr "ìžë™ ë°°í¬ ì„¤ì •"
msgid "SetPasswordToCloneLink|set a password"
msgstr "패스워드 설정"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "%d ê°œì˜ ì´ë²¤íŠ¸ 표시 중"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "소스 코드"
-msgid "Specify the following URL during the Runner setup:"
+msgid "Spam Logs"
msgstr ""
+msgid "Specify the following URL during the Runner setup:"
+msgstr "Runner 설정 중 ë‹¤ìŒ URLì„ ì§€ì •í•˜ì„¸ìš”."
+
msgid "StarProject|Star"
msgstr "별표"
@@ -941,7 +1106,7 @@ 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 "스위치 브랜치/태그"
@@ -1008,7 +1173,7 @@ 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 ""
+msgstr "git storageì— ì ‘ê·¼í•˜ëŠ”ë° ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. "
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "즉, 빈 저장소를 만들거나 기존 저장소를 가져올 때까지 코드를 Push 할 수 없습니다."
@@ -1178,7 +1343,7 @@ msgid "UploadLink|click to upload"
msgstr "업로드하려면 í´ë¦­í•˜ì‹­ì‹œì˜¤."
msgid "Use the following registration token during setup:"
-msgstr ""
+msgstr "설정 ì¤‘ì— ë‹¤ìŒ ë“±ë¡ í† í° ì´ìš© : "
msgid "Use your global notification setting"
msgstr "전체 알림 설정 사용"
@@ -1204,14 +1369,17 @@ msgstr "ì´ ë°ì´í„°ë¥¼ ë³´ê³  싶ì€ê°€ìš”? 관리ìžì—게 액세스 권한ì
msgid "We don't have enough data to show this stage."
msgstr "ì´ ë‹¨ê³„ë¥¼ ë³´ì—¬ì£¼ê¸°ì— ì¶©ë¶„í•œ ë°ì´í„°ê°€ 없습니다."
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "액세스 요청 철회"
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
-msgstr "%{group_name} ê·¸ë£¹ì„ ì œê±°í•˜ë ¤ê³ í•©ë‹ˆë‹¤. \"ì •ë§ë¡œ\" 확실합니까?"
+msgstr "%{group_name} ê·¸ë£¹ì„ ì œê±°í•˜ë ¤ê³ í•©ë‹ˆë‹¤. \\\"ì •ë§ë¡œ\\\" 확실합니까?"
msgid "You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
-msgstr "%{project_name_with_namespace} 프로ì íŠ¸ë¥¼ 삭제하려고합니다. ì‚­ì œëœ í”„ë¡œì íŠ¸ë¥¼ ë³µì› í•  수 없습니다! \"ì •ë§ë¡œ\" 확실합니까?"
+msgstr "%{project_name_with_namespace} 프로ì íŠ¸ë¥¼ 삭제하려고합니다. \"ì‚­ì œëœ í”„ë¡œì íŠ¸ë¥¼ ë³µì› í•  수 없습니다! \\\"ì •ë§ë¡œ\\\" 확실합니까?"
msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
msgstr "í¬í¬ 관계를 소스 프로ì íŠ¸ %{forked_from_project}ì— ëŒ€í•´ 제거하려고합니다. \"ì •ë§ë¡œ\" 확실합니까?"
@@ -1267,4 +1435,5 @@ msgstr "알림 ì´ë©”ì¼"
msgid "parent"
msgid_plural "parents"
-msgstr[0] "부모" \ No newline at end of file
+msgstr[0] "부모"
+
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index d8887110867..88ca25dbb3b 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 10:14-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Portuguese, Brazilian\n"
"Language: pt_BR\n"
@@ -57,9 +57,18 @@ msgstr "Uma coleção de gráficos sobre Integração Contínua"
msgid "About auto deploy"
msgstr "Sobre o deploy automático"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "Ativo"
@@ -84,6 +93,12 @@ msgstr "Adicionar novo diretório"
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Projeto arquivado! O repositório é somente leitura"
@@ -105,6 +120,63 @@ 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"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] ""
@@ -137,6 +209,9 @@ msgstr "Navegar pelos arquivos"
msgid "ByAuthor|by"
msgstr "por"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "Configuração da IC"
@@ -164,6 +239,9 @@ msgstr "Registro de mudanças"
msgid "Charts"
msgstr "Gráficos"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Cherry-pick esse commit"
@@ -259,12 +337,18 @@ msgstr "Commit feito por"
msgid "Compare"
msgstr "Comparar"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "Guia de contribuição"
msgid "Contributors"
msgstr "Contribuidores"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "Copiar URL para área de transferência"
@@ -351,6 +435,9 @@ msgid_plural "Deploys"
msgstr[0] "Implantação"
msgstr[1] "Implantações"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "Descrição"
@@ -399,6 +486,9 @@ msgstr "Alterar"
msgid "Edit Pipeline Schedule %{id}"
msgstr "Alterar Agendamento do Pipeline %{id}"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -464,6 +554,12 @@ msgstr "Da abertura de tarefas até a implantação para a produção"
msgid "From merge request merge until deploy to production"
msgstr "Do merge request até a implantação em produção"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -476,6 +572,9 @@ msgstr "Ir para seu fork"
msgid "GoToYourFork|Fork"
msgstr "Fork"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -497,6 +596,9 @@ msgstr ""
msgid "Home"
msgstr "Início"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "Manutenção iniciada com sucesso"
@@ -515,14 +617,8 @@ msgstr "Apresentando a Análise de Ciclo"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "Jobs no último mês"
-
-msgid "Jobs for last week"
-msgstr "Jobs na última semana"
-
-msgid "Jobs for last year"
-msgstr "Jobs no último ano"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "Desabilitado"
@@ -530,6 +626,9 @@ msgstr "Desabilitado"
msgid "LFSStatus|Enabled"
msgstr "Habilitado"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "Último %d dia"
@@ -562,20 +661,38 @@ msgstr "Sair do grupo"
msgid "Leave project"
msgstr "Sair do projeto"
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "Limitado a mostrar %d evento, no máximo"
msgstr[1] "Limitado a mostrar %d eventos, no máximo"
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr "Mediana"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "adicione uma chave SSH"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -677,6 +794,9 @@ msgstr "Participar"
msgid "NotificationLevel|Watch"
msgstr "Observar"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtrar"
@@ -686,9 +806,15 @@ msgstr "Aberto"
msgid "Options"
msgstr "Opções"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "Proprietário"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr ""
@@ -701,6 +827,9 @@ msgstr "Agendamento da Pipeline"
msgid "Pipeline Schedules"
msgstr "Agendamentos da Pipeline"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "Falhou:"
@@ -764,6 +893,15 @@ msgstr ""
msgid "Pipelines charts"
msgstr "Gráficos de pipelines"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "todos"
@@ -776,6 +914,12 @@ msgstr "com etapa"
msgid "Pipeline|with stages"
msgstr "com etapas"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -812,6 +956,9 @@ msgstr "Exportação do projeto iniciada. Um link para baixá-la será enviado p
msgid "Project home"
msgstr "Página inicial do projeto"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -836,6 +983,9 @@ msgstr "Etapa"
msgid "ProjectNetworkGraph|Graph"
msgstr "Ãrvore"
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -896,6 +1046,9 @@ msgstr "Reverter este commit"
msgid "Revert this merge request"
msgstr "Reverter esse merge request"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "Salvar agendamento da pipeline"
@@ -920,6 +1073,9 @@ msgstr ""
msgid "Select target branch"
msgstr "Selecionar branch de destino"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Defina uma senha para sua conta para aceitar ou entregar código via %{protocol}."
@@ -935,14 +1091,23 @@ msgstr "Configurar implantação automática"
msgid "SetPasswordToCloneLink|set a password"
msgstr "defina uma senha"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Mostrando %d evento"
msgstr[1] "Mostrando %d eventos"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "Código-fonte"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1219,6 +1384,9 @@ msgstr "Precisa visualizar os dados? Solicite acesso ao administrador."
msgid "We don't have enough data to show this stage."
msgstr "Esta etapa não possui dados suficientes para exibição."
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Remover Requisição de Acesso"
@@ -1284,4 +1452,5 @@ msgstr "emails de notificação"
msgid "parent"
msgid_plural "parents"
msgstr[0] "pai"
-msgstr[1] "pais" \ No newline at end of file
+msgstr[1] "pais"
+
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index 926995d1f91..96e6c8a8d3f 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:41-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Russian\n"
"Language: ru_RU\n"
@@ -61,9 +61,18 @@ msgstr "Графики отноÑительно непрерывной интеÐ
msgid "About auto deploy"
msgstr "ÐвтоматичеÑкое развертывание"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "Ðктивный"
@@ -88,6 +97,12 @@ msgstr "Добавить каталог"
msgid "All"
msgstr ""
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Ðрхивный проект! Репозиторий доÑтупен только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ"
@@ -95,7 +110,7 @@ msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Ð’Ñ‹ дейÑтвительно хотите удалить Ñто раÑпиÑание конвейера?"
msgid "Are you sure you want to discard your changes?"
-msgstr ""
+msgstr "Ð’Ñ‹ уверены, что Ð’Ñ‹ хотите отменить Ваши изменениÑ?"
msgid "Are you sure you want to reset registration token?"
msgstr ""
@@ -104,11 +119,68 @@ msgid "Are you sure you want to reset the health check token?"
msgstr ""
msgid "Are you sure?"
-msgstr ""
+msgstr "Вы уверены?"
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Приложить файл через drag &amp; drop или %{upload_link}"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Ветка"
@@ -142,6 +214,9 @@ msgstr "ПроÑмотр файлов"
msgid "ByAuthor|by"
msgstr "по автору"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "ÐаÑтройка CI"
@@ -149,7 +224,7 @@ msgid "Cancel"
msgstr "Отмена"
msgid "Cancel edit"
-msgstr ""
+msgstr "Отменить редактирование"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Выбрать в ветке"
@@ -169,6 +244,9 @@ msgstr "Журнал изменений"
msgid "Charts"
msgstr "Диаграммы"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Подобрать в Ñтом коммите"
@@ -230,7 +308,7 @@ msgid "CiStatus|running"
msgstr "выполнÑетÑÑ"
msgid "Comments"
-msgstr ""
+msgstr "Комментарии"
msgid "Commit"
msgid_plural "Commits"
@@ -265,12 +343,18 @@ msgstr "ФикÑировано"
msgid "Compare"
msgstr "Сравнить"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "РуководÑтво учаÑтника"
msgid "Contributors"
msgstr "УчаÑтники"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "Копировать URL в буфер обмена"
@@ -281,7 +365,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}."
@@ -358,6 +442,9 @@ msgstr[0] "РазмеÑтить"
msgstr[1] "Размещение"
msgstr[2] "Размещение"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "ОпиÑание"
@@ -368,7 +455,7 @@ msgid "Directory name"
msgstr "Каталог"
msgid "Discard changes"
-msgstr ""
+msgstr "Отменить изменениÑ"
msgid "Don't show again"
msgstr "Ðе показывать Ñнова"
@@ -406,6 +493,9 @@ msgstr "Редактировать"
msgid "Edit Pipeline Schedule %{id}"
msgstr "Изменить раÑпиÑание конвейера %{id}"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -472,11 +562,17 @@ msgstr "От ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ñ‹ до Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð
msgid "From merge request merge until deploy to production"
msgstr "От запроÑа на ÑлиÑние до Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð² рабочей Ñреде"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
msgid "GitLab Runner section"
-msgstr ""
+msgstr "Ð¡ÐµÐºÑ†Ð¸Ñ Gitlab Runner"
msgid "Go to your fork"
msgstr "Перейти к вашему форку"
@@ -484,6 +580,9 @@ msgstr "Перейти к вашему форку"
msgid "GoToYourFork|Fork"
msgstr "Форк"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -505,6 +604,9 @@ msgstr ""
msgid "Home"
msgstr "ГлавнаÑ"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "ОчиÑтка уÑпешно запущена"
@@ -512,7 +614,7 @@ msgid "Import repository"
msgstr "Импорт репозиториÑ"
msgid "Install a Runner compatible with GitLab CI"
-msgstr ""
+msgstr "УÑтановите Gitlab Runner ÑовмеÑтимый Ñ Gitlab CI"
msgid "Interval Pattern"
msgstr "Шаблон интервала"
@@ -523,14 +625,8 @@ msgstr "Внедрение Цикла Ðналитик"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "Работы за прошлый меÑÑц"
-
-msgid "Jobs for last week"
-msgstr "Работы за прошлую неделю"
-
-msgid "Jobs for last year"
-msgstr "Работы за прошлый год"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "Отключено"
@@ -538,6 +634,9 @@ msgstr "Отключено"
msgid "LFSStatus|Enabled"
msgstr "Включено"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "ПоÑледний %d день"
@@ -571,21 +670,39 @@ msgstr "Покинуть группу"
msgid "Leave project"
msgstr "Покинуть проект"
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "Ограничение %d ÑобытиÑ"
msgstr[1] "Ограничение %d Ñобытий"
msgstr[2] "Ограничение %d Ñобытий"
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr "Среднее"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "добавить ключ SSH"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -688,6 +805,9 @@ msgstr "УчаÑтие"
msgid "NotificationLevel|Watch"
msgstr "ОтÑлеживать"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Фильтр"
@@ -697,9 +817,15 @@ msgstr "Открыто"
msgid "Options"
msgstr "ÐаÑтройки"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "Владелец"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "Конвейер"
@@ -712,6 +838,9 @@ msgstr "РаÑпиÑание конвейера"
msgid "Pipeline Schedules"
msgstr "РаÑпиÑÐ°Ð½Ð¸Ñ ÐºÐ¾Ð½Ð²ÐµÐ¹ÐµÑ€Ð¾Ð²"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "Ðеудача:"
@@ -775,6 +904,15 @@ msgstr "Конвейер"
msgid "Pipelines charts"
msgstr "Диаграмма конвейера"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "вÑе"
@@ -787,6 +925,12 @@ msgstr "Ñо Ñтадией"
msgid "Pipeline|with stages"
msgstr "Ñо ÑтадиÑми"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -823,6 +967,9 @@ msgstr "Ðачат ÑкÑпорт проекта. СÑылка Ð´Ð»Ñ Ñкачи
msgid "Project home"
msgstr "ДомашнÑÑ Ñтраница"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -847,6 +994,9 @@ msgstr "Этап"
msgid "ProjectNetworkGraph|Graph"
msgstr "Граф"
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -907,6 +1057,9 @@ msgstr "Отменить Ñто изменение"
msgid "Revert this merge request"
msgstr "Отменить Ñтот Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "Сохранить раÑпиÑание конвейра"
@@ -931,6 +1084,9 @@ msgstr ""
msgid "Select target branch"
msgstr "Выбор целевой ветки"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "УÑтановите пароль в Ñвоем аккаунте, чтобы отправлÑÑ‚ÑŒ или получать код через %{protocol}."
@@ -946,15 +1102,24 @@ msgstr "ÐаÑтройка автоматичеÑкого развертыван
msgid "SetPasswordToCloneLink|set a password"
msgstr "уÑтановить пароль"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Показано %d Ñобытие"
msgstr[1] "Показано %d Ñобытий"
msgstr[2] "Показано %d Ñобытий"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "ИÑходный код"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1234,6 +1399,9 @@ msgstr "Хотите увидеть данные? ОбратитеÑÑŒ к адм
msgid "We don't have enough data to show this stage."
msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾ Ñтапу отÑутÑтвует."
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Отменить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ñтупа"
@@ -1301,4 +1469,5 @@ msgid "parent"
msgid_plural "parents"
msgstr[0] "иÑточник"
msgstr[1] "иÑточники"
-msgstr[2] "иÑточники" \ No newline at end of file
+msgstr[2] "иÑточники"
+
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index 5f9f087ff64..4d24140f3dc 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:49-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Ukrainian\n"
"Language: uk_UA\n"
@@ -61,9 +61,18 @@ msgstr "Це набір графічних елементів Ð´Ð»Ñ Ð±ÐµÐ·Ð¿ÐµÑ
msgid "About auto deploy"
msgstr "Про авто розгортаннÑ"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
msgstr ""
+msgid "Account"
+msgstr ""
+
msgid "Active"
msgstr "Ðктивний"
@@ -88,6 +97,12 @@ msgstr "Додати новий каталог"
msgid "All"
msgstr "Ð’ÑÑ–"
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Заархівований проект! Репозиторій доÑтупний лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ"
@@ -109,6 +124,63 @@ msgstr ""
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "Прикріпити файл за допомогою перетÑÐ³ÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ %{upload_link}"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Гілка"
@@ -142,6 +214,9 @@ msgstr "ПереглÑд файлів"
msgid "ByAuthor|by"
msgstr "від"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ CI"
@@ -169,6 +244,9 @@ msgstr "СпиÑок змін (Changelog)"
msgid "Charts"
msgstr "Графіки"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Cherry-pick в цьому комміті"
@@ -265,12 +343,18 @@ msgstr "Комміт від"
msgid "Compare"
msgstr "ПорівнÑти"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "Керівництво контриб’юторів"
msgid "Contributors"
msgstr "Контриб’ютори"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "Скопіювати URL в буфер обміну"
@@ -358,6 +442,9 @@ msgstr[0] "РозгортаннÑ"
msgstr[1] "РозгортаннÑ"
msgstr[2] "Розгортань"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "ОпиÑ"
@@ -406,6 +493,9 @@ msgstr "Редагувати"
msgid "Edit Pipeline Schedule %{id}"
msgstr "Редагувати Розклад Конвеєра %{id}"
+msgid "Emails"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -472,6 +562,12 @@ msgstr "З моменту ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð¸ до розгорÑ
msgid "From merge request merge until deploy to production"
msgstr "З об'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð½Ð° ПРОД"
+msgid "GPG Keys"
+msgstr ""
+
+msgid "Geo Nodes"
+msgstr ""
+
msgid "Git storage health information has been reset"
msgstr ""
@@ -484,6 +580,9 @@ msgstr "Перейти до вашого форку"
msgid "GoToYourFork|Fork"
msgstr "Форк"
+msgid "Group overview"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -505,6 +604,9 @@ msgstr ""
msgid "Home"
msgstr "Головна"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "ÐžÑ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ ÑƒÑпішно розпочато"
@@ -523,14 +625,8 @@ msgstr "ПредÑтавлÑємо аналітику циклу"
msgid "Issue events"
msgstr ""
-msgid "Jobs for last month"
-msgstr "КількіÑÑ‚ÑŒ завдань за оÑтанній міÑÑць"
-
-msgid "Jobs for last week"
-msgstr "КількіÑÑ‚ÑŒ завдань за оÑтанній тиждень"
-
-msgid "Jobs for last year"
-msgstr "КількіÑÑ‚ÑŒ завдань за оÑтанній рік"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "Вимкнено"
@@ -538,6 +634,9 @@ msgstr "Вимкнено"
msgid "LFSStatus|Enabled"
msgstr "Увімкнено"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "ОÑтанній %d день"
@@ -571,21 +670,39 @@ msgstr "Залишити групу"
msgid "Leave project"
msgstr "Залишити проект"
+msgid "License"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ %d події"
msgstr[1] "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ %d подій"
msgstr[2] "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ %d подій"
+msgid "Locked Files"
+msgstr ""
+
msgid "Median"
msgstr "Медіана"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
msgstr ""
+msgid "Messages"
+msgstr ""
+
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "не додаÑте SSH ключ"
+msgid "Monitoring"
+msgstr ""
+
msgid "More information is available|here"
msgstr ""
@@ -688,6 +805,9 @@ msgstr "Берете учаÑÑ‚ÑŒ"
msgid "NotificationLevel|Watch"
msgstr "ВідÑтежувати"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Фільтр"
@@ -697,9 +817,15 @@ msgstr "Відкрито"
msgid "Options"
msgstr "Параметри"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "ВлаÑник"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "Конвеєр"
@@ -712,6 +838,9 @@ msgstr "Розклад Конвеєра"
msgid "Pipeline Schedules"
msgstr "Розклади Конвеєрів"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "Ðе вдалоÑÑ:"
@@ -775,6 +904,15 @@ msgstr "Конвеєри"
msgid "Pipelines charts"
msgstr "Чарти Конвеєрів"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "вÑÑ–"
@@ -787,6 +925,12 @@ msgstr "зі Ñтадією"
msgid "Pipeline|with stages"
msgstr "зі ÑтадіÑми"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
+msgstr ""
+
msgid "Project"
msgstr ""
@@ -823,6 +967,9 @@ msgstr "Розпочато екÑпорт проекту. ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ð
msgid "Project home"
msgstr "Ð”Ð¾Ð¼Ð°ÑˆÐ½Ñ Ñторінка проекту"
+msgid "Project overview"
+msgstr ""
+
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
@@ -847,6 +994,9 @@ msgstr "Етап"
msgid "ProjectNetworkGraph|Graph"
msgstr "ІÑторіÑ"
+msgid "Push Rules"
+msgstr ""
+
msgid "Push events"
msgstr ""
@@ -907,6 +1057,9 @@ msgstr "СкаÑувати цей комміт"
msgid "Revert this merge request"
msgstr "СкаÑувати цей запит на злиттÑ"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "Зберегти Розклад Конвеєра"
@@ -931,6 +1084,9 @@ msgstr ""
msgid "Select target branch"
msgstr "Вибір цільової гілки"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Ð’Ñтановіть пароль Ñвого облікового запиÑу, щоб відправлÑти або отримувати код через %{protocol}."
@@ -946,15 +1102,24 @@ msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ðµ розгортаннÑ"
msgid "SetPasswordToCloneLink|set a password"
msgstr "вÑтановити пароль"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Показано %d подію"
msgstr[1] "Показано %d події"
msgstr[2] "Показано %d подій"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "Код"
+msgid "Spam Logs"
+msgstr ""
+
msgid "Specify the following URL during the Runner setup:"
msgstr ""
@@ -1234,6 +1399,9 @@ msgstr "Хочете побачити дані? Будь лаÑка, попроÑ
msgid "We don't have enough data to show this stage."
msgstr "Ми не маємо доÑтатньо даних Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ цього етапу."
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "СкаÑувати запит доÑтупу"
@@ -1301,4 +1469,5 @@ msgid "parent"
msgid_plural "parents"
msgstr[0] "джерело"
msgstr[1] "джерела"
-msgstr[2] "джерел" \ No newline at end of file
+msgstr[2] "джерел"
+
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index eb607acf1f4..47de28209df 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:59-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@@ -28,20 +28,20 @@ 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."
-msgstr ""
+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[0] "%{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"
@@ -53,7 +53,16 @@ msgstr "æŒç»­é›†æˆæ•°æ®å›¾"
msgid "About auto deploy"
msgstr "关于自动部署"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
+msgstr "为方便修å¤æŒ‚载问题,访问故障存储已被暂时ç¦ç”¨ã€‚在问题解决åŽè¯·é‡ç½®å­˜å‚¨å¥åº·ä¿¡æ¯ï¼Œä»¥å…许å†æ¬¡è®¿é—®ã€‚"
+
+msgid "Account"
msgstr ""
msgid "Active"
@@ -78,6 +87,12 @@ msgid "Add new directory"
msgstr "添加目录"
msgid "All"
+msgstr "全部"
+
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
msgstr ""
msgid "Archived project! Repository is read-only"
@@ -87,20 +102,77 @@ msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "确定è¦åˆ é™¤æ­¤æµæ°´çº¿è®¡åˆ’å—?"
msgid "Are you sure you want to discard your changes?"
-msgstr ""
+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 ""
+msgstr "确定å—?"
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "拖放文件到此处或者 %{upload_link}"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "分支"
@@ -132,6 +204,9 @@ msgstr "æµè§ˆæ–‡ä»¶"
msgid "ByAuthor|by"
msgstr "作者:"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "CI é…ç½®"
@@ -139,7 +214,7 @@ msgid "Cancel"
msgstr "å–消"
msgid "Cancel edit"
-msgstr ""
+msgstr "å–消编辑"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "选择分支"
@@ -159,6 +234,9 @@ msgstr "更新日志"
msgid "Charts"
msgstr "统计图"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "优选此æ交"
@@ -220,7 +298,7 @@ msgid "CiStatus|running"
msgstr "è¿è¡Œä¸­"
msgid "Comments"
-msgstr ""
+msgstr "评论"
msgid "Commit"
msgid_plural "Commits"
@@ -253,12 +331,18 @@ msgstr "æ交者:"
msgid "Compare"
msgstr "比较"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "贡献指å—"
msgid "Contributors"
msgstr "贡献者"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "å¤åˆ¶ URL 到剪贴æ¿"
@@ -269,7 +353,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} æ¥æ‹‰å–或推é€ã€‚"
@@ -344,17 +428,20 @@ msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] "部署"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "æè¿°"
msgid "Details"
-msgstr ""
+msgstr "详情"
msgid "Directory name"
msgstr "目录å称"
msgid "Discard changes"
-msgstr ""
+msgstr "放弃更改"
msgid "Don't show again"
msgstr "ä¸å†æ˜¾ç¤º"
@@ -392,23 +479,26 @@ msgstr "编辑"
msgid "Edit Pipeline Schedule %{id}"
msgstr "编辑 %{id} æµæ°´çº¿è®¡åˆ’"
-msgid "EventFilterBy|Filter by all"
+msgid "Emails"
msgstr ""
+msgid "EventFilterBy|Filter by all"
+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 点)"
@@ -456,39 +546,51 @@ msgstr "从创建议题到部署至生产环境"
msgid "From merge request merge until deploy to production"
msgstr "从åˆå¹¶è¯·æ±‚被åˆå¹¶åŽåˆ°éƒ¨ç½²è‡³ç”Ÿäº§çŽ¯å¢ƒ"
-msgid "Git storage health information has been reset"
+msgid "GPG Keys"
msgstr ""
-msgid "GitLab Runner section"
+msgid "Geo Nodes"
msgstr ""
+msgid "Git storage health information has been reset"
+msgstr "Git 存储å¥åº·ä¿¡æ¯å·²é‡ç½®"
+
+msgid "GitLab Runner section"
+msgstr "GitLab Runner"
+
msgid "Go to your fork"
msgstr "跳转到派生项目"
msgid "GoToYourFork|Fork"
msgstr "跳转到派生项目"
-msgid "Health Check"
+msgid "Group overview"
msgstr ""
+msgid "Health Check"
+msgstr "å¥åº·æ£€æŸ¥"
+
msgid "Health information can be retrieved from the following endpoints. More information is available"
-msgstr ""
+msgstr "å¥åº·ä¿¡æ¯å¯ä»¥ä»Žä»¥ä¸‹API路径获å–。如需了解更多信æ¯ï¼Œè¯·æŸ¥çœ‹"
msgid "HealthCheck|Access token is"
-msgstr ""
+msgstr "访问令牌是"
msgid "HealthCheck|Healthy"
-msgstr ""
+msgstr "å¥åº·"
msgid "HealthCheck|No Health Problems Detected"
-msgstr ""
+msgstr "没有检测到å¥åº·é—®é¢˜"
msgid "HealthCheck|Unhealthy"
-msgstr ""
+msgstr "éžå¥åº·"
msgid "Home"
msgstr "首页"
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "已开始维护"
@@ -496,7 +598,7 @@ msgid "Import repository"
msgstr "导入存储库"
msgid "Install a Runner compatible with GitLab CI"
-msgstr ""
+msgstr "安装一个与 GitLab CI 兼容的 Runner"
msgid "Interval Pattern"
msgstr "循环周期"
@@ -505,16 +607,10 @@ msgid "Introducing Cycle Analytics"
msgstr "周期分æžç®€ä»‹"
msgid "Issue events"
-msgstr ""
-
-msgid "Jobs for last month"
-msgstr "上个月的作业"
+msgstr "议题事件"
-msgid "Jobs for last week"
-msgstr "上个星期的作业"
-
-msgid "Jobs for last year"
-msgstr "去年的作业"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "åœç”¨"
@@ -522,6 +618,9 @@ msgstr "åœç”¨"
msgid "LFSStatus|Enabled"
msgstr "å¯ç”¨"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "最近 %d 天"
@@ -536,10 +635,10 @@ msgid "Last commit"
msgstr "最åŽæ交"
msgid "LastPushEvent|You pushed to"
-msgstr ""
+msgstr "您推é€äº†"
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "于"
msgid "Learn more in the"
msgstr "了解更多"
@@ -553,22 +652,40 @@ msgstr "退出群组"
msgid "Leave project"
msgstr "退出项目"
+msgid "License"
+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 ""
+
msgid "Median"
msgstr "中ä½æ•°"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
+msgstr "åˆå¹¶äº‹ä»¶"
+
+msgid "Messages"
msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "新建 SSH 公钥"
-msgid "More information is available|here"
+msgid "Monitoring"
msgstr ""
+msgid "More information is available|here"
+msgstr "帮助文档"
+
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] "新建议题"
@@ -666,6 +783,9 @@ msgstr "å‚与"
msgid "NotificationLevel|Watch"
msgstr "关注"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "筛选"
@@ -675,9 +795,15 @@ msgstr "开始于"
msgid "Options"
msgstr "æ“作"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "所有者"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "æµæ°´çº¿"
@@ -690,6 +816,9 @@ msgstr "æµæ°´çº¿è®¡åˆ’"
msgid "Pipeline Schedules"
msgstr "æµæ°´çº¿è®¡åˆ’"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "失败:"
@@ -753,6 +882,15 @@ msgstr "æµæ°´çº¿"
msgid "Pipelines charts"
msgstr "æµæ°´çº¿ç»Ÿè®¡å›¾"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "所有"
@@ -765,9 +903,15 @@ msgstr "于阶段"
msgid "Pipeline|with stages"
msgstr "于阶段"
-msgid "Project"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
msgstr ""
+msgid "Project"
+msgstr "项目"
+
msgid "Project '%{project_name}' queued for deletion."
msgstr "项目 '%{project_name}' 已进入删除队列。"
@@ -784,7 +928,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 "无法删除项目导出。"
@@ -801,9 +945,12 @@ msgstr "项目导出已开始。下载链接将通过电å­é‚®ä»¶å‘é€ã€‚"
msgid "Project home"
msgstr "项目首页"
-msgid "ProjectActivityRSS|Subscribe"
+msgid "Project overview"
msgstr ""
+msgid "ProjectActivityRSS|Subscribe"
+msgstr "订阅"
+
msgid "ProjectFeature|Disabled"
msgstr "åœç”¨"
@@ -825,9 +972,12 @@ msgstr "阶段"
msgid "ProjectNetworkGraph|Graph"
msgstr "分支图"
-msgid "Push events"
+msgid "Push Rules"
msgstr ""
+msgid "Push events"
+msgstr "推é€äº‹ä»¶"
+
msgid "Read more"
msgstr "了解更多"
@@ -865,19 +1015,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 "还原此æ交"
@@ -885,6 +1035,9 @@ msgstr "还原此æ交"
msgid "Revert this merge request"
msgstr "还原此åˆå¹¶è¯·æ±‚"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "ä¿å­˜æµæ°´çº¿è®¡åˆ’"
@@ -904,11 +1057,14 @@ msgid "Select a timezone"
msgstr "选择时区"
msgid "Select existing branch"
-msgstr ""
+msgstr "选择现有分支"
msgid "Select target branch"
msgstr "选择目标分支"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "为账å·åˆ›å»ºä¸€ä¸ªç”¨äºŽæŽ¨é€æˆ–拉å–çš„ %{protocol} 密ç ã€‚"
@@ -924,16 +1080,25 @@ msgstr "设置自动部署"
msgid "SetPasswordToCloneLink|set a password"
msgstr "设置密ç "
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "显示 %d 个事件"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "æºä»£ç "
-msgid "Specify the following URL during the Runner setup:"
+msgid "Spam Logs"
msgstr ""
+msgid "Specify the following URL during the Runner setup:"
+msgstr "在 Runner 设置时指定以下 URL:"
+
msgid "StarProject|Star"
msgstr "星标"
@@ -941,7 +1106,7 @@ 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 "切æ¢åˆ†æ”¯/标签"
@@ -957,7 +1122,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 "ç¼–ç é˜¶æ®µæ¦‚述了从第一次æ交到创建åˆå¹¶è¯·æ±‚的时间。创建第一个åˆå¹¶è¯·æ±‚åŽï¼Œæ•°æ®å°†è‡ªåŠ¨æ·»åŠ åˆ°æ­¤å¤„。"
@@ -1008,7 +1173,7 @@ 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 ""
+msgstr "访问 Git 存储时出现问题:"
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "在创建一个空的存储库或导入现有存储库之å‰ï¼Œå°†æ— æ³•æŽ¨é€ä»£ç ã€‚"
@@ -1178,7 +1343,7 @@ msgid "UploadLink|click to upload"
msgstr "点击上传"
msgid "Use the following registration token during setup:"
-msgstr ""
+msgstr "在安装过程中使用以下注册令牌:"
msgid "Use your global notification setting"
msgstr "使用全局通知设置"
@@ -1204,6 +1369,9 @@ msgstr "æƒé™ä¸è¶³ã€‚如需查看相关数æ®ï¼Œè¯·å‘管ç†å‘˜ç”³è¯·æƒé™ã€‚
msgid "We don't have enough data to show this stage."
msgstr "该阶段的数æ®ä¸è¶³ï¼Œæ— æ³•æ˜¾ç¤ºã€‚"
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "å–消æƒé™ç”³è¯·"
@@ -1267,4 +1435,5 @@ msgstr "通知邮件"
msgid "parent"
msgid_plural "parents"
-msgstr[0] "父级" \ No newline at end of file
+msgstr[0] "父级"
+
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index 74c7b464091..fee0d661c7a 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:59-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:21-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Traditional, Hong Kong\n"
"Language: zh_HK\n"
@@ -28,20 +28,20 @@ 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."
-msgstr ""
+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[0] "%{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"
@@ -53,7 +53,16 @@ msgstr "相關æŒçºŒé›†æˆçš„圖åƒé›†åˆ"
msgid "About auto deploy"
msgstr "關於自動部署"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
+msgstr "å› æ¢å¾©å®‰è£ï¼Œè¨ªå•æ•…障存儲已被暫時ç¦ç”¨ã€‚在å•é¡Œè§£æ±ºå¾Œå°‡é‡ç½®å­˜å„²ä¿¡æ¯ï¼Œä»¥ä¾¿å†æ¬¡è¨ªå•ã€‚"
+
+msgid "Account"
msgstr ""
msgid "Active"
@@ -78,6 +87,12 @@ msgid "Add new directory"
msgstr "添加新目錄"
msgid "All"
+msgstr "全部"
+
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
msgstr ""
msgid "Archived project! Repository is read-only"
@@ -87,20 +102,77 @@ msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "確定è¦åˆªé™¤æ­¤æµæ°´ç·šè¨ˆåŠƒå—Žï¼Ÿ"
msgid "Are you sure you want to discard your changes?"
-msgstr ""
+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 ""
+msgstr "確定嗎?"
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "拖放文件到此處或者 %{upload_link}"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "分支"
@@ -132,6 +204,9 @@ msgstr "ç€è¦½æ–‡ä»¶"
msgid "ByAuthor|by"
msgstr "作者:"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "CI é…ç½®"
@@ -139,7 +214,7 @@ msgid "Cancel"
msgstr "å–消"
msgid "Cancel edit"
-msgstr ""
+msgstr "å–消编辑"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "挑é¸åˆ°åˆ†æ”¯"
@@ -159,6 +234,9 @@ msgstr "更新日誌"
msgid "Charts"
msgstr "統計圖"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "優é¸æ­¤æ交"
@@ -220,7 +298,7 @@ msgid "CiStatus|running"
msgstr "é‹è¡Œä¸­"
msgid "Comments"
-msgstr ""
+msgstr "è©•è«– (Comment)"
msgid "Commit"
msgid_plural "Commits"
@@ -253,12 +331,18 @@ msgstr "æ交者:"
msgid "Compare"
msgstr "比較"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "è²¢ç»æŒ‡å—"
msgid "Contributors"
msgstr "è²¢ç»è€…"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "複製URL到剪貼æ¿"
@@ -269,7 +353,7 @@ msgid "Create New Directory"
msgstr "創建新目錄"
msgid "Create a new branch"
-msgstr ""
+msgstr "創建壹個新分支 (branch)"
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "在帳戶上創建個人訪å•ä»¤ç‰Œï¼Œä»¥é€šéŽ %{protocol} 來拉å–或推é€ã€‚"
@@ -344,17 +428,20 @@ msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] "部署"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "æè¿°"
msgid "Details"
-msgstr ""
+msgstr "詳情"
msgid "Directory name"
msgstr "目錄å稱"
msgid "Discard changes"
-msgstr ""
+msgstr "放棄更改"
msgid "Don't show again"
msgstr "ä¸å†é¡¯ç¤º"
@@ -392,23 +479,26 @@ msgstr "編輯"
msgid "Edit Pipeline Schedule %{id}"
msgstr "編輯 %{id} æµæ°´ç·šè¨ˆåŠƒ"
-msgid "EventFilterBy|Filter by all"
+msgid "Emails"
msgstr ""
+msgid "EventFilterBy|Filter by all"
+msgstr "全部"
+
msgid "EventFilterBy|Filter by comments"
-msgstr ""
+msgstr "按評論 (comment) éŽæ¿¾"
msgid "EventFilterBy|Filter by issue events"
-msgstr ""
+msgstr "按議題事件 (issue event) éŽæ¿¾"
msgid "EventFilterBy|Filter by merge events"
-msgstr ""
+msgstr "按åˆä½µäº‹ä»¶ (merge event) éŽæ¿¾"
msgid "EventFilterBy|Filter by push events"
-msgstr ""
+msgstr "按推é€äº‹ä»¶ (push event) éŽæ¿¾"
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "按團隊éŽæ¿¾"
msgid "Every day (at 4:00am)"
msgstr "æ¯æ—¥åŸ·è¡Œï¼ˆæ·©æ™¨ 4 點)"
@@ -456,39 +546,51 @@ msgstr "從創建議題到部署到生產環境"
msgid "From merge request merge until deploy to production"
msgstr "從åˆä½µè«‹æ±‚çš„åˆä½µåˆ°éƒ¨ç½²è‡³ç”Ÿç”¢ç’°å¢ƒ"
-msgid "Git storage health information has been reset"
+msgid "GPG Keys"
msgstr ""
-msgid "GitLab Runner section"
+msgid "Geo Nodes"
msgstr ""
+msgid "Git storage health information has been reset"
+msgstr "Git 存儲å¥åº·ä¿¡æ¯å·²é‡ç½®"
+
+msgid "GitLab Runner section"
+msgstr "GitLab Runner 介紹"
+
msgid "Go to your fork"
msgstr "跳轉到派生項目"
msgid "GoToYourFork|Fork"
msgstr "跳轉到派生項目"
-msgid "Health Check"
+msgid "Group overview"
msgstr ""
+msgid "Health Check"
+msgstr "å¥åº·æª¢æŸ¥ (Health Check)"
+
msgid "Health information can be retrieved from the following endpoints. More information is available"
-msgstr ""
+msgstr "å¥åº·ä¿¡æ¯å¯ä»¥å¾žä»¥ä¸‹ç«¯é»žæª¢ç´¢ã€‚想了解更多信æ¯è«‹æŸ¥çœ‹"
msgid "HealthCheck|Access token is"
-msgstr ""
+msgstr "訪å•ä»¤ç‰Œæ˜¯"
msgid "HealthCheck|Healthy"
-msgstr ""
+msgstr "å¥åº·"
msgid "HealthCheck|No Health Problems Detected"
-msgstr ""
+msgstr "沒有檢測到å¥åº·å•é¡Œ"
msgid "HealthCheck|Unhealthy"
-msgstr ""
+msgstr "ä¸è‰¯"
msgid "Home"
msgstr "首é "
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "已開始維護"
@@ -496,7 +598,7 @@ msgid "Import repository"
msgstr "導入存儲庫"
msgid "Install a Runner compatible with GitLab CI"
-msgstr ""
+msgstr "安è£å£¹å€‹èˆ‡ GitLab CI 兼容的 Runner"
msgid "Interval Pattern"
msgstr "循環週期"
@@ -505,16 +607,10 @@ msgid "Introducing Cycle Analytics"
msgstr "週期分æžç°¡ä»‹"
msgid "Issue events"
-msgstr ""
-
-msgid "Jobs for last month"
-msgstr "上個月的作業"
+msgstr "議題事件 (issue event)"
-msgid "Jobs for last week"
-msgstr "上個星期的作業"
-
-msgid "Jobs for last year"
-msgstr "去年的作業"
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "åœç”¨"
@@ -522,6 +618,9 @@ msgstr "åœç”¨"
msgid "LFSStatus|Enabled"
msgstr "啟用"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "最近 %d 天"
@@ -536,10 +635,10 @@ msgid "Last commit"
msgstr "最後æ交"
msgid "LastPushEvent|You pushed to"
-msgstr ""
+msgstr "您推é€äº†"
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "在"
msgid "Learn more in the"
msgstr "了解更多"
@@ -553,22 +652,40 @@ msgstr "退出群組"
msgid "Leave project"
msgstr "退出項目"
+msgid "License"
+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 ""
+
msgid "Median"
msgstr "中ä½æ•¸"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
+msgstr "åˆä½µäº‹ä»¶ (merge event)"
+
+msgid "Messages"
msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "添加壹個 SSH 公鑰"
-msgid "More information is available|here"
+msgid "Monitoring"
msgstr ""
+msgid "More information is available|here"
+msgstr "幫助文檔"
+
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] "新建議題"
@@ -666,6 +783,9 @@ msgstr "åƒèˆ‡"
msgid "NotificationLevel|Watch"
msgstr "關注"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "篩é¸"
@@ -675,9 +795,15 @@ msgstr "開始於"
msgid "Options"
msgstr "æ“作"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "所有者"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "æµæ°´ç·š"
@@ -690,6 +816,9 @@ msgstr "æµæ°´ç·šè¨ˆåŠƒ"
msgid "Pipeline Schedules"
msgstr "æµæ°´ç·šè¨ˆåŠƒ"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "失敗:"
@@ -753,6 +882,15 @@ msgstr "æµæ°´ç·š"
msgid "Pipelines charts"
msgstr "æµæ°´ç·šåœ–表"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "所有"
@@ -765,9 +903,15 @@ msgstr "於階段"
msgid "Pipeline|with stages"
msgstr "於階段"
-msgid "Project"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
msgstr ""
+msgid "Project"
+msgstr "專案"
+
msgid "Project '%{project_name}' queued for deletion."
msgstr "項目 '%{project_name}' 已進入刪除隊列。"
@@ -784,7 +928,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 "無法刪除項目導出。"
@@ -801,9 +945,12 @@ msgstr "項目導出已開始。下載éˆæŽ¥å°‡é€šéŽé›»å­éƒµä»¶ç™¼é€ã€‚"
msgid "Project home"
msgstr "項目首é "
-msgid "ProjectActivityRSS|Subscribe"
+msgid "Project overview"
msgstr ""
+msgid "ProjectActivityRSS|Subscribe"
+msgstr "訂閱"
+
msgid "ProjectFeature|Disabled"
msgstr "åœç”¨"
@@ -825,9 +972,12 @@ msgstr "階段"
msgid "ProjectNetworkGraph|Graph"
msgstr "分支圖"
-msgid "Push events"
+msgid "Push Rules"
msgstr ""
+msgid "Push events"
+msgstr "推é€äº‹ä»¶ (push event) "
+
msgid "Read more"
msgstr "了解更多"
@@ -865,19 +1015,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 "還原此æ交"
@@ -885,6 +1035,9 @@ msgstr "還原此æ交"
msgid "Revert this merge request"
msgstr "還原此åˆä½µè«‹æ±‚"
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "ä¿å­˜æµæ°´ç·šè¨ˆåŠƒ"
@@ -904,11 +1057,14 @@ msgid "Select a timezone"
msgstr "é¸æ“‡æ™‚å€"
msgid "Select existing branch"
-msgstr ""
+msgstr "é¸æ“‡ç¾æœ‰åˆ†æ”¯ (branch)"
msgid "Select target branch"
msgstr "é¸æ“‡ç›®æ¨™åˆ†æ”¯"
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "為賬號添加壹個用於推é€æˆ–拉å–çš„ %{protocol} 密碼。"
@@ -924,16 +1080,25 @@ msgstr "設置自動部署"
msgid "SetPasswordToCloneLink|set a password"
msgstr "設置密碼"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "顯示 %d 個事件"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "æºä»£ç¢¼"
-msgid "Specify the following URL during the Runner setup:"
+msgid "Spam Logs"
msgstr ""
+msgid "Specify the following URL during the Runner setup:"
+msgstr "在 Runner 設置時指定以下 URL:"
+
msgid "StarProject|Star"
msgstr "星標"
@@ -941,7 +1106,7 @@ 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 "切æ›åˆ†æ”¯/標籤"
@@ -957,7 +1122,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 "編碼階段概述了從第壹次æ交到創建åˆä½µè«‹æ±‚的時間。創建第壹個åˆä½µè«‹æ±‚後,數據將自動添加到此處。"
@@ -1008,7 +1173,7 @@ 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 ""
+msgstr "è¨ªå• Git 存儲時出ç¾å•é¡Œï¼š"
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "在創建壹個空的存儲庫或導入ç¾æœ‰å­˜å„²åº«ä¹‹å‰ï¼Œæ‚¨å°‡ç„¡æ³•æŽ¨é€ä»£ç¢¼ã€‚"
@@ -1178,7 +1343,7 @@ msgid "UploadLink|click to upload"
msgstr "點擊上傳"
msgid "Use the following registration token during setup:"
-msgstr ""
+msgstr "在安è£éŽç¨‹ä¸­ä½¿ç”¨ä»¥ä¸‹è¨»å†Šä»¤ç‰Œï¼š"
msgid "Use your global notification setting"
msgstr "使用全局通知設置"
@@ -1204,6 +1369,9 @@ msgstr "權é™ä¸è¶³ã€‚如需查看相關數據,請å‘管ç†å“¡ç”³è«‹æ¬Šé™ã€‚
msgid "We don't have enough data to show this stage."
msgstr "該階段的數據ä¸è¶³ï¼Œç„¡æ³•é¡¯ç¤ºã€‚"
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "å–消權é™ç”³è¯·"
@@ -1267,4 +1435,5 @@ msgstr "通知郵件"
msgid "parent"
msgid_plural "parents"
-msgstr[0] "父級" \ No newline at end of file
+msgstr[0] "父級"
+
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index 1fc6b79187f..09c07a83d34 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-08-18 14:15+0530\n"
-"PO-Revision-Date: 2017-08-23 09:59-0400\n"
+"POT-Creation-Date: 2017-09-06 08:32+0200\n"
+"PO-Revision-Date: 2017-09-06 06:20-0400\n"
"Last-Translator: gitlab <mbartlett+crowdin@gitlab.com>\n"
"Language-Team: Chinese Traditional\n"
"Language: zh_TW\n"
@@ -28,20 +28,20 @@ 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."
-msgstr ""
+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 ""
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
-msgstr[0] ""
+msgstr[0] "%{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"
@@ -53,7 +53,16 @@ msgstr "æŒçºŒæ•´åˆ (CI) 相關的圖表"
msgid "About auto deploy"
msgstr "關於自動部署"
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
+msgstr "已暫時åœç”¨å¤±æ•—çš„ Git 儲存空間。當儲存空間æ¢å¾©æ­£å¸¸å¾Œï¼Œè«‹é‡ç½®å„²å­˜ç©ºé–“å¥åº·æŒ‡æ•¸ã€‚"
+
+msgid "Account"
msgstr ""
msgid "Active"
@@ -78,6 +87,12 @@ msgid "Add new directory"
msgstr "新增目錄"
msgid "All"
+msgstr "全部"
+
+msgid "Appearances"
+msgstr ""
+
+msgid "Applications"
msgstr ""
msgid "Archived project! Repository is read-only"
@@ -87,20 +102,77 @@ msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "確定è¦åˆªé™¤æ­¤æµæ°´ç·š (pipeline) 排程嗎?"
msgid "Are you sure you want to discard your changes?"
-msgstr ""
+msgstr "確定è¦æ”¾æ£„修改嗎?"
msgid "Are you sure you want to reset registration token?"
-msgstr ""
+msgstr "確定è¦é‡ç½®è¨»å†Šæ†‘è­‰ (registration token) 嗎?"
msgid "Are you sure you want to reset the health check token?"
-msgstr ""
+msgstr "確定è¦é‡ç½®å¥åº·æª¢æŸ¥å­˜å–憑證 (access token) 嗎?"
msgid "Are you sure?"
-msgstr ""
+msgstr "確定嗎?"
msgid "Attach a file by drag &amp; drop or %{upload_link}"
msgstr "拖放檔案到此處或者 %{upload_link}"
+msgid "Authentication log"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
+msgstr ""
+
+msgid "BillingPlans|Current plan"
+msgstr ""
+
+msgid "BillingPlans|Customer Support"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Please contact %{customer_support_link} in that case."
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|You are currently on the %{plan_link} plan."
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|paid annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "Billinglans|Downgrade"
+msgstr ""
+
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "分支 (branch) "
@@ -132,6 +204,9 @@ msgstr "ç€è¦½æª”案"
msgid "ByAuthor|by"
msgstr "作者:"
+msgid "CI / CD"
+msgstr ""
+
msgid "CI configuration"
msgstr "CI 組態"
@@ -139,7 +214,7 @@ msgid "Cancel"
msgstr "å–消"
msgid "Cancel edit"
-msgstr ""
+msgstr "å–消編輯"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "挑é¸åˆ°åˆ†æ”¯ (branch) "
@@ -159,6 +234,9 @@ msgstr "更新日誌"
msgid "Charts"
msgstr "統計圖"
+msgid "Chat"
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "挑é¸æ­¤æ›´å‹•è¨˜éŒ„ (commit) "
@@ -220,7 +298,7 @@ msgid "CiStatus|running"
msgstr "執行中"
msgid "Comments"
-msgstr ""
+msgstr "留言"
msgid "Commit"
msgid_plural "Commits"
@@ -253,12 +331,18 @@ msgstr "é€äº¤è€…為 "
msgid "Compare"
msgstr "比較"
+msgid "Container Registry"
+msgstr ""
+
msgid "Contribution guide"
msgstr "å”作指å—"
msgid "Contributors"
msgstr "å”作者"
+msgid "Copy SSH public key to clipboard"
+msgstr ""
+
msgid "Copy URL to clipboard"
msgstr "複製網å€åˆ°å‰ªè²¼ç°¿"
@@ -269,7 +353,7 @@ msgid "Create New Directory"
msgstr "建立新目錄"
msgid "Create a new branch"
-msgstr ""
+msgstr "建立新分支 (branch)"
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "建立個人存å–憑證 (access token) 以使用 %{protocol} 來上傳 (push) 或下載 (pull) 。"
@@ -344,17 +428,20 @@ msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] "部署"
+msgid "Deploy Keys"
+msgstr ""
+
msgid "Description"
msgstr "æè¿°"
msgid "Details"
-msgstr ""
+msgstr "細節"
msgid "Directory name"
msgstr "目錄å稱"
msgid "Discard changes"
-msgstr ""
+msgstr "放棄修改"
msgid "Don't show again"
msgstr "ä¸å†é¡¯ç¤º"
@@ -392,23 +479,26 @@ msgstr "編輯"
msgid "Edit Pipeline Schedule %{id}"
msgstr "編輯 %{id} æµæ°´ç·š (pipeline) 排程"
-msgid "EventFilterBy|Filter by all"
+msgid "Emails"
msgstr ""
+msgid "EventFilterBy|Filter by all"
+msgstr "顯示全部"
+
msgid "EventFilterBy|Filter by comments"
-msgstr ""
+msgstr "以留言篩é¸"
msgid "EventFilterBy|Filter by issue events"
-msgstr ""
+msgstr "以議題 (issue) 事件篩é¸"
msgid "EventFilterBy|Filter by merge events"
-msgstr ""
+msgstr "以åˆä½µ (merge) 事件篩é¸"
msgid "EventFilterBy|Filter by push events"
-msgstr ""
+msgstr "ä»¥æŽ¨é€ (push) 事件篩é¸"
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "以團隊篩é¸"
msgid "Every day (at 4:00am)"
msgstr "æ¯æ—¥åŸ·è¡Œï¼ˆæ·©æ™¨å››é»žï¼‰"
@@ -456,39 +546,51 @@ msgstr "從議題 (issue) 建立直到部署至營é‹ç’°å¢ƒ"
msgid "From merge request merge until deploy to production"
msgstr "從請求被åˆä½µå¾Œ (merge request merged) 直到部署至營é‹ç’°å¢ƒ"
-msgid "Git storage health information has been reset"
+msgid "GPG Keys"
msgstr ""
-msgid "GitLab Runner section"
+msgid "Geo Nodes"
msgstr ""
+msgid "Git storage health information has been reset"
+msgstr "Git 儲存空間å¥åº·æŒ‡æ•¸å·²é‡ç½®"
+
+msgid "GitLab Runner section"
+msgstr "GitLab Runner"
+
msgid "Go to your fork"
msgstr "å‰å¾€æ‚¨çš„分支 (fork) "
msgid "GoToYourFork|Fork"
msgstr "å‰å¾€æ‚¨çš„分支 (fork) "
-msgid "Health Check"
+msgid "Group overview"
msgstr ""
+msgid "Health Check"
+msgstr "å¥åº·æª¢æŸ¥"
+
msgid "Health information can be retrieved from the following endpoints. More information is available"
-msgstr ""
+msgstr "å¥åº·è³‡è¨Šå¯å¾žä»¥ä¸‹é€£çµå–得。想了解更多請åƒé–±"
msgid "HealthCheck|Access token is"
-msgstr ""
+msgstr "å­˜å–憑證 (access token) 是"
msgid "HealthCheck|Healthy"
-msgstr ""
+msgstr "å¥åº·"
msgid "HealthCheck|No Health Problems Detected"
-msgstr ""
+msgstr "沒有檢測到å¥åº·å•é¡Œ"
msgid "HealthCheck|Unhealthy"
-msgstr ""
+msgstr "ä¸è‰¯"
msgid "Home"
msgstr "首é "
+msgid "Hooks"
+msgstr ""
+
msgid "Housekeeping successfully started"
msgstr "已開始維護"
@@ -496,7 +598,7 @@ msgid "Import repository"
msgstr "匯入檔案庫 (repository)"
msgid "Install a Runner compatible with GitLab CI"
-msgstr ""
+msgstr "安è£èˆ‡ GitLab CI 相容的 Runner"
msgid "Interval Pattern"
msgstr "循環週期"
@@ -505,16 +607,10 @@ msgid "Introducing Cycle Analytics"
msgstr "週期分æžç°¡ä»‹"
msgid "Issue events"
-msgstr ""
-
-msgid "Jobs for last month"
-msgstr "上個月的任務 (job) "
+msgstr "議題 (issue) 事件"
-msgid "Jobs for last week"
-msgstr "上個星期的任務 (job) "
-
-msgid "Jobs for last year"
-msgstr "去年的任務 (job) "
+msgid "Issues"
+msgstr ""
msgid "LFSStatus|Disabled"
msgstr "åœç”¨"
@@ -522,6 +618,9 @@ msgstr "åœç”¨"
msgid "LFSStatus|Enabled"
msgstr "啟用"
+msgid "Labels"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "最近 %d 天"
@@ -536,10 +635,10 @@ msgid "Last commit"
msgstr "最後更動記錄 (commit) "
msgid "LastPushEvent|You pushed to"
-msgstr ""
+msgstr "您上傳 (push) 了"
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "æ–¼"
msgid "Learn more in the"
msgstr "了解更多"
@@ -553,22 +652,40 @@ msgstr "退出群組"
msgid "Leave project"
msgstr "退出專案"
+msgid "License"
+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 ""
+
msgid "Median"
msgstr "中ä½æ•¸"
+msgid "Members"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
msgid "Merge events"
+msgstr "åˆä½µ (merge) 事件"
+
+msgid "Messages"
msgstr ""
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "新增 SSH 金鑰"
-msgid "More information is available|here"
+msgid "Monitoring"
msgstr ""
+msgid "More information is available|here"
+msgstr "å¥åº·æª¢æŸ¥"
+
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] "建立議題 (issue) "
@@ -666,6 +783,9 @@ msgstr "åƒèˆ‡"
msgid "NotificationLevel|Watch"
msgstr "關注"
+msgid "Notifications"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "篩é¸"
@@ -675,9 +795,15 @@ msgstr "開始於"
msgid "Options"
msgstr "é¸é …"
+msgid "Overview"
+msgstr ""
+
msgid "Owner"
msgstr "所有權"
+msgid "Password"
+msgstr ""
+
msgid "Pipeline"
msgstr "æµæ°´ç·š (pipeline) "
@@ -690,6 +816,9 @@ msgstr "æµæ°´ç·š (pipeline) 排程"
msgid "Pipeline Schedules"
msgstr "æµæ°´ç·š (pipeline) 排程"
+msgid "Pipeline quota"
+msgstr ""
+
msgid "PipelineCharts|Failed:"
msgstr "失敗:"
@@ -753,6 +882,15 @@ msgstr "æµæ°´ç·š (pipeline) "
msgid "Pipelines charts"
msgstr "æµæ°´ç·š (pipeline) 圖表"
+msgid "Pipelines for last month"
+msgstr ""
+
+msgid "Pipelines for last week"
+msgstr ""
+
+msgid "Pipelines for last year"
+msgstr ""
+
msgid "Pipeline|all"
msgstr "所有"
@@ -765,9 +903,15 @@ msgstr "於階段"
msgid "Pipeline|with stages"
msgstr "於階段"
-msgid "Project"
+msgid "Preferences"
+msgstr ""
+
+msgid "Profile Settings"
msgstr ""
+msgid "Project"
+msgstr "專案"
+
msgid "Project '%{project_name}' queued for deletion."
msgstr "專案 '%{project_name}' 已加入刪除佇列。"
@@ -784,7 +928,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 "匯出的專案無法被刪除。"
@@ -801,9 +945,12 @@ msgstr "專案導出已開始。完æˆå¾Œä¸‹è¼‰é€£çµæœƒé€åˆ°æ‚¨çš„信箱。"
msgid "Project home"
msgstr "專案首é "
-msgid "ProjectActivityRSS|Subscribe"
+msgid "Project overview"
msgstr ""
+msgid "ProjectActivityRSS|Subscribe"
+msgstr "訂閱"
+
msgid "ProjectFeature|Disabled"
msgstr "åœç”¨"
@@ -825,9 +972,12 @@ msgstr "階段"
msgid "ProjectNetworkGraph|Graph"
msgstr "分支圖"
-msgid "Push events"
+msgid "Push Rules"
msgstr ""
+msgid "Push events"
+msgstr "æŽ¨é€ (push) 事件"
+
msgid "Read more"
msgstr "瞭解更多"
@@ -865,19 +1015,19 @@ msgid "Remove project"
msgstr "刪除專案"
msgid "Repository"
-msgstr ""
+msgstr "檔案庫 (repository)"
msgid "Request Access"
msgstr "申請權é™"
msgid "Reset git storage health information"
-msgstr ""
+msgstr "é‡ç½® Git 儲存空間å¥åº·æŒ‡æ•¸"
msgid "Reset health check access token"
-msgstr ""
+msgstr "é‡ç½®å¥åº·æª¢æŸ¥å­˜å–憑證 (access token)"
msgid "Reset runners registration token"
-msgstr ""
+msgstr "é‡ç½® Runner 註冊憑證 (registration token)"
msgid "Revert this commit"
msgstr "還原此更動記錄 (commit)"
@@ -885,6 +1035,9 @@ msgstr "還原此更動記錄 (commit)"
msgid "Revert this merge request"
msgstr "還原此åˆä½µè«‹æ±‚ (merge request) "
+msgid "SSH Keys"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr "儲存æµæ°´ç·š (pipeline) 排程"
@@ -904,11 +1057,14 @@ msgid "Select a timezone"
msgstr "é¸æ“‡æ™‚å€"
msgid "Select existing branch"
-msgstr ""
+msgstr "é¸æ“‡ç¾æœ‰åˆ†æ”¯ (branch)"
msgid "Select target branch"
msgstr "é¸æ“‡ç›®æ¨™åˆ†æ”¯ (branch) "
+msgid "Service Templates"
+msgstr ""
+
msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "請先設定密碼,æ‰èƒ½ä½¿ç”¨ %{protocol} 來上傳 (push) 或下載 (pull) 。"
@@ -924,16 +1080,25 @@ msgstr "設定自動部署"
msgid "SetPasswordToCloneLink|set a password"
msgstr "設定密碼"
+msgid "Settings"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "顯示 %d 個事件"
+msgid "Snippets"
+msgstr ""
+
msgid "Source code"
msgstr "原始碼"
-msgid "Specify the following URL during the Runner setup:"
+msgid "Spam Logs"
msgstr ""
+msgid "Specify the following URL during the Runner setup:"
+msgstr "åœ¨å®‰è£ Runner 時指定以下 URL:"
+
msgid "StarProject|Star"
msgstr "收è—"
@@ -941,7 +1106,7 @@ 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 "切æ›åˆ†æ”¯ (branch) 或標籤"
@@ -957,7 +1122,7 @@ msgid "Target Branch"
msgstr "目標分支 (branch) "
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 "程å¼é–‹ç™¼éšŽæ®µé¡¯ç¤ºå¾žç¬¬ä¸€æ¬¡æ›´å‹•è¨˜éŒ„ (commit) 到建立åˆä½µè«‹æ±‚ (merge request) 的時間。建立第一個åˆä½µè«‹æ±‚後,資料將自動填入。"
@@ -1008,7 +1173,7 @@ 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 ""
+msgstr "å­˜å– Git 儲存空間時出ç¾å•é¡Œï¼š"
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "這代表在您建立一個空的檔案庫 (repository) 或是匯入一個ç¾å­˜çš„檔案庫之å‰ï¼Œæ‚¨å°‡ç„¡æ³•ä¸Šå‚³æ›´æ–° (push) 。"
@@ -1178,7 +1343,7 @@ msgid "UploadLink|click to upload"
msgstr "點擊上傳"
msgid "Use the following registration token during setup:"
-msgstr ""
+msgstr "在安è£éŽç¨‹ä¸­ä½¿ç”¨æ­¤è¨»å†Šæ†‘è­‰ (registration token):"
msgid "Use your global notification setting"
msgstr "使用全域通知設定"
@@ -1204,14 +1369,17 @@ msgstr "權é™ä¸è¶³ã€‚如需查看相關資料,請å‘管ç†å“¡ç”³è«‹æ¬Šé™ã€‚
msgid "We don't have enough data to show this stage."
msgstr "因該階段的資料ä¸è¶³è€Œç„¡æ³•é¡¯ç¤ºç›¸é—œè³‡è¨Š"
+msgid "Wiki"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "å–消權é™ç”³è«‹"
msgid "You are going to remove %{group_name}. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
-msgstr "å³å°‡è¦åˆªé™¤ %{group_name}。被刪除的群組無法復原ï¼çœŸçš„「確定ã€è¦é€™éº¼åšå—Žï¼Ÿ"
+msgstr "å°‡è¦åˆªé™¤ %{group_name}。被刪除的群組無法復原ï¼çœŸçš„「確定ã€è¦é€™éº¼åšå—Žï¼Ÿ"
msgid "You are going to remove %{project_name_with_namespace}. Removed project CANNOT be restored! Are you ABSOLUTELY sure?"
-msgstr "å³å°‡è¦åˆªé™¤ %{project_name_with_namespace}。被刪除的專案無法復原ï¼çœŸçš„「確定ã€è¦é€™éº¼åšå—Žï¼Ÿ"
+msgstr "å°‡è¦åˆªé™¤ %{project_name_with_namespace}。被刪除的專案無法復原ï¼çœŸçš„「確定ã€è¦é€™éº¼åšå—Žï¼Ÿ"
msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
msgstr "å°‡è¦åˆªé™¤æœ¬åˆ†æ”¯å°ˆæ¡ˆèˆ‡ä¸»å¹¹ %{forked_from_project} 的所有關è¯ã€‚ 真的「確定ã€è¦é€™éº¼åšå—Žï¼Ÿ"
@@ -1267,4 +1435,5 @@ msgstr "通知信"
msgid "parent"
msgid_plural "parents"
-msgstr[0] "上層" \ No newline at end of file
+msgstr[0] "上層"
+
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
index 9d60dab12d1..b52b63e05a4 100644
--- a/spec/controllers/profiles_controller_spec.rb
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -16,7 +16,11 @@ describe ProfilesController do
end
it "ignores an email update from a user with an external email address" do
- ldap_user = create(:omniauth_user, external_email: true)
+ stub_omniauth_setting(sync_profile_from_provider: ['ldap'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+
+ ldap_user = create(:omniauth_user)
+ ldap_user.create_user_synced_attributes_metadata(provider: 'ldap', name_synced: true, email_synced: true)
sign_in(ldap_user)
put :update,
@@ -27,5 +31,24 @@ describe ProfilesController do
expect(response.status).to eq(302)
expect(ldap_user.unconfirmed_email).not_to eq('john@gmail.com')
end
+
+ it "ignores an email and name update but allows a location update from a user with external email and name, but not external location" do
+ stub_omniauth_setting(sync_profile_from_provider: ['ldap'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+
+ ldap_user = create(:omniauth_user, name: 'Alex')
+ ldap_user.create_user_synced_attributes_metadata(provider: 'ldap', name_synced: true, email_synced: true, location_synced: false)
+ sign_in(ldap_user)
+
+ put :update,
+ user: { email: "john@gmail.com", name: "John", location: "City, Country" }
+
+ ldap_user.reload
+
+ expect(response.status).to eq(302)
+ expect(ldap_user.unconfirmed_email).not_to eq('john@gmail.com')
+ expect(ldap_user.name).not_to eq('John')
+ expect(ldap_user.location).to eq('City, Country')
+ end
end
end
diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb
index d2c613a2423..caa63e7bd22 100644
--- a/spec/controllers/projects/artifacts_controller_spec.rb
+++ b/spec/controllers/projects/artifacts_controller_spec.rb
@@ -81,14 +81,6 @@ describe Projects::ArtifactsController do
expect(params['Entry']).to eq(Base64.encode64('ci_artifacts.txt'))
end
end
-
- context 'when the file does not exist' do
- it 'responds Not Found' do
- get :raw, namespace_id: project.namespace, project_id: project, job_id: job, path: 'unknown'
-
- expect(response).to be_not_found
- end
- end
end
describe 'GET latest_succeeded' do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index bb67db268fa..6775012bab5 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -56,6 +56,28 @@ describe Projects::MergeRequestsController do
expect(response).to be_success
end
+
+ context "loads notes" do
+ let(:first_contributor) { create(:user) }
+ let(:contributor) { create(:user) }
+ let(:merge_request) { create(:merge_request, author: first_contributor, target_project: project, source_project: project) }
+ let(:contributor_merge_request) { create(:merge_request, :merged, author: contributor, target_project: project, source_project: project) }
+ # the order here is important
+ # as the controller reloads these from DB, references doesn't correspond after
+ let!(:first_contributor_note) { create(:note, author: first_contributor, noteable: merge_request, project: project) }
+ let!(:contributor_note) { create(:note, author: contributor, noteable: merge_request, project: project) }
+ let!(:owner_note) { create(:note, author: user, noteable: merge_request, project: project) }
+
+ it "with special_role FIRST_TIME_CONTRIBUTOR" do
+ go(format: :html)
+
+ notes = assigns(:notes)
+ expect(notes).to match(a_collection_containing_exactly(an_object_having_attributes(special_role: Note::SpecialRole::FIRST_TIME_CONTRIBUTOR),
+ an_object_having_attributes(special_role: nil),
+ an_object_having_attributes(special_role: nil)
+ ))
+ end
+ end
end
describe 'as json' do
diff --git a/spec/features/admin/admin_browses_logs_spec.rb b/spec/features/admin/admin_browses_logs_spec.rb
index 3e3404dfdac..02f50d7e27f 100644
--- a/spec/features/admin/admin_browses_logs_spec.rb
+++ b/spec/features/admin/admin_browses_logs_spec.rb
@@ -8,8 +8,10 @@ describe 'Admin browses logs' do
it 'shows available log files' do
visit admin_logs_path
- expect(page).to have_content 'test.log'
- expect(page).to have_content 'githost.log'
- expect(page).to have_content 'application.log'
+ expect(page).to have_link 'application.log'
+ expect(page).to have_link 'githost.log'
+ expect(page).to have_link 'test.log'
+ expect(page).to have_link 'sidekiq.log'
+ expect(page).to have_link 'repocheck.log'
end
end
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 4297bfff3d9..2db6f9a2982 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -166,12 +166,10 @@ describe 'New/edit issue', :js do
end
end
- page.within '.issuable-meta' do
+ page.within '.breadcrumbs' do
issue = Issue.find_by(title: 'title')
- expect(page).to have_text("Issue #{issue.to_reference}")
- # compare paths because the host differ in test
- expect(find_link(issue.to_reference)[:href]).to end_with(issue_path(issue))
+ expect(page).to have_text("Issues #{issue.to_reference}")
end
end
diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb
index e77f1f92731..ca536f2800c 100644
--- a/spec/features/merge_requests/diff_notes_avatars_spec.rb
+++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb
@@ -139,7 +139,7 @@ feature 'Diff note avatars', js: true do
end
page.within find("[id='#{position.line_code(project.repository)}']") do
- find('.diff-notes-collapse').click
+ find('.diff-notes-collapse').trigger('click')
expect(page).to have_selector('img.js-diff-comment-avatar', count: 2)
end
@@ -152,7 +152,7 @@ feature 'Diff note avatars', js: true do
page.within '.js-discussion-note-form' do
find('.js-note-text').native.send_keys('Test')
- find('.js-comment-button').trigger 'click'
+ find('.js-comment-button').trigger('click')
wait_for_requests
end
diff --git a/spec/features/merge_requests/form_spec.rb b/spec/features/merge_requests/form_spec.rb
index 89410b0e90f..de98b147d04 100644
--- a/spec/features/merge_requests/form_spec.rb
+++ b/spec/features/merge_requests/form_spec.rb
@@ -84,13 +84,10 @@ describe 'New/edit merge request', :js do
end
end
- page.within '.issuable-meta' do
+ page.within '.breadcrumbs' do
merge_request = MergeRequest.find_by(source_branch: 'fix')
- expect(page).to have_text("Merge request #{merge_request.to_reference}")
- # compare paths because the host differ in test
- expect(find_link(merge_request.to_reference)[:href])
- .to end_with(merge_request_path(merge_request))
+ expect(page).to have_text("Merge Requests #{merge_request.to_reference}")
end
end
diff --git a/spec/features/merge_requests/resolve_outdated_diff_discussions.rb b/spec/features/merge_requests/resolve_outdated_diff_discussions.rb
new file mode 100644
index 00000000000..55a82bdf2b9
--- /dev/null
+++ b/spec/features/merge_requests/resolve_outdated_diff_discussions.rb
@@ -0,0 +1,78 @@
+require 'spec_helper'
+
+feature 'Resolve outdated diff discussions', js: true do
+ let(:project) { create(:project, :repository, :public) }
+
+ let(:merge_request) do
+ create(:merge_request, source_project: project, source_branch: 'csv', target_branch: 'master')
+ end
+
+ let(:outdated_diff_refs) { project.commit('926c6595b263b2a40da6b17f3e3b7ea08344fad6').diff_refs }
+ let(:current_diff_refs) { merge_request.diff_refs }
+
+ let(:outdated_position) do
+ Gitlab::Diff::Position.new(
+ old_path: 'files/csv/Book1.csv',
+ new_path: 'files/csv/Book1.csv',
+ old_line: nil,
+ new_line: 9,
+ diff_refs: outdated_diff_refs
+ )
+ end
+
+ let(:current_position) do
+ Gitlab::Diff::Position.new(
+ old_path: 'files/csv/Book1.csv',
+ new_path: 'files/csv/Book1.csv',
+ old_line: nil,
+ new_line: 1,
+ diff_refs: current_diff_refs
+ )
+ end
+
+ let!(:outdated_discussion) do
+ create(:diff_note_on_merge_request,
+ project: project,
+ noteable: merge_request,
+ position: outdated_position).to_discussion
+ end
+
+ let!(:current_discussion) do
+ create(:diff_note_on_merge_request,
+ noteable: merge_request,
+ project: project,
+ position: current_position).to_discussion
+ end
+
+ before do
+ sign_in(merge_request.author)
+ end
+
+ context 'when a discussion was resolved by a push' do
+ before do
+ project.update!(resolve_outdated_diff_discussions: true)
+
+ merge_request.update_diff_discussion_positions(
+ old_diff_refs: outdated_diff_refs,
+ new_diff_refs: current_diff_refs,
+ current_user: merge_request.author
+ )
+
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'shows that as automatically resolved' do
+ within(".discussion[data-discussion-id='#{outdated_discussion.id}']") do
+ expect(page).to have_css('.discussion-body', visible: false)
+ expect(page).to have_content('Automatically resolved')
+ end
+ end
+
+ it 'does not show that for active discussions' do
+ within(".discussion[data-discussion-id='#{current_discussion.id}']") do
+ expect(page).to have_css('.discussion-body', visible: true)
+ expect(page).not_to have_content('Automatically resolved')
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/sub_group_issuables_spec.rb b/spec/features/projects/sub_group_issuables_spec.rb
index b2b39dbd24c..eb2d3ff50a0 100644
--- a/spec/features/projects/sub_group_issuables_spec.rb
+++ b/spec/features/projects/sub_group_issuables_spec.rb
@@ -26,7 +26,6 @@ describe 'Subgroup Issuables', :js, :nested_groups do
def expect_to_have_full_subgroup_title
title = find('.breadcrumbs-links')
- expect(title).not_to have_selector '.initializing'
- expect(title).to have_content 'group / subgroup / project'
+ expect(title).to have_content 'group subgroup project'
end
end
diff --git a/spec/helpers/blame_helper_spec.rb b/spec/helpers/blame_helper_spec.rb
index b4368516d83..722d21c566f 100644
--- a/spec/helpers/blame_helper_spec.rb
+++ b/spec/helpers/blame_helper_spec.rb
@@ -35,25 +35,32 @@ describe BlameHelper do
end
describe '#age_map_class' do
- let(:dates) do
- [Time.zone.local(2014, 3, 17, 0, 0, 0)]
- end
- let(:blame_groups) do
- [
- { commit: double(committed_date: dates[0]) }
- ]
- end
+ let(:date) { Time.zone.local(2014, 3, 17, 0, 0, 0) }
+ let(:blame_groups) { [{ commit: double(committed_date: date) }] }
let(:duration) do
- project = double(created_at: dates[0])
+ project = double(created_at: date)
helper.age_map_duration(blame_groups, project)
end
it 'returns blame-commit-age-9 when oldest' do
- expect(helper.age_map_class(dates[0], duration)).to eq 'blame-commit-age-9'
+ expect(helper.age_map_class(date, duration)).to eq 'blame-commit-age-9'
end
it 'returns blame-commit-age-0 class when newest' do
expect(helper.age_map_class(duration[:now], duration)).to eq 'blame-commit-age-0'
end
+
+ context 'when called on the same day as project creation' do
+ let(:same_day_duration) do
+ project = double(created_at: now)
+ helper.age_map_duration(today_blame_groups, project)
+ end
+ let(:today_blame_groups) { [{ commit: double(committed_date: now) }] }
+ let(:now) { Time.zone.now }
+
+ it 'returns blame-commit-age-0 class' do
+ expect(helper.age_map_class(duration[:now], same_day_duration)).to eq 'blame-commit-age-0'
+ end
+ end
end
end
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 9d6e03e3868..05f969904f5 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -91,7 +91,8 @@ describe GroupsHelper do
let!(:very_deep_nested_group) { create(:group, parent: deep_nested_group) }
it 'outputs the groups in the correct order' do
- expect(helper.group_title(very_deep_nested_group)).to match(/>#{group.name}<\/a>.*>#{nested_group.name}<\/a>.*>#{deep_nested_group.name}<\/a>/)
+ expect(helper.group_title(very_deep_nested_group))
+ .to match(/<li style="text-indent: 16px;"><a.*>#{deep_nested_group.name}.*<\/li>.*<a.*>#{very_deep_nested_group.name}<\/a>/m)
end
end
end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 70eb01c9c44..03d706062b7 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -52,12 +52,71 @@ describe MarkupHelper do
end
end
- describe '#link_to_gfm' do
+ describe '#markdown_field' do
+ let(:attribute) { :title }
+
+ describe 'with already redacted attribute' do
+ it 'returns the redacted attribute' do
+ commit.redacted_title_html = 'commit title'
+
+ expect(Banzai).not_to receive(:render_field)
+
+ expect(helper.markdown_field(commit, attribute)).to eq('commit title')
+ end
+ end
+
+ describe 'without redacted attribute' do
+ it 'renders the markdown value' do
+ expect(Banzai).to receive(:render_field).with(commit, attribute).and_call_original
+
+ helper.markdown_field(commit, attribute)
+ end
+ end
+ end
+
+ describe '#link_to_markdown_field' do
+ let(:link) { '/commits/0a1b2c3d' }
+ let(:issues) { create_list(:issue, 2, project: project) }
+
+ it 'handles references nested in links with all the text' do
+ allow(commit).to receive(:title).and_return("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real")
+
+ actual = helper.link_to_markdown_field(commit, :title, link)
+ doc = Nokogiri::HTML.parse(actual)
+
+ # Make sure we didn't create invalid markup
+ expect(doc.errors).to be_empty
+
+ # Leading commit link
+ expect(doc.css('a')[0].attr('href')).to eq link
+ expect(doc.css('a')[0].text).to eq 'This should finally fix '
+
+ # First issue link
+ expect(doc.css('a')[1].attr('href'))
+ .to eq project_issue_path(project, issues[0])
+ expect(doc.css('a')[1].text).to eq issues[0].to_reference
+
+ # Internal commit link
+ expect(doc.css('a')[2].attr('href')).to eq link
+ expect(doc.css('a')[2].text).to eq ' and '
+
+ # Second issue link
+ expect(doc.css('a')[3].attr('href'))
+ .to eq project_issue_path(project, issues[1])
+ expect(doc.css('a')[3].text).to eq issues[1].to_reference
+
+ # Trailing commit link
+ expect(doc.css('a')[4].attr('href')).to eq link
+ expect(doc.css('a')[4].text).to eq ' for real'
+ end
+ end
+
+ describe '#link_to_markdown' do
let(:link) { '/commits/0a1b2c3d' }
let(:issues) { create_list(:issue, 2, project: project) }
it 'handles references nested in links with all the text' do
- actual = helper.link_to_gfm("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", link)
+ actual = helper.link_to_markdown("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", link)
doc = Nokogiri::HTML.parse(actual)
# Make sure we didn't create invalid markup
@@ -87,7 +146,7 @@ describe MarkupHelper do
end
it 'forwards HTML options' do
- actual = helper.link_to_gfm("Fixed in #{commit.id}", link, class: 'foo')
+ actual = helper.link_to_markdown("Fixed in #{commit.id}", link, class: 'foo')
doc = Nokogiri::HTML.parse(actual)
expect(doc.css('a')).to satisfy do |v|
@@ -98,23 +157,43 @@ describe MarkupHelper do
it "escapes HTML passed in as the body" do
actual = "This is a <h1>test</h1> - see #{issues[0].to_reference}"
- expect(helper.link_to_gfm(actual, link))
+ expect(helper.link_to_markdown(actual, link))
.to match('&lt;h1&gt;test&lt;/h1&gt;')
end
it 'ignores reference links when they are the entire body' do
text = issues[0].to_reference
- act = helper.link_to_gfm(text, '/foo')
+ act = helper.link_to_markdown(text, '/foo')
expect(act).to eq %Q(<a href="/foo">#{issues[0].to_reference}</a>)
end
it 'replaces commit message with emoji to link' do
- actual = link_to_gfm(':book: Book', '/foo')
+ actual = link_to_markdown(':book: Book', '/foo')
expect(actual)
.to eq '<gl-emoji title="open book" data-name="book" data-unicode-version="6.0">📖</gl-emoji><a href="/foo"> Book</a>'
end
end
+ describe '#link_to_html' do
+ it 'wraps the rendered content in a link' do
+ link = '/commits/0a1b2c3d'
+ issue = create(:issue, project: project)
+
+ rendered = helper.markdown("This should finally fix #{issue.to_reference} for real", pipeline: :single_line)
+ doc = Nokogiri::HTML.parse(rendered)
+
+ expect(doc.css('a')[0].attr('href'))
+ .to eq project_issue_path(project, issue)
+ expect(doc.css('a')[0].text).to eq issue.to_reference
+
+ wrapped = helper.link_to_html(rendered, link)
+ doc = Nokogiri::HTML.parse(wrapped)
+
+ expect(doc.css('a')[0].attr('href')).to eq link
+ expect(doc.css('a')[0].text).to eq 'This should finally fix '
+ end
+ end
+
describe '#render_wiki_content' do
before do
@wiki = double('WikiPage')
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index 9921ca1af33..cd15e27b497 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -23,10 +23,10 @@ describe NotesHelper do
end
describe "#notes_max_access_for_users" do
- it 'returns human access levels' do
- expect(helper.note_max_access_for_user(owner_note)).to eq('Owner')
- expect(helper.note_max_access_for_user(master_note)).to eq('Master')
- expect(helper.note_max_access_for_user(reporter_note)).to eq('Reporter')
+ it 'returns access levels' do
+ expect(helper.note_max_access_for_user(owner_note)).to eq(Gitlab::Access::OWNER)
+ expect(helper.note_max_access_for_user(master_note)).to eq(Gitlab::Access::MASTER)
+ expect(helper.note_max_access_for_user(reporter_note)).to eq(Gitlab::Access::REPORTER)
end
it 'handles access in different projects' do
@@ -34,8 +34,8 @@ describe NotesHelper do
second_project.team << [master, :reporter]
other_note = create(:note, author: master, project: second_project)
- expect(helper.note_max_access_for_user(master_note)).to eq('Master')
- expect(helper.note_max_access_for_user(other_note)).to eq('Reporter')
+ expect(helper.note_max_access_for_user(master_note)).to eq(Gitlab::Access::MASTER)
+ expect(helper.note_max_access_for_user(other_note)).to eq(Gitlab::Access::REPORTER)
end
end
@@ -231,7 +231,7 @@ describe NotesHelper do
end
end
- describe '#form_resurces' do
+ describe '#form_resources' do
it 'returns note for personal snippet' do
@snippet = create(:personal_snippet)
@note = create(:note_on_personal_snippet)
@@ -266,4 +266,22 @@ describe NotesHelper do
expect(noteable_note_url(note)).to match("/#{project.namespace.path}/#{project.path}/issues/#{issue.iid}##{dom_id(note)}")
end
end
+
+ describe '#discussion_resolved_intro' do
+ context 'when the discussion was resolved by a push' do
+ let(:discussion) { double(:discussion, resolved_by_push?: true) }
+
+ it 'returns "Automatically resolved"' do
+ expect(discussion_resolved_intro(discussion)).to eq('Automatically resolved')
+ end
+ end
+
+ context 'when the discussion was not resolved by a push' do
+ let(:discussion) { double(:discussion, resolved_by_push?: false) }
+
+ it 'returns "Resolved"' do
+ expect(discussion_resolved_intro(discussion)).to eq('Resolved')
+ end
+ end
+ end
end
diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb
index b33b3f3a228..c1d0614c79e 100644
--- a/spec/helpers/profiles_helper_spec.rb
+++ b/spec/helpers/profiles_helper_spec.rb
@@ -6,22 +6,41 @@ describe ProfilesHelper do
user = create(:user)
allow(helper).to receive(:current_user).and_return(user)
- expect(helper.email_provider_label).to be_nil
+ expect(helper.attribute_provider_label(:email)).to be_nil
end
- it "returns omniauth provider label for users with external email" do
+ it "returns omniauth provider label for users with external attributes" do
+ stub_omniauth_setting(sync_profile_from_provider: ['cas3'])
+ stub_omniauth_setting(sync_profile_attributes: true)
stub_cas_omniauth_provider
- cas_user = create(:omniauth_user, provider: 'cas3', external_email: true, email_provider: 'cas3')
+ cas_user = create(:omniauth_user, provider: 'cas3')
+ cas_user.create_user_synced_attributes_metadata(provider: 'cas3', name_synced: true, email_synced: true, location_synced: true)
allow(helper).to receive(:current_user).and_return(cas_user)
- expect(helper.email_provider_label).to eq('CAS')
+ expect(helper.attribute_provider_label(:email)).to eq('CAS')
+ expect(helper.attribute_provider_label(:name)).to eq('CAS')
+ expect(helper.attribute_provider_label(:location)).to eq('CAS')
+ end
+
+ it "returns the correct omniauth provider label for users with some external attributes" do
+ stub_omniauth_setting(sync_profile_from_provider: ['cas3'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+ stub_cas_omniauth_provider
+ cas_user = create(:omniauth_user, provider: 'cas3')
+ cas_user.create_user_synced_attributes_metadata(provider: 'cas3', name_synced: false, email_synced: true, location_synced: false)
+ allow(helper).to receive(:current_user).and_return(cas_user)
+
+ expect(helper.attribute_provider_label(:name)).to be_nil
+ expect(helper.attribute_provider_label(:email)).to eq('CAS')
+ expect(helper.attribute_provider_label(:location)).to be_nil
end
it "returns 'LDAP' for users with external email but no email provider" do
- ldap_user = create(:omniauth_user, external_email: true)
+ ldap_user = create(:omniauth_user)
+ ldap_user.create_user_synced_attributes_metadata(email_synced: true)
allow(helper).to receive(:current_user).and_return(ldap_user)
- expect(helper.email_provider_label).to eq('LDAP')
+ expect(helper.attribute_provider_label(:email)).to eq('LDAP')
end
end
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 463af15930d..ab647401e14 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -17,7 +17,7 @@ describe SearchHelper do
end
end
- context "with a user" do
+ context "with a standard user" do
let(:user) { create(:user) }
before do
@@ -29,7 +29,11 @@ describe SearchHelper do
end
it "includes default sections" do
- expect(search_autocomplete_opts("adm").size).to eq(1)
+ expect(search_autocomplete_opts("dash").size).to eq(1)
+ end
+
+ it "does not include admin sections" do
+ expect(search_autocomplete_opts("admin").size).to eq(0)
end
it "does not allow regular expression in search term" do
@@ -67,6 +71,18 @@ describe SearchHelper do
end
end
end
+
+ context 'with an admin user' do
+ let(:admin) { create(:admin) }
+
+ before do
+ allow(self).to receive(:current_user).and_return(admin)
+ end
+
+ it "includes admin sections" do
+ expect(search_autocomplete_opts("admin").size).to eq(1)
+ end
+ end
end
describe 'search_filter_input_options' do
diff --git a/spec/lib/banzai/commit_renderer_spec.rb b/spec/lib/banzai/commit_renderer_spec.rb
new file mode 100644
index 00000000000..049d025a5b9
--- /dev/null
+++ b/spec/lib/banzai/commit_renderer_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Banzai::CommitRenderer do
+ describe '.render' do
+ it 'renders a commit description and title' do
+ user = double(:user)
+ project = create(:project, :repository)
+
+ expect(Banzai::ObjectRenderer).to receive(:new).with(project, user).and_call_original
+
+ described_class::ATTRIBUTES.each do |attr|
+ expect_any_instance_of(Banzai::ObjectRenderer).to receive(:render).with([project.commit], attr).once.and_call_original
+ expect(Banzai::Renderer).to receive(:cacheless_render_field).with(project.commit, attr)
+ end
+
+ described_class.render([project.commit], project, user)
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
index ff6b19459bb..85eddde732e 100644
--- a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
+++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
@@ -96,5 +96,41 @@ describe Banzai::Filter::TableOfContentsFilter do
expect(links.last.attr('href')).to eq '#header-2'
expect(links.last.text).to eq 'Header 2'
end
+
+ context 'table of contents nesting' do
+ let(:results) do
+ result(
+ header(1, 'Header 1') <<
+ header(2, 'Header 1-1') <<
+ header(3, 'Header 1-1-1') <<
+ header(2, 'Header 1-2') <<
+ header(1, 'Header 2') <<
+ header(2, 'Header 2-1')
+ )
+ end
+
+ it 'keeps list levels regarding header levels' do
+ items = doc.css('li')
+
+ # Header 1
+ expect(items[0].ancestors).to satisfy_none { |node| node.name == 'li' }
+
+ # Header 1-1
+ expect(items[1].ancestors).to include(items[0])
+
+ # Header 1-1-1
+ expect(items[2].ancestors).to include(items[0], items[1])
+
+ # Header 1-2
+ expect(items[3].ancestors).to include(items[0])
+ expect(items[3].ancestors).not_to include(items[1])
+
+ # Header 2
+ expect(items[4].ancestors).to satisfy_none { |node| node.name == 'li' }
+
+ # Header 2-1
+ expect(items[5].ancestors).to include(items[4])
+ end
+ end
end
end
diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb
index 7f5d481c36c..b172a1b718c 100644
--- a/spec/lib/banzai/object_renderer_spec.rb
+++ b/spec/lib/banzai/object_renderer_spec.rb
@@ -1,53 +1,77 @@
require 'spec_helper'
describe Banzai::ObjectRenderer do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { project.owner }
let(:renderer) { described_class.new(project, user, custom_value: 'value') }
let(:object) { Note.new(note: 'hello', note_html: '<p dir="auto">hello</p>', cached_markdown_version: CacheMarkdownField::CACHE_VERSION) }
describe '#render' do
- it 'renders and redacts an Array of objects' do
- renderer.render([object], :note)
+ context 'with cache' do
+ it 'renders and redacts an Array of objects' do
+ renderer.render([object], :note)
- expect(object.redacted_note_html).to eq '<p dir="auto">hello</p>'
- expect(object.user_visible_reference_count).to eq 0
- end
+ expect(object.redacted_note_html).to eq '<p dir="auto">hello</p>'
+ expect(object.user_visible_reference_count).to eq 0
+ end
- it 'calls Banzai::Redactor to perform redaction' do
- expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original
+ it 'calls Banzai::Redactor to perform redaction' do
+ expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original
- renderer.render([object], :note)
- end
+ renderer.render([object], :note)
+ end
- it 'retrieves field content using Banzai.render_field' do
- expect(Banzai).to receive(:render_field).with(object, :note).and_call_original
+ it 'retrieves field content using Banzai::Renderer.render_field' do
+ expect(Banzai::Renderer).to receive(:render_field).with(object, :note).and_call_original
- renderer.render([object], :note)
- end
+ renderer.render([object], :note)
+ end
- it 'passes context to PostProcessPipeline' do
- another_user = create(:user)
- another_project = create(:project)
- object = Note.new(
- note: 'hello',
- note_html: 'hello',
- author: another_user,
- project: another_project
- )
-
- expect(Banzai::Pipeline::PostProcessPipeline).to receive(:to_document).with(
- anything,
- hash_including(
- skip_redaction: true,
- current_user: user,
- project: another_project,
+ it 'passes context to PostProcessPipeline' do
+ another_user = create(:user)
+ another_project = create(:project)
+ object = Note.new(
+ note: 'hello',
+ note_html: 'hello',
author: another_user,
- custom_value: 'value'
+ project: another_project
)
- ).and_call_original
- renderer.render([object], :note)
+ expect(Banzai::Pipeline::PostProcessPipeline).to receive(:to_document).with(
+ anything,
+ hash_including(
+ skip_redaction: true,
+ current_user: user,
+ project: another_project,
+ author: another_user,
+ custom_value: 'value'
+ )
+ ).and_call_original
+
+ renderer.render([object], :note)
+ end
+ end
+
+ context 'without cache' do
+ let(:commit) { project.commit }
+
+ it 'renders and redacts an Array of objects' do
+ renderer.render([commit], :title)
+
+ expect(commit.redacted_title_html).to eq("Merge branch 'branch-merged' into 'master'")
+ end
+
+ it 'calls Banzai::Redactor to perform redaction' do
+ expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original
+
+ renderer.render([commit], :title)
+ end
+
+ it 'retrieves field content using Banzai::Renderer.cacheless_render_field' do
+ expect(Banzai::Renderer).to receive(:cacheless_render_field).with(commit, :title).and_call_original
+
+ renderer.render([commit], :title)
+ end
end
end
end
diff --git a/spec/lib/banzai/renderer_spec.rb b/spec/lib/banzai/renderer_spec.rb
index 0e094405e33..da42272bbef 100644
--- a/spec/lib/banzai/renderer_spec.rb
+++ b/spec/lib/banzai/renderer_spec.rb
@@ -4,6 +4,7 @@ describe Banzai::Renderer do
def fake_object(fresh:)
object = double('object')
+ allow(object).to receive(:respond_to?).with(:cached_markdown_fields).and_return(true)
allow(object).to receive(:cached_html_up_to_date?).with(:field).and_return(fresh)
allow(object).to receive(:cached_html_for).with(:field).and_return('field_html')
@@ -12,25 +13,38 @@ describe Banzai::Renderer do
describe '#render_field' do
let(:renderer) { described_class }
- subject { renderer.render_field(object, :field) }
- context 'with a stale cache' do
- let(:object) { fake_object(fresh: false) }
+ context 'without cache' do
+ let(:commit) { create(:project, :repository).commit }
- it 'caches and returns the result' do
- expect(object).to receive(:refresh_markdown_cache!).with(do_update: true)
+ it 'returns cacheless render field' do
+ expect(renderer).to receive(:cacheless_render_field).with(commit, :title)
- is_expected.to eq('field_html')
+ renderer.render_field(commit, :title)
end
end
- context 'with an up-to-date cache' do
- let(:object) { fake_object(fresh: true) }
+ context 'with cache' do
+ subject { renderer.render_field(object, :field) }
- it 'uses the cache' do
- expect(object).to receive(:refresh_markdown_cache!).never
+ context 'with a stale cache' do
+ let(:object) { fake_object(fresh: false) }
- is_expected.to eq('field_html')
+ it 'caches and returns the result' do
+ expect(object).to receive(:refresh_markdown_cache!).with(do_update: true)
+
+ is_expected.to eq('field_html')
+ end
+ end
+
+ context 'with an up-to-date cache' do
+ let(:object) { fake_object(fresh: true) }
+
+ it 'uses the cache' do
+ expect(object).to receive(:refresh_markdown_cache!).never
+
+ is_expected.to eq('field_html')
+ end
end
end
end
diff --git a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
index 0d5fffa38ff..c56b08b18a2 100644
--- a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
@@ -214,7 +214,7 @@ end
# The background migration relies on a temporary table, hence we're migrating
# to a specific version of the database where said table is still present.
#
-describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migration, schema: 20170608152748 do
+describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migration, schema: 20170825154015 do
let(:migration) { described_class.new }
let(:project) { create(:project_empty_repo) }
let(:author) { create(:user) }
diff --git a/spec/lib/gitlab/ci/build/artifacts/path_spec.rb b/spec/lib/gitlab/ci/build/artifacts/path_spec.rb
new file mode 100644
index 00000000000..7bd6a2ead25
--- /dev/null
+++ b/spec/lib/gitlab/ci/build/artifacts/path_spec.rb
@@ -0,0 +1,64 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Build::Artifacts::Path do
+ describe '#valid?' do
+ context 'when path contains a zero character' do
+ it 'is not valid' do
+ expect(described_class.new("something/\255")).not_to be_valid
+ end
+ end
+
+ context 'when path is not utf8 string' do
+ it 'is not valid' do
+ expect(described_class.new("something/\0")).not_to be_valid
+ end
+ end
+
+ context 'when path is valid' do
+ it 'is valid' do
+ expect(described_class.new("some/file/path")).to be_valid
+ end
+ end
+ end
+
+ describe '#directory?' do
+ context 'when path ends with a directory indicator' do
+ it 'is a directory' do
+ expect(described_class.new("some/file/dir/")).to be_directory
+ end
+ end
+
+ context 'when path does not end with a directory indicator' do
+ it 'is not a directory' do
+ expect(described_class.new("some/file")).not_to be_directory
+ end
+ end
+ end
+
+ describe '#name' do
+ it 'returns a base name' do
+ expect(described_class.new("some/file").name).to eq 'file'
+ end
+ end
+
+ describe '#nodes' do
+ it 'returns number of path nodes' do
+ expect(described_class.new("some/dir/file").nodes).to eq 2
+ end
+ end
+
+ describe '#to_s' do
+ context 'when path is valid' do
+ it 'returns a string representation of a path' do
+ expect(described_class.new('some/path').to_s).to eq 'some/path'
+ end
+ end
+
+ context 'when path is invalid' do
+ it 'raises an error' do
+ expect { described_class.new("invalid/\0").to_s }
+ .to raise_error ArgumentError
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index dfbdbee48f7..d39b33a0c05 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -273,6 +273,25 @@ EOT
end
end
+ describe '#json_safe_diff' do
+ let(:project) { create(:project, :repository) }
+
+ it 'fake binary message when it detects binary' do
+ # Rugged will not detect this as binary, but we can fake it
+ diff_message = "Binary files files/images/icn-time-tracking.pdf and files/images/icn-time-tracking.pdf differ\n"
+ binary_diff = described_class.between(project.repository, 'add-pdf-text-binary', 'add-pdf-text-binary^').first
+
+ expect(binary_diff.diff).not_to be_empty
+ expect(binary_diff.json_safe_diff).to eq(diff_message)
+ end
+
+ it 'leave non-binary diffs as-is' do
+ diff = described_class.new(@rugged_diff)
+
+ expect(diff.json_safe_diff).to eq(diff.diff)
+ end
+ end
+
describe '#submodule?' do
before do
commit = repository.lookup('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 08959e7bc16..556a148c3bc 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -390,46 +390,73 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe "#delete_branch" do
- before(:all) do
- @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
- @repo.delete_branch("feature")
+ shared_examples "deleting a branch" do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') }
+
+ after do
+ FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
+ ensure_seeds
+ end
+
+ it "removes the branch from the repo" do
+ branch_name = "to-be-deleted-soon"
+
+ repository.create_branch(branch_name)
+ expect(repository.rugged.branches[branch_name]).not_to be_nil
+
+ repository.delete_branch(branch_name)
+ expect(repository.rugged.branches[branch_name]).to be_nil
+ end
+
+ context "when branch does not exist" do
+ it "raises a DeleteBranchError exception" do
+ expect { repository.delete_branch("this-branch-does-not-exist") }.to raise_error(Gitlab::Git::Repository::DeleteBranchError)
+ end
+ end
end
- it "should remove the branch from the repo" do
- expect(@repo.rugged.branches["feature"]).to be_nil
+ context "when Gitaly delete_branch is enabled" do
+ it_behaves_like "deleting a branch"
end
- after(:all) do
- FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
- ensure_seeds
+ context "when Gitaly delete_branch is disabled", skip_gitaly_mock: true do
+ it_behaves_like "deleting a branch"
end
end
describe "#create_branch" do
- before(:all) do
- @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
- end
+ shared_examples 'creating a branch' do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') }
- it "should create a new branch" do
- expect(@repo.create_branch('new_branch', 'master')).not_to be_nil
- end
+ after do
+ FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
+ ensure_seeds
+ end
- it "should create a new branch with the right name" do
- expect(@repo.create_branch('another_branch', 'master').name).to eq('another_branch')
- end
+ it "should create a new branch" do
+ expect(repository.create_branch('new_branch', 'master')).not_to be_nil
+ end
- it "should fail if we create an existing branch" do
- @repo.create_branch('duplicated_branch', 'master')
- expect {@repo.create_branch('duplicated_branch', 'master')}.to raise_error("Branch duplicated_branch already exists")
+ it "should create a new branch with the right name" do
+ expect(repository.create_branch('another_branch', 'master').name).to eq('another_branch')
+ end
+
+ it "should fail if we create an existing branch" do
+ repository.create_branch('duplicated_branch', 'master')
+ expect {repository.create_branch('duplicated_branch', 'master')}.to raise_error("Branch duplicated_branch already exists")
+ end
+
+ it "should fail if we create a branch from a non existing ref" do
+ expect {repository.create_branch('branch_based_in_wrong_ref', 'master_2_the_revenge')}.to raise_error("Invalid reference master_2_the_revenge")
+ end
end
- it "should fail if we create a branch from a non existing ref" do
- expect {@repo.create_branch('branch_based_in_wrong_ref', 'master_2_the_revenge')}.to raise_error("Invalid reference master_2_the_revenge")
+ context 'when Gitaly create_branch feature is enabled' do
+ it_behaves_like 'creating a branch'
end
- after(:all) do
- FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
- ensure_seeds
+ context 'when Gitaly create_branch feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'creating a branch'
end
end
@@ -905,7 +932,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'should set the autocrlf option to the provided option' do
@repo.autocrlf = :input
- File.open(File.join(SEED_STORAGE_PATH, TEST_MUTABLE_REPO_PATH, '.git', 'config')) do |config_file|
+ File.open(File.join(SEED_STORAGE_PATH, TEST_MUTABLE_REPO_PATH, 'config')) do |config_file|
expect(config_file.read).to match('autocrlf = input')
end
end
@@ -977,7 +1004,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'with local and remote branches' do
let(:repository) do
- Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git'), '')
+ Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
end
before do
@@ -1024,7 +1051,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'with local and remote branches' do
let(:repository) do
- Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git'), '')
+ Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
end
before do
@@ -1230,7 +1257,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe '#local_branches' do
before(:all) do
- @repo = Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git'), '')
+ @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
end
after(:all) do
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 5b16fc5d084..d664d371028 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -11,8 +11,8 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
allow(@shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/')
@project = create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project')
- allow(@project.repository).to receive(:fetch_ref).and_return(true)
- allow(@project.repository.raw).to receive(:rugged_branch_exists?).and_return(false)
+ allow_any_instance_of(Repository).to receive(:fetch_ref).and_return(true)
+ allow_any_instance_of(Gitlab::Git::Repository).to receive(:branch_exists?).and_return(false)
expect_any_instance_of(Gitlab::Git::Repository).to receive(:create_branch).with('feature', 'DCBA')
allow_any_instance_of(Gitlab::Git::Repository).to receive(:create_branch)
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index 065b0ec6658..8e3554375e8 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -117,6 +117,13 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
expect(saved_project_json['pipelines'].first['statuses'].count { |hash| hash['type'] == 'Ci::Build' }).to eq(1)
end
+ it 'has no when YML attributes but only the DB column' do
+ allow_any_instance_of(Ci::Pipeline).to receive(:ci_yaml_file).and_return(File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')))
+ expect_any_instance_of(Ci::GitlabCiYamlProcessor).not_to receive(:build_attributes)
+
+ saved_project_json
+ end
+
it 'has pipeline commits' do
expect(saved_project_json['pipelines']).not_to be_empty
end
@@ -251,15 +258,11 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
create(:label_priority, label: group_label, priority: 1)
milestone = create(:milestone, project: project)
merge_request = create(:merge_request, source_project: project, milestone: milestone)
- commit_status = create(:commit_status, project: project)
- ci_pipeline = create(:ci_pipeline,
- project: project,
- sha: merge_request.diff_head_sha,
- ref: merge_request.source_branch,
- statuses: [commit_status])
+ ci_build = create(:ci_build, project: project, when: nil)
+ ci_build.pipeline.update(project: project)
+ create(:commit_status, project: project, pipeline: ci_build.pipeline)
- create(:ci_build, pipeline: ci_pipeline, project: project)
create(:milestone, project: project)
create(:note, noteable: issue, project: project)
create(:note, noteable: merge_request, project: project)
@@ -267,7 +270,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
create(:note_on_commit,
author: user,
project: project,
- commit_id: ci_pipeline.sha)
+ commit_id: ci_build.pipeline.sha)
create(:event, :created, target: milestone, project: project, author: user)
create(:service, project: project, type: 'CustomIssueTrackerService', category: 'issue_tracker')
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index b852ac570a3..122b8ee0314 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -65,6 +65,7 @@ Note:
- change_position
- resolved_at
- resolved_by_id
+- resolved_by_push
- discussion_id
- original_discussion_id
LabelLink:
@@ -398,6 +399,7 @@ Project:
- public_builds
- last_repository_check_failed
- last_repository_check_at
+- collapse_outdated_diff_comments
- container_registry_enabled
- only_allow_merge_if_pipeline_succeeds
- has_external_issue_tracker
@@ -406,6 +408,7 @@ Project:
- only_allow_merge_if_all_discussions_are_resolved
- auto_cancel_pending_pipelines
- printing_merge_request_link_enabled
+- resolve_outdated_diff_discussions
- build_allow_git_fetch
- last_repository_updated_at
- ci_config_path
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index 5100a5a609e..6a6e465cea2 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -37,7 +37,8 @@ describe Gitlab::LDAP::User do
end
it "does not mark existing ldap user as changed" do
- create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', external_email: true, email_provider: 'ldapmain')
+ create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain')
+ ldap_user.gl_user.user_synced_attributes_metadata(provider: 'ldapmain', email: true)
expect(ldap_user.changed?).to be_falsey
end
end
@@ -141,12 +142,12 @@ describe Gitlab::LDAP::User do
expect(ldap_user.gl_user.email).to eq(info[:email])
end
- it "has external_email set to true" do
- expect(ldap_user.gl_user.external_email?).to be(true)
+ it "has user_synced_attributes_metadata email set to true" do
+ expect(ldap_user.gl_user.user_synced_attributes_metadata.email_synced).to be_truthy
end
- it "has email_provider set to provider" do
- expect(ldap_user.gl_user.email_provider).to eql 'ldapmain'
+ it "has synced_attribute_provider set to ldapmain" do
+ expect(ldap_user.gl_user.user_synced_attributes_metadata.provider).to eql 'ldapmain'
end
end
@@ -156,11 +157,11 @@ describe Gitlab::LDAP::User do
end
it "has a temp email" do
- expect(ldap_user.gl_user.temp_oauth_email?).to be(true)
+ expect(ldap_user.gl_user.temp_oauth_email?).to be_truthy
end
- it "has external_email set to false" do
- expect(ldap_user.gl_user.external_email?).to be(false)
+ it "has synced attribute email set to false" do
+ expect(ldap_user.gl_user.user_synced_attributes_metadata.email_synced).to be_falsey
end
end
end
@@ -168,7 +169,7 @@ describe Gitlab::LDAP::User do
describe 'blocking' do
def configure_block(value)
allow_any_instance_of(Gitlab::LDAP::Config)
- .to receive(:block_auto_created_users).and_return(value)
+ .to receive(:block_auto_created_users).and_return(value)
end
context 'signup' do
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 2cf0f7516de..8aaf320cbf5 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -10,7 +10,11 @@ describe Gitlab::OAuth::User do
{
nickname: '-john+gitlab-ETC%.git@gmail.com',
name: 'John',
- email: 'john@mail.com'
+ email: 'john@mail.com',
+ address: {
+ locality: 'locality',
+ country: 'country'
+ }
}
end
let(:ldap_user) { Gitlab::LDAP::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
@@ -422,11 +426,12 @@ describe Gitlab::OAuth::User do
end
end
- describe 'updating email' do
+ describe 'ensure backwards compatibility with with sync email from provider option' do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
before do
stub_omniauth_config(sync_email_from_provider: 'my-provider')
+ stub_omniauth_config(sync_profile_from_provider: ['my-provider'])
end
context "when provider sets an email" do
@@ -434,12 +439,12 @@ describe Gitlab::OAuth::User do
expect(gl_user.email).to eq(info_hash[:email])
end
- it "has external_email set to true" do
- expect(gl_user.external_email?).to be(true)
+ it "has external_attributes set to true" do
+ expect(gl_user.user_synced_attributes_metadata).not_to be_nil
end
- it "has email_provider set to provider" do
- expect(gl_user.email_provider).to eql 'my-provider'
+ it "has attributes_provider set to my-provider" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
end
end
@@ -452,8 +457,9 @@ describe Gitlab::OAuth::User do
expect(gl_user.email).not_to eq(info_hash[:email])
end
- it "has external_email set to false" do
- expect(gl_user.external_email?).to be(false)
+ it "has user_synced_attributes_metadata set to nil" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be_falsey
end
end
end
@@ -487,4 +493,172 @@ describe Gitlab::OAuth::User do
end
end
end
+
+ describe 'updating email with sync profile' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ before do
+ stub_omniauth_config(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_config(sync_profile_attributes: true)
+ end
+
+ context "when provider sets an email" do
+ it "updates the user email" do
+ expect(gl_user.email).to eq(info_hash[:email])
+ end
+
+ it "has email_synced_attribute set to true" do
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(true)
+ end
+
+ it "has my-provider as attributes_provider" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
+ end
+ end
+
+ context "when provider doesn't set an email" do
+ before do
+ info_hash.delete(:email)
+ end
+
+ it "does not update the user email" do
+ expect(gl_user.email).not_to eq(info_hash[:email])
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(false)
+ end
+ end
+ end
+
+ describe 'updating name' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+ end
+
+ context "when provider sets a name" do
+ it "updates the user name" do
+ expect(gl_user.name).to eq(info_hash[:name])
+ end
+ end
+
+ context "when provider doesn't set a name" do
+ before do
+ info_hash.delete(:name)
+ end
+
+ it "does not update the user name" do
+ expect(gl_user.name).not_to eq(info_hash[:name])
+ expect(gl_user.user_synced_attributes_metadata.name_synced).to be(false)
+ end
+ end
+ end
+
+ describe 'updating location' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+ end
+
+ context "when provider sets a location" do
+ it "updates the user location" do
+ expect(gl_user.location).to eq(info_hash[:address][:locality] + ', ' + info_hash[:address][:country])
+ expect(gl_user.user_synced_attributes_metadata.location_synced).to be(true)
+ end
+ end
+
+ context "when provider doesn't set a location" do
+ before do
+ info_hash[:address].delete(:country)
+ info_hash[:address].delete(:locality)
+ end
+
+ it "does not update the user location" do
+ expect(gl_user.location).to be_nil
+ expect(gl_user.user_synced_attributes_metadata.location_synced).to be(false)
+ end
+ end
+ end
+
+ describe 'updating user info' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ context "update all info" do
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+ end
+
+ it "updates the user email" do
+ expect(gl_user.email).to eq(info_hash[:email])
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(true)
+ end
+
+ it "updates the user name" do
+ expect(gl_user.name).to eq(info_hash[:name])
+ expect(gl_user.user_synced_attributes_metadata.name_synced).to be(true)
+ end
+
+ it "updates the user location" do
+ expect(gl_user.location).to eq(info_hash[:address][:locality] + ', ' + info_hash[:address][:country])
+ expect(gl_user.user_synced_attributes_metadata.location_synced).to be(true)
+ end
+
+ it "sets my-provider as the attributes provider" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql('my-provider')
+ end
+ end
+
+ context "update only requested info" do
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_setting(sync_profile_attributes: %w(name location))
+ end
+
+ it "updates the user name" do
+ expect(gl_user.name).to eq(info_hash[:name])
+ expect(gl_user.user_synced_attributes_metadata.name_synced).to be(true)
+ end
+
+ it "updates the user location" do
+ expect(gl_user.location).to eq(info_hash[:address][:locality] + ', ' + info_hash[:address][:country])
+ expect(gl_user.user_synced_attributes_metadata.location_synced).to be(true)
+ end
+
+ it "does not update the user email" do
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(false)
+ end
+ end
+
+ context "update default_scope" do
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ end
+
+ it "updates the user email" do
+ expect(gl_user.email).to eq(info_hash[:email])
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(true)
+ end
+ end
+
+ context "update no info when profile sync is nil" do
+ it "does not have sync_attribute" do
+ expect(gl_user.user_synced_attributes_metadata).to be(nil)
+ end
+
+ it "does not update the user email" do
+ expect(gl_user.email).not_to eq(info_hash[:email])
+ end
+
+ it "does not update the user name" do
+ expect(gl_user.name).not_to eq(info_hash[:name])
+ end
+
+ it "does not update the user location" do
+ expect(gl_user.location).not_to eq(info_hash[:address][:country])
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
index 308b1a128be..fdc3990132a 100644
--- a/spec/lib/gitlab/url_sanitizer_spec.rb
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -1,11 +1,7 @@
require 'spec_helper'
describe Gitlab::UrlSanitizer do
- let(:credentials) { { user: 'blah', password: 'password' } }
- let(:url_sanitizer) do
- described_class.new("https://github.com/me/project.git", credentials: credentials)
- end
- let(:user) { double(:user, username: 'john.doe') }
+ using RSpec::Parameterized::TableSyntax
describe '.sanitize' do
def sanitize_url(url)
@@ -16,83 +12,166 @@ describe Gitlab::UrlSanitizer do
})
end
- it 'mask the credentials from HTTP URLs' do
- filtered_content = sanitize_url('http://user:pass@test.com/root/repoC.git/')
+ where(:input, :output) do
+ 'http://user:pass@test.com/root/repoC.git/' | 'http://*****:*****@test.com/root/repoC.git/'
+ 'https://user:pass@test.com/root/repoA.git/' | 'https://*****:*****@test.com/root/repoA.git/'
+ 'ssh://user@host.test/path/to/repo.git' | 'ssh://*****@host.test/path/to/repo.git'
- expect(filtered_content).to include("http://*****:*****@test.com/root/repoC.git/")
- end
+ # git protocol does not support authentication but clean any details anyway
+ 'git://user:pass@host.test/path/to/repo.git' | 'git://*****:*****@host.test/path/to/repo.git'
+ 'git://host.test/path/to/repo.git' | 'git://host.test/path/to/repo.git'
- it 'mask the credentials from HTTPS URLs' do
- filtered_content = sanitize_url('https://user:pass@test.com/root/repoA.git/')
+ # SCP-style URLs are left unmodified
+ 'user@server:project.git' | 'user@server:project.git'
+ 'user:pass@server:project.git' | 'user:pass@server:project.git'
- expect(filtered_content).to include("https://*****:*****@test.com/root/repoA.git/")
+ # return an empty string for invalid URLs
+ 'ssh://' | ''
end
- it 'mask credentials from SSH URLs' do
- filtered_content = sanitize_url('ssh://user@host.test/path/to/repo.git')
-
- expect(filtered_content).to include("ssh://*****@host.test/path/to/repo.git")
+ with_them do
+ it { expect(sanitize_url(input)).to include("repository '#{output}' not found") }
end
+ end
- it 'does not modify Git URLs' do
- # git protocol does not support authentication
- filtered_content = sanitize_url('git://host.test/path/to/repo.git')
+ describe '.valid?' do
+ where(:value, :url) do
+ false | nil
+ false | ''
+ false | '123://invalid:url'
+ true | 'valid@project:url.git'
+ true | 'ssh://example.com'
+ true | 'ssh://:@example.com'
+ true | 'ssh://foo@example.com'
+ true | 'ssh://foo:bar@example.com'
+ true | 'ssh://foo:bar@example.com/group/group/project.git'
+ true | 'git://example.com/group/group/project.git'
+ true | 'git://foo:bar@example.com/group/group/project.git'
+ true | 'http://foo:bar@example.com/group/group/project.git'
+ true | 'https://foo:bar@example.com/group/group/project.git'
+ end
- expect(filtered_content).to include("git://host.test/path/to/repo.git")
+ with_them do
+ it { expect(described_class.valid?(url)).to eq(value) }
end
+ end
+
+ describe '#sanitized_url' do
+ context 'credentials in hash' do
+ where(username: ['foo', '', nil], password: ['bar', '', nil])
- it 'does not modify scp-like URLs' do
- filtered_content = sanitize_url('user@server:project.git')
+ with_them do
+ let(:credentials) { { user: username, password: password } }
+ subject { described_class.new('http://example.com', credentials: credentials).sanitized_url }
- expect(filtered_content).to include("user@server:project.git")
+ it { is_expected.to eq('http://example.com') }
+ end
end
- it 'returns an empty string for invalid URLs' do
- filtered_content = sanitize_url('ssh://')
+ context 'credentials in URL' do
+ where(userinfo: %w[foo:bar@ foo@ :bar@ :@ @] + [nil])
- expect(filtered_content).to include("repository '' not found")
- end
- end
+ with_them do
+ subject { described_class.new("http://#{userinfo}example.com").sanitized_url }
- describe '.valid?' do
- it 'validates url strings' do
- expect(described_class.valid?(nil)).to be(false)
- expect(described_class.valid?('valid@project:url.git')).to be(true)
- expect(described_class.valid?('123://invalid:url')).to be(false)
+ it { is_expected.to eq('http://example.com') }
+ end
end
end
- describe '#sanitized_url' do
- it { expect(url_sanitizer.sanitized_url).to eq("https://github.com/me/project.git") }
- end
-
describe '#credentials' do
- it { expect(url_sanitizer.credentials).to eq(credentials) }
+ 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
- context 'when user is given to #initialize' do
- let(:url_sanitizer) do
- described_class.new("https://github.com/me/project.git", credentials: { user: user.username })
+ with_them do
+ subject { described_class.new('user@example.com:path.git', credentials: input).credentials }
+
+ it { is_expected.to eq(output) }
end
- it { expect(url_sanitizer.credentials).to eq({ user: 'john.doe' }) }
+ it 'overrides URL-provided credentials' do
+ sanitizer = described_class.new('http://a:b@example.com', credentials: { user: 'c', password: 'd' })
+
+ expect(sanitizer.credentials).to eq(user: 'c', password: 'd')
+ end
+ end
+
+ context 'credentials in URL' do
+ where(:url, :credentials) do
+ 'http://foo:bar@example.com' | { user: 'foo', password: 'bar' }
+ 'http://:bar@example.com' | { user: nil, password: 'bar' }
+ 'http://foo:@example.com' | { user: 'foo', password: nil }
+ 'http://foo@example.com' | { user: 'foo', password: nil }
+ 'http://:@example.com' | { user: nil, password: nil }
+ '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 }
+ 'no' | { user: nil, password: nil }
+ end
+
+ with_them do
+ subject { described_class.new(url).credentials }
+
+ it { is_expected.to eq(credentials) }
+ end
end
end
describe '#full_url' do
- it { expect(url_sanitizer.full_url).to eq("https://blah:password@github.com/me/project.git") }
+ context 'credentials in hash' do
+ where(:credentials, :userinfo) do
+ { user: 'foo', password: 'bar' } | 'foo:bar@'
+ { user: 'foo', password: '' } | 'foo@'
+ { user: 'foo', password: nil } | 'foo@'
+ { user: '', password: 'bar' } | ':bar@'
+ { user: '', password: '' } | nil
+ { user: '', password: nil } | nil
+ { user: nil, password: 'bar' } | ':bar@'
+ { user: nil, password: '' } | nil
+ { user: nil, password: nil } | nil
+ end
- it 'supports scp-like URLs' do
- sanitizer = described_class.new('user@server:project.git')
+ with_them do
+ subject { described_class.new('http://example.com', credentials: credentials).full_url }
- expect(sanitizer.full_url).to eq('user@server:project.git')
+ it { is_expected.to eq("http://#{userinfo}example.com") }
+ end
end
- context 'when user is given to #initialize' do
- let(:url_sanitizer) do
- described_class.new("https://github.com/me/project.git", credentials: { user: user.username })
+ context 'credentials in URL' do
+ where(:input, :output) do
+ nil | ''
+ '' | :same
+ 'git@example.com' | :same
+ 'http://example.com' | :same
+ 'http://foo@example.com' | :same
+ 'http://foo:@example.com' | 'http://foo@example.com'
+ 'http://:bar@example.com' | :same
+ 'http://foo:bar@example.com' | :same
end
- it { expect(url_sanitizer.full_url).to eq("https://john.doe@github.com/me/project.git") }
+ with_them do
+ let(:expected) { output == :same ? input : output }
+
+ it { expect(described_class.new(input).full_url).to eq(expected) }
+ end
end
end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 37f6fd3a25b..fb5fb7daaab 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -480,4 +480,71 @@ describe Issuable do
end
end
end
+
+ describe '#first_contribution?' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
+ let(:other_project) { create(:project) }
+ let(:owner) { create(:owner) }
+ let(:master) { create(:user) }
+ let(:reporter) { create(:user) }
+ let(:guest) { create(:user) }
+
+ let(:contributor) { create(:user) }
+ let(:first_time_contributor) { create(:user) }
+
+ before do
+ group.add_owner(owner)
+ project.add_master(master)
+ project.add_reporter(reporter)
+ project.add_guest(guest)
+ project.add_guest(contributor)
+ project.add_guest(first_time_contributor)
+ end
+
+ let(:merged_mr) { create(:merge_request, :merged, author: contributor, target_project: project, source_project: project) }
+ let(:open_mr) { create(:merge_request, author: first_time_contributor, target_project: project, source_project: project) }
+ let(:merged_mr_other_project) { create(:merge_request, :merged, author: first_time_contributor, target_project: other_project, source_project: other_project) }
+
+ context "for merge requests" do
+ it "is false for MASTER" do
+ mr = create(:merge_request, author: master, target_project: project, source_project: project)
+
+ expect(mr).not_to be_first_contribution
+ end
+
+ it "is false for OWNER" do
+ mr = create(:merge_request, author: owner, target_project: project, source_project: project)
+
+ expect(mr).not_to be_first_contribution
+ end
+
+ it "is false for REPORTER" do
+ mr = create(:merge_request, author: reporter, target_project: project, source_project: project)
+
+ expect(mr).not_to be_first_contribution
+ end
+
+ it "is true when you don't have any merged MR" do
+ expect(open_mr).to be_first_contribution
+ expect(merged_mr).not_to be_first_contribution
+ end
+
+ it "handles multiple projects separately" do
+ expect(open_mr).to be_first_contribution
+ expect(merged_mr_other_project).not_to be_first_contribution
+ end
+ end
+
+ context "for issues" do
+ let(:contributor_issue) { create(:issue, author: contributor, project: project) }
+ let(:first_time_contributor_issue) { create(:issue, author: first_time_contributor, project: project) }
+
+ it "is false even without merged MR" do
+ expect(merged_mr).to be
+ expect(first_time_contributor_issue).not_to be_first_contribution
+ expect(contributor_issue).not_to be_first_contribution
+ end
+ end
+ end
end
diff --git a/spec/models/concerns/resolvable_note_spec.rb b/spec/models/concerns/resolvable_note_spec.rb
index d00faa4f8be..91591017587 100644
--- a/spec/models/concerns/resolvable_note_spec.rb
+++ b/spec/models/concerns/resolvable_note_spec.rb
@@ -189,8 +189,8 @@ describe Note, ResolvableNote do
allow(subject).to receive(:resolvable?).and_return(false)
end
- it "returns nil" do
- expect(subject.resolve!(current_user)).to be_nil
+ it "returns false" do
+ expect(subject.resolve!(current_user)).to be_falsey
end
it "doesn't set resolved_at" do
@@ -224,8 +224,8 @@ describe Note, ResolvableNote do
subject.resolve!(user)
end
- it "returns nil" do
- expect(subject.resolve!(current_user)).to be_nil
+ it "returns false" do
+ expect(subject.resolve!(current_user)).to be_falsey
end
it "doesn't change resolved_at" do
@@ -279,8 +279,8 @@ describe Note, ResolvableNote do
allow(subject).to receive(:resolvable?).and_return(false)
end
- it "returns nil" do
- expect(subject.unresolve!).to be_nil
+ it "returns false" do
+ expect(subject.unresolve!).to be_falsey
end
end
@@ -320,8 +320,8 @@ describe Note, ResolvableNote do
end
context "when not resolved" do
- it "returns nil" do
- expect(subject.unresolve!).to be_nil
+ it "returns false" do
+ expect(subject.unresolve!).to be_falsey
end
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index f5d079c27c4..d80d5657c42 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -1262,7 +1262,6 @@ describe MergeRequest do
describe "#reload_diff" do
let(:discussion) { create(:diff_note_on_merge_request, project: subject.project, noteable: subject).to_discussion }
-
let(:commit) { subject.project.commit(sample_commit.id) }
it "does not change existing merge request diff" do
@@ -1280,9 +1279,19 @@ describe MergeRequest do
subject.reload_diff
end
- it "updates diff discussion positions" do
- old_diff_refs = subject.diff_refs
+ it "calls update_diff_discussion_positions" do
+ expect(subject).to receive(:update_diff_discussion_positions)
+
+ subject.reload_diff
+ end
+ end
+ describe '#update_diff_discussion_positions' do
+ let(:discussion) { create(:diff_note_on_merge_request, project: subject.project, noteable: subject).to_discussion }
+ let(:commit) { subject.project.commit(sample_commit.id) }
+ let(:old_diff_refs) { subject.diff_refs }
+
+ before do
# Update merge_request_diff so that #diff_refs will return commit.diff_refs
allow(subject).to receive(:create_merge_request_diff) do
subject.merge_request_diffs.create(
@@ -1293,7 +1302,9 @@ describe MergeRequest do
subject.merge_request_diff(true)
end
+ end
+ it "updates diff discussion positions" do
expect(Discussions::UpdateDiffPositionService).to receive(:new).with(
subject.project,
subject.author,
@@ -1305,7 +1316,26 @@ describe MergeRequest do
expect_any_instance_of(Discussions::UpdateDiffPositionService).to receive(:execute).with(discussion).and_call_original
expect_any_instance_of(DiffNote).to receive(:save).once
- subject.reload_diff(subject.author)
+ subject.update_diff_discussion_positions(old_diff_refs: old_diff_refs,
+ new_diff_refs: commit.diff_refs,
+ current_user: subject.author)
+ end
+
+ context 'when resolve_outdated_diff_discussions is set' do
+ before do
+ discussion
+
+ subject.project.update!(resolve_outdated_diff_discussions: true)
+ end
+
+ it 'calls MergeRequests::ResolvedDiscussionNotificationService' do
+ expect_any_instance_of(MergeRequests::ResolvedDiscussionNotificationService)
+ .to receive(:execute).with(subject)
+
+ subject.update_diff_discussion_positions(old_diff_refs: old_diff_refs,
+ new_diff_refs: commit.diff_refs,
+ current_user: subject.author)
+ end
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index fd83a58ed9f..abf732e60bf 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2116,4 +2116,70 @@ describe User do
expect(user.verified_email?('other_email@example.com')).to be false
end
end
+
+ describe '#sync_attribute?' do
+ let(:user) { described_class.new }
+
+ context 'oauth user' do
+ it 'returns true if name can be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(name location))
+ expect(user.sync_attribute?(:name)).to be_truthy
+ end
+
+ it 'returns true if email can be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(name email))
+ expect(user.sync_attribute?(:email)).to be_truthy
+ end
+
+ it 'returns true if location can be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(location email))
+ expect(user.sync_attribute?(:email)).to be_truthy
+ end
+
+ it 'returns false if name can not be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(location email))
+ expect(user.sync_attribute?(:name)).to be_falsey
+ end
+
+ it 'returns false if email can not be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(location email))
+ expect(user.sync_attribute?(:name)).to be_falsey
+ end
+
+ it 'returns false if location can not be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(location email))
+ expect(user.sync_attribute?(:name)).to be_falsey
+ end
+
+ it 'returns true for all syncable attributes if all syncable attributes can be synced' do
+ stub_omniauth_setting(sync_profile_attributes: true)
+ expect(user.sync_attribute?(:name)).to be_truthy
+ expect(user.sync_attribute?(:email)).to be_truthy
+ expect(user.sync_attribute?(:location)).to be_truthy
+ end
+
+ it 'returns false for all syncable attributes but email if no syncable attributes are declared' do
+ expect(user.sync_attribute?(:name)).to be_falsey
+ expect(user.sync_attribute?(:email)).to be_truthy
+ expect(user.sync_attribute?(:location)).to be_falsey
+ end
+ end
+
+ context 'ldap user' do
+ it 'returns true for email if ldap user' do
+ allow(user).to receive(:ldap_user?).and_return(true)
+ expect(user.sync_attribute?(:name)).to be_falsey
+ expect(user.sync_attribute?(:email)).to be_truthy
+ expect(user.sync_attribute?(:location)).to be_falsey
+ end
+
+ it 'returns true for email and location if ldap user and location declared as syncable' do
+ allow(user).to receive(:ldap_user?).and_return(true)
+ stub_omniauth_setting(sync_profile_attributes: %w(location))
+ expect(user.sync_attribute?(:name)).to be_falsey
+ expect(user.sync_attribute?(:email)).to be_truthy
+ expect(user.sync_attribute?(:location)).to be_truthy
+ end
+ end
+ end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index edbfaf510c5..f663719d28c 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -673,6 +673,12 @@ describe API::Commits do
it_behaves_like 'ref diff'
end
end
+
+ context 'when binary diff are treated as text' do
+ let(:commit_id) { TestEnv::BRANCH_SHA['add-pdf-text-binary'] }
+
+ it_behaves_like 'ref diff'
+ end
end
end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index a6c804fb2b3..1274e66bb4c 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -5,13 +5,26 @@ describe API::Internal do
let(:key) { create(:key, user: user) }
let(:project) { create(:project, :repository) }
let(:secret_token) { Gitlab::Shell.secret_token }
+ let(:gl_repository) { "project-#{project.id}" }
+ let(:reference_counter) { double('ReferenceCounter') }
describe "GET /internal/check" do
it do
+ expect_any_instance_of(Redis).to receive(:ping).and_return('PONG')
+
get api("/internal/check"), secret_token: secret_token
expect(response).to have_http_status(200)
expect(json_response['api_version']).to eq(API::API.version)
+ expect(json_response['redis']).to be(true)
+ end
+
+ it 'returns false for field `redis` when redis is unavailable' do
+ expect_any_instance_of(Redis).to receive(:ping).and_raise(Errno::ENOENT)
+
+ get api("/internal/check"), secret_token: secret_token
+
+ expect(json_response['redis']).to be(false)
end
end
@@ -661,9 +674,7 @@ describe API::Internal do
# end
describe 'POST /internal/post_receive' do
- let(:gl_repository) { "project-#{project.id}" }
let(:identifier) { 'key-123' }
- let(:reference_counter) { double('ReferenceCounter') }
let(:valid_params) do
{
@@ -749,6 +760,22 @@ describe API::Internal do
end
end
+ describe 'POST /internal/pre_receive' do
+ let(:valid_params) do
+ { gl_repository: gl_repository, secret_token: secret_token }
+ end
+
+ it 'decreases the reference counter and returns the result' do
+ expect(Gitlab::ReferenceCounter).to receive(:new).with(gl_repository)
+ .and_return(reference_counter)
+ expect(reference_counter).to receive(:increase).and_return(true)
+
+ post api("/internal/pre_receive"), valid_params
+
+ expect(json_response['reference_counter_increased']).to be(true)
+ end
+ end
+
def project_with_repo_path(path)
double().tap do |fake_project|
allow(fake_project).to receive_message_chain('repository.path_to_repo' => path)
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index f56baf9663d..2d7cc1a1798 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
describe API::Jobs do
- let!(:project) do
+ set(:project) do
create(:project, :repository, public_builds: false)
end
- let!(:pipeline) do
+ set(:pipeline) do
create(:ci_empty_pipeline, project: project,
sha: project.commit.id,
ref: project.default_branch)
@@ -188,6 +188,84 @@ describe API::Jobs do
end
end
+ describe 'GET /projects/:id/jobs/:job_id/artifacts/:artifact_path' do
+ context 'when job has artifacts' do
+ let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) }
+
+ let(:artifact) do
+ 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif'
+ end
+
+ context 'when user is anonymous' do
+ let(:api_user) { nil }
+
+ context 'when project is public' do
+ it 'allows to access artifacts' do
+ project.update_column(:visibility_level,
+ Gitlab::VisibilityLevel::PUBLIC)
+ project.update_column(:public_builds, true)
+
+ get_artifact_file(artifact)
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ context 'when project is public with builds access disabled' do
+ it 'rejects access to artifacts' do
+ project.update_column(:visibility_level,
+ Gitlab::VisibilityLevel::PUBLIC)
+ project.update_column(:public_builds, false)
+
+ get_artifact_file(artifact)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'when project is private' do
+ it 'rejects access and hides existence of artifacts' do
+ project.update_column(:visibility_level,
+ Gitlab::VisibilityLevel::PRIVATE)
+ project.update_column(:public_builds, true)
+
+ get_artifact_file(artifact)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ context 'when user is authorized' do
+ it 'returns a specific artifact file for a valid path' do
+ expect(Gitlab::Workhorse)
+ .to receive(:send_artifacts_entry)
+ .and_call_original
+
+ get_artifact_file(artifact)
+
+ expect(response).to have_http_status(200)
+ expect(response.headers)
+ .to include('Content-Type' => 'application/json',
+ 'Gitlab-Workhorse-Send-Data' => /artifacts-entry/)
+ end
+ end
+ end
+
+ context 'when job does not have artifacts' do
+ it 'does not return job artifact file' do
+ get_artifact_file('some/artifact')
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ def get_artifact_file(artifact_path)
+ get api("/projects/#{project.id}/jobs/#{job.id}/" \
+ "artifacts/#{artifact_path}", api_user)
+ end
+ end
+
describe 'GET /projects/:id/jobs/:job_id/artifacts' do
before do
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user)
@@ -209,11 +287,12 @@ describe API::Jobs do
end
end
- context 'unauthorized user' do
+ context 'when anonymous user is accessing private artifacts' do
let(:api_user) { nil }
- it 'does not return specific job artifacts' do
- expect(response).to have_http_status(401)
+ it 'hides artifacts and rejects request' do
+ expect(project).to be_private
+ expect(response).to have_http_status(404)
end
end
end
@@ -242,8 +321,9 @@ describe API::Jobs do
get_for_ref
end
- it 'gives 401' do
- expect(response).to have_http_status(401)
+ it 'does not find a resource in a private project' do
+ expect(project).to be_private
+ expect(response).to have_http_status(404)
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 4490e50702b..f771e4fa4ff 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -414,6 +414,7 @@ describe API::Projects do
jobs_enabled: false,
merge_requests_enabled: false,
wiki_enabled: false,
+ resolve_outdated_diff_discussions: false,
only_allow_merge_if_pipeline_succeeds: false,
request_access_enabled: true,
only_allow_merge_if_all_discussions_are_resolved: false,
@@ -477,20 +478,40 @@ describe API::Projects do
expect(json_response['avatar_url']).to eq("http://localhost/uploads/-/system/project/avatar/#{project_id}/banana_sample.gif")
end
+ it 'sets a project as allowing outdated diff discussions to automatically resolve' do
+ project = attributes_for(:project, resolve_outdated_diff_discussions: false)
+
+ post api('/projects', user), project
+
+ expect(json_response['resolve_outdated_diff_discussions']).to be_falsey
+ end
+
+ it 'sets a project as allowing outdated diff discussions to automatically resolve if resolve_outdated_diff_discussions' do
+ project = attributes_for(:project, resolve_outdated_diff_discussions: true)
+
+ post api('/projects', user), project
+
+ expect(json_response['resolve_outdated_diff_discussions']).to be_truthy
+ end
+
it 'sets a project as allowing merge even if build fails' do
- project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: false })
+ project = attributes_for(:project, only_allow_merge_if_pipeline_succeeds: false)
+
post api('/projects', user), project
+
expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_falsey
end
it 'sets a project as allowing merge only if merge_when_pipeline_succeeds' do
- project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: true })
+ project = attributes_for(:project, only_allow_merge_if_pipeline_succeeds: true)
+
post api('/projects', user), project
+
expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_truthy
end
it 'sets a project as allowing merge even if discussions are unresolved' do
- project = attributes_for(:project, { only_allow_merge_if_all_discussions_are_resolved: false })
+ project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: false)
post api('/projects', user), project
@@ -506,7 +527,7 @@ describe API::Projects do
end
it 'sets a project as allowing merge only if all discussions are resolved' do
- project = attributes_for(:project, { only_allow_merge_if_all_discussions_are_resolved: true })
+ project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: true)
post api('/projects', user), project
@@ -514,7 +535,7 @@ describe API::Projects do
end
it 'ignores import_url when it is nil' do
- project = attributes_for(:project, { import_url: nil })
+ project = attributes_for(:project, import_url: nil)
post api('/projects', user), project
@@ -642,20 +663,36 @@ describe API::Projects do
expect(json_response['visibility']).to eq('private')
end
+ it 'sets a project as allowing outdated diff discussions to automatically resolve' do
+ project = attributes_for(:project, resolve_outdated_diff_discussions: false)
+
+ post api("/projects/user/#{user.id}", admin), project
+
+ expect(json_response['resolve_outdated_diff_discussions']).to be_falsey
+ end
+
+ it 'sets a project as allowing outdated diff discussions to automatically resolve' do
+ project = attributes_for(:project, resolve_outdated_diff_discussions: true)
+
+ post api("/projects/user/#{user.id}", admin), project
+
+ expect(json_response['resolve_outdated_diff_discussions']).to be_truthy
+ end
+
it 'sets a project as allowing merge even if build fails' do
- project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: false })
+ project = attributes_for(:project, only_allow_merge_if_pipeline_succeeds: false)
post api("/projects/user/#{user.id}", admin), project
expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_falsey
end
- it 'sets a project as allowing merge only if merge_when_pipeline_succeeds' do
- project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: true })
+ it 'sets a project as allowing merge only if pipeline succeeds' do
+ project = attributes_for(:project, only_allow_merge_if_pipeline_succeeds: true)
post api("/projects/user/#{user.id}", admin), project
expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_truthy
end
it 'sets a project as allowing merge even if discussions are unresolved' do
- project = attributes_for(:project, { only_allow_merge_if_all_discussions_are_resolved: false })
+ project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: false)
post api("/projects/user/#{user.id}", admin), project
@@ -663,7 +700,7 @@ describe API::Projects do
end
it 'sets a project as allowing merge only if all discussions are resolved' do
- project = attributes_for(:project, { only_allow_merge_if_all_discussions_are_resolved: true })
+ project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: true)
post api("/projects/user/#{user.id}", admin), project
@@ -732,6 +769,7 @@ describe API::Projects do
expect(json_response['wiki_enabled']).to be_present
expect(json_response['jobs_enabled']).to be_present
expect(json_response['snippets_enabled']).to be_present
+ expect(json_response['resolve_outdated_diff_discussions']).to eq(project.resolve_outdated_diff_discussions)
expect(json_response['container_registry_enabled']).to be_present
expect(json_response['created_at']).to be_present
expect(json_response['last_activity_at']).to be_present
diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb
index a514166274a..cae2c3118da 100644
--- a/spec/requests/api/v3/projects_spec.rb
+++ b/spec/requests/api/v3/projects_spec.rb
@@ -687,6 +687,7 @@ describe API::V3::Projects do
expect(json_response['wiki_enabled']).to be_present
expect(json_response['builds_enabled']).to be_present
expect(json_response['snippets_enabled']).to be_present
+ expect(json_response['resolve_outdated_diff_discussions']).to eq(project.resolve_outdated_diff_discussions)
expect(json_response['container_registry_enabled']).to be_present
expect(json_response['created_at']).to be_present
expect(json_response['last_activity_at']).to be_present
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index f5ed9ff608f..bbc3a8c79f5 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -52,6 +52,17 @@ describe Ci::RetryBuildService do
expect(new_build.send(attribute)).to eq build.send(attribute)
end
end
+
+ context 'when job has nullified protected' do
+ before do
+ build.update_attribute(:protected, nil)
+ end
+
+ it "clones protected build attribute" do
+ expect(new_build.protected).to be_nil
+ expect(new_build.protected).to eq build.protected
+ end
+ end
end
describe 'reject acessors' do
diff --git a/spec/services/discussions/update_diff_position_service_spec.rb b/spec/services/discussions/update_diff_position_service_spec.rb
index c239494298b..82b156f5ebe 100644
--- a/spec/services/discussions/update_diff_position_service_spec.rb
+++ b/spec/services/discussions/update_diff_position_service_spec.rb
@@ -150,21 +150,7 @@ describe Discussions::UpdateDiffPositionService do
)
end
- context "when the diff line is the same" do
- let(:line) { 16 }
-
- it "updates the position" do
- subject.execute(discussion)
-
- expect(discussion.original_position).to eq(old_position)
- expect(discussion.position).not_to eq(old_position)
- expect(discussion.position.new_line).to eq(22)
- end
- end
-
- context "when the diff line has changed" do
- let(:line) { 9 }
-
+ shared_examples 'outdated diff note' do
it "doesn't update the position" do
subject.execute(discussion)
@@ -189,5 +175,51 @@ describe Discussions::UpdateDiffPositionService do
subject.execute(discussion)
end
end
+
+ context "when the diff line is the same" do
+ let(:line) { 16 }
+
+ it "updates the position" do
+ subject.execute(discussion)
+
+ expect(discussion.original_position).to eq(old_position)
+ expect(discussion.position).not_to eq(old_position)
+ expect(discussion.position.new_line).to eq(22)
+ end
+
+ context 'when the resolve_outdated_diff_discussions setting is set' do
+ before do
+ project.update!(resolve_outdated_diff_discussions: true)
+ end
+
+ it 'does not resolve the discussion' do
+ subject.execute(discussion)
+
+ expect(discussion).not_to be_resolved
+ expect(discussion).not_to be_resolved_by_push
+ end
+ end
+ end
+
+ context "when the diff line has changed" do
+ let(:line) { 9 }
+
+ include_examples 'outdated diff note'
+
+ context 'when the resolve_outdated_diff_discussions setting is set' do
+ before do
+ project.update!(resolve_outdated_diff_discussions: true)
+ end
+
+ it 'sets resolves the discussion and sets resolved_by_push' do
+ subject.execute(discussion)
+
+ expect(discussion).to be_resolved
+ expect(discussion).to be_resolved_by_push
+ end
+
+ include_examples 'outdated diff note'
+ end
+ end
end
end
diff --git a/spec/support/seed_helper.rb b/spec/support/seed_helper.rb
index 8731847592b..11ef1fc477f 100644
--- a/spec/support/seed_helper.rb
+++ b/spec/support/seed_helper.rb
@@ -41,7 +41,7 @@ module SeedHelper
end
def create_mutable_seeds
- system(git_env, *%W(#{Gitlab.config.git.bin_path} clone #{TEST_REPO_PATH} #{TEST_MUTABLE_REPO_PATH}),
+ system(git_env, *%W(#{Gitlab.config.git.bin_path} clone --bare #{TEST_REPO_PATH} #{TEST_MUTABLE_REPO_PATH}),
chdir: SEED_STORAGE_PATH,
out: '/dev/null',
err: '/dev/null')
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 290ded3ff7e..71b9deeabc3 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -176,6 +176,24 @@ module TestEnv
spawn_script = Rails.root.join('scripts/gitaly-test-spawn').to_s
@gitaly_pid = Bundler.with_original_env { IO.popen([spawn_script], &:read).to_i }
+ wait_gitaly
+ end
+
+ def wait_gitaly
+ sleep_time = 10
+ sleep_interval = 0.1
+ socket = Gitlab::GitalyClient.address('default').sub('unix:', '')
+
+ Integer(sleep_time / sleep_interval).times do
+ begin
+ Socket.unix(socket)
+ return
+ rescue
+ sleep sleep_interval
+ end
+ end
+
+ raise "could not connect to gitaly at #{socket.inspect} after #{sleep_time} seconds"
end
def stop_gitaly
diff --git a/spec/views/layouts/nav/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
index faea2505e40..b17bc6692f3 100644
--- a/spec/views/layouts/nav/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -1,11 +1,13 @@
require 'spec_helper'
-describe 'layouts/nav/_project' do
+describe 'layouts/nav/sidebar/_project' do
describe 'container registry tab' do
before do
+ project = create(:project, :repository)
stub_container_registry_config(enabled: true)
- assign(:project, create(:project, :repository))
+ assign(:project, project)
+ assign(:repository, project.repository)
allow(view).to receive(:current_ref).and_return('master')
allow(view).to receive(:can?).and_return(true)