diff options
author | Kamil Trzcinski <ayufan@ayufan.eu> | 2017-09-06 21:00:47 +0200 |
---|---|---|
committer | Kamil Trzcinski <ayufan@ayufan.eu> | 2017-09-06 21:00:47 +0200 |
commit | cd8ea329f0d64c04e5dee00fb8916268dae7a6f7 (patch) | |
tree | a77f550a9acfce3c64484ff9f300a560b6587bd0 | |
parent | 632f6ba267bc09a658defc3721d2b52de05cf7e6 (diff) | |
parent | bb1ad6edcd62d8e8b8a1a37ed0782bdf7bf2bbd1 (diff) | |
download | gitlab-ce-cd8ea329f0d64c04e5dee00fb8916268dae7a6f7.tar.gz |
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into zj/gitlab-ce-zj-auto-devops-table
222 files changed, 5831 insertions, 1668 deletions
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/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 6677391c689..00000000000 --- a/app/assets/javascripts/group_name.js +++ /dev/null @@ -1,67 +0,0 @@ -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'); - this.toggle.innerHTML = '<i class="fa fa-ellipsis-h" aria-hidden="true"></i>'; - this.toggle.addEventListener('click', this.toggleGroups.bind(this)); - this.title.insertBefore(this.toggle, this.groupTitle); - 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/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/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/commits.scss b/app/assets/stylesheets/pages/commits.scss index bfa2a155cdf..994707422bb 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/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/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 c4c41eac5db..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 += ' · '.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 += ' · '.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 !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 << " ".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/notes_helper.rb b/app/helpers/notes_helper.rb index 083ace65b09..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) diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index d83c7411c9d..5946c475835 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -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 cec7656773c..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 !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/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 c439997d636..5ebe6f180e6 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) } diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 0e1b3b29e07..871c76fbad3 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_initialize :set_config_source, if: :new_record? 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/merge_request.rb b/app/models/merge_request.rb index b82f49d7073..2a56bab48a3 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -960,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_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/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/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/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/nav/_breadcrumbs.html.haml b/app/views/layouts/nav/_breadcrumbs.html.haml index ff0f6489861..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?(@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/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/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/projects/activity.html.haml b/app/views/projects/activity.html.haml index 2897c955c78..f80dadb8037 100644 --- a/app/views/projects/activity.html.haml +++ b/app/views/projects/activity.html.haml @@ -1,7 +1,7 @@ - @no_container = true -- 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" diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml index 67d9db9aefe..303e20e8780 100644 --- a/app/views/projects/boards/_show.html.haml +++ b/app/views/projects/boards/_show.html.haml @@ -1,8 +1,8 @@ - @no_breadcrumb_container = true - @no_container = true - @content_class = "issue-boards-content" +- breadcrumb_title "Issue Board" - page_title "Boards" -- add_to_breadcrumbs("Issues", project_issues_path(@project)) - content_for :page_specific_javascripts do = webpack_bundle_tag 'common_vue' 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" · %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" · #{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 b1834de0bad..73583c6bbc2 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -1,7 +1,5 @@ - @no_container = true - page_title "Branches" -- add_to_breadcrumbs("Repository", project_tree_path(@project)) - = render "projects/commits/head" %div{ class: container_class } 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 · = 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" %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 0f048079ef5..e873b931683 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -5,8 +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") -- 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 ecef91855af..2632fea6eba 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -1,6 +1,6 @@ - @no_container = true +- breadcrumb_title "Compare Revisions" - page_title "Compare" -- 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 eca733a933a..7cc42455394 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -1,7 +1,6 @@ - @no_container = true -- breadcrumb_title "Compare" +- add_to_breadcrumbs "Compare Revisions", project_compare_index_path(@project) - page_title "#{params[:from]}...#{params[:to]}" -- 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 5691024b997..8d008be5aae 100644 --- a/app/views/projects/cycle_analytics/show.html.haml +++ b/app/views/projects/cycle_analytics/show.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Cycle Analytics" -- 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/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 44bd8d1f9ad..f0ef647ddb3 100644 --- a/app/views/projects/graphs/charts.html.haml +++ b/app/views/projects/graphs/charts.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Charts" -- 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 2f60078796e..08b38428b50 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -5,8 +5,6 @@ = webpack_bundle_tag('graphs') = webpack_bundle_tag('graphs_show') -- 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/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 9751de0f938..8604c7d3ea4 100644 --- a/app/views/projects/jobs/index.html.haml +++ b/app/views/projects/jobs/index.html.haml @@ -2,8 +2,6 @@ - page_title "Jobs" = render "projects/pipelines/head" -- 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/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/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 2defd45a0b2..e29cb277389 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -2,7 +2,6 @@ - page_title "Graph", @ref - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('network') -- 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 83b51bae73d..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' @@ -11,8 +11,6 @@ - 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 } diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml index d710ba92cdd..487ac87186d 100644 --- a/app/views/projects/pipelines/charts.html.haml +++ b/app/views/projects/pipelines/charts.html.haml @@ -1,6 +1,6 @@ - @no_container = true +- breadcrumb_title "CI / CD Charts" - page_title _("Charts"), _("Pipelines") -- 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 - · - = 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 + · + = 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 c0a368dc475..324cd423ede 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 .form-group diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 5c3339cc749..25153fd0b6f 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -1,7 +1,5 @@ - page_title "Members" -- 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/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml index 2a829cd6c3d..eaf374bcb83 100644 --- a/app/views/projects/settings/ci_cd/show.html.haml +++ b/app/views/projects/settings/ci_cd/show.html.haml @@ -1,10 +1,54 @@ - @content_class = "limit-container-width" unless fluid_layout -- page_title "Pipelines" -- 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 1efa5907b3a..933daa7f549 100644 --- a/app/views/projects/settings/integrations/show.html.haml +++ b/app/views/projects/settings/integrations/show.html.haml @@ -1,6 +1,6 @@ - @content_class = "limit-container-width" unless fluid_layout +- breadcrumb_title "Integrations Settings" - page_title 'Integrations' -- 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 d4d461f6f22..6d4af72b8ea 100644 --- a/app/views/projects/settings/repository/show.html.haml +++ b/app/views/projects/settings/repository/show.html.haml @@ -1,6 +1,6 @@ +- breadcrumb_title "Repository Settings" - page_title "Repository" - @content_class = "limit-container-width" unless fluid_layout -- add_to_breadcrumbs("Settings", edit_project_path(@project)) = render "projects/settings/head" 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/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/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/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/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/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_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/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/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 399239dc8c4..73e4993e422 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1552,6 +1552,16 @@ ActiveRecord::Schema.define(version: 20170905112933) 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 @@ -1617,8 +1627,6 @@ ActiveRecord::Schema.define(version: 20170905112933) 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 @@ -1770,6 +1778,7 @@ ActiveRecord::Schema.define(version: 20170905112933) 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/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/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/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/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 9114b69606b..1d224d7bc21 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -291,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/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/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 & 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 & drop or %{upload_link}" +msgstr "Datei mittels Drag & 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 & 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 & drop or %{upload_link}" msgstr "Adjunte un archivo arrastrando & 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 & drop or %{upload_link}" msgstr "Attachez un fichier par glisser & 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 & 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 & drop or %{upload_link}" msgstr "Aggiungi un file tramite trascina & rilascia ( drag & 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 & 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 & 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 "ì´ ì»¤ë°‹ì„ 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 & 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 & drop or %{upload_link}" msgstr "Приложить файл через drag & 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 & 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 & 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 & 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 & 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/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('<h1>test</h1>') 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 68540dd4e59..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 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/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/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/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/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/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/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') |