)
- end
-
- let(:project) { create(:project) }
-
- shared_examples :preserve_unchanged do
- it 'does not modify any relative URL in anchor' do
- doc = filter(link('README.md'))
- expect(doc.at_css('a')['href']).to eq 'README.md'
- end
-
- it 'does not modify any relative URL in image' do
- doc = filter(image('files/images/logo-black.png'))
- expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
- end
- end
-
- it 'does not raise an exception on invalid URIs' do
- act = link("://foo")
- expect { filter(act) }.not_to raise_error
- end
-
- context 'with a valid repository' do
- it 'rebuilds relative URL for a link' do
- doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('a')['href'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
-
- doc = filter(nested_link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('a')['href'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
- end
-
- it 'rebuilds relative URL for an image' do
- doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('img')['src'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
-
- doc = filter(nested_image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('img')['src'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
- end
-
- it 'does not modify absolute URL' do
- doc = filter(link('http://example.com'))
- expect(doc.at_css('a')['href']).to eq 'http://example.com'
- end
-
- it 'supports Unicode filenames' do
- path = '/uploads/한글.png'
- escaped = Addressable::URI.escape(path)
-
- # Stub these methods so the file doesn't actually need to be in the repo
- allow_any_instance_of(described_class)
- .to receive(:file_exists?).and_return(true)
- allow_any_instance_of(described_class)
- .to receive(:image?).with(path).and_return(true)
-
- doc = filter(image(escaped))
- expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png"
- end
- end
-
- context 'in group context' do
- let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') }
- let(:group) { create(:group) }
- let(:filter_context) { { project: nil, group: group } }
- let(:relative_path) { "groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" }
-
- it 'rewrites the link correctly' do
- doc = raw_filter(upload_link, filter_context)
-
- expect(doc.at_css('a')['href']).to eq("#{Gitlab.config.gitlab.url}/#{relative_path}")
- end
-
- it 'rewrites the link correctly for subgroup' do
- subgroup = create(:group, parent: group)
- relative_path = "groups/#{subgroup.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
-
- doc = raw_filter(upload_link, { project: nil, group: subgroup })
-
- expect(doc.at_css('a')['href']).to eq("#{Gitlab.config.gitlab.url}/#{relative_path}")
- end
-
- it 'does not modify absolute URL' do
- doc = filter(link('http://example.com'), filter_context)
-
- expect(doc.at_css('a')['href']).to eq 'http://example.com'
- end
- end
-
- context 'when project or group context does not exist' do
- let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') }
-
- it 'does not raise error' do
- expect { raw_filter(upload_link, project: nil) }.not_to raise_error
- end
-
- it 'does not rewrite link' do
- doc = raw_filter(upload_link, project: nil)
-
- expect(doc.to_html).to eq upload_link
- end
- end
-end
--
cgit v1.2.1
From 16b8297e77501134cd93a74c3d5c60712930e7fd Mon Sep 17 00:00:00 2001
From: Douwe Maan
Date: Fri, 22 Dec 2017 11:38:35 +0100
Subject: Execute project hooks and services after commit when moving an issue
---
app/models/project.rb | 16 +++++++++++-----
.../unreleased/dm-issue-move-transaction-error.yml | 5 +++++
config/initializers/forbid_sidekiq_in_transactions.rb | 8 +++++---
lib/after_commit_queue.rb | 10 +++++++++-
spec/services/issues/move_service_spec.rb | 12 ++++++++++++
5 files changed, 42 insertions(+), 9 deletions(-)
create mode 100644 changelogs/unreleased/dm-issue-move-transaction-error.yml
diff --git a/app/models/project.rb b/app/models/project.rb
index 3440c01b356..f9c640300ff 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -951,7 +951,9 @@ class Project < ActiveRecord::Base
def send_move_instructions(old_path_with_namespace)
# New project path needs to be committed to the DB or notification will
# retrieve stale information
- run_after_commit { NotificationService.new.project_was_moved(self, old_path_with_namespace) }
+ run_after_commit do
+ NotificationService.new.project_was_moved(self, old_path_with_namespace)
+ end
end
def owner
@@ -963,15 +965,19 @@ class Project < ActiveRecord::Base
end
def execute_hooks(data, hooks_scope = :push_hooks)
- hooks.public_send(hooks_scope).each do |hook| # rubocop:disable GitlabSecurity/PublicSend
- hook.async_execute(data, hooks_scope.to_s)
+ run_after_commit_or_now do
+ hooks.public_send(hooks_scope).each do |hook| # rubocop:disable GitlabSecurity/PublicSend
+ hook.async_execute(data, hooks_scope.to_s)
+ end
end
end
def execute_services(data, hooks_scope = :push_hooks)
# Call only service hooks that are active for this scope
- services.public_send(hooks_scope).each do |service| # rubocop:disable GitlabSecurity/PublicSend
- service.async_execute(data)
+ run_after_commit_or_now do
+ services.public_send(hooks_scope).each do |service| # rubocop:disable GitlabSecurity/PublicSend
+ service.async_execute(data)
+ end
end
end
diff --git a/changelogs/unreleased/dm-issue-move-transaction-error.yml b/changelogs/unreleased/dm-issue-move-transaction-error.yml
new file mode 100644
index 00000000000..0892169894a
--- /dev/null
+++ b/changelogs/unreleased/dm-issue-move-transaction-error.yml
@@ -0,0 +1,5 @@
+---
+title: Execute project hooks and services after commit when moving an issue
+merge_request:
+author:
+type: fixed
diff --git a/config/initializers/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb
index bedd57ede04..cb611aa21df 100644
--- a/config/initializers/forbid_sidekiq_in_transactions.rb
+++ b/config/initializers/forbid_sidekiq_in_transactions.rb
@@ -1,5 +1,7 @@
module Sidekiq
module Worker
+ EnqueueFromTransactionError = Class.new(StandardError)
+
mattr_accessor :skip_transaction_check
self.skip_transaction_check = false
@@ -12,11 +14,11 @@ module Sidekiq
end
module ClassMethods
- module NoSchedulingFromTransactions
+ module NoEnqueueingFromTransactions
%i(perform_async perform_at perform_in).each do |name|
define_method(name) do |*args|
if !Sidekiq::Worker.skip_transaction_check && AfterCommitQueue.inside_transaction?
- raise <<-MSG.strip_heredoc
+ raise Sidekiq::Worker::EnqueueFromTransactionError, <<~MSG
`#{self}.#{name}` cannot be called inside a transaction as this can lead to
race conditions when the worker runs before the transaction is committed and
tries to access a model that has not been saved yet.
@@ -30,7 +32,7 @@ module Sidekiq
end
end
- prepend NoSchedulingFromTransactions
+ prepend NoEnqueueingFromTransactions
end
end
end
diff --git a/lib/after_commit_queue.rb b/lib/after_commit_queue.rb
index db63c5038ae..a4d8507960e 100644
--- a/lib/after_commit_queue.rb
+++ b/lib/after_commit_queue.rb
@@ -14,7 +14,15 @@ module AfterCommitQueue
def run_after_commit_or_now(&block)
if AfterCommitQueue.inside_transaction?
- run_after_commit(&block)
+ if ActiveRecord::Base.connection.current_transaction.records.include?(self)
+ run_after_commit(&block)
+ else
+ # If the current transaction does not include this record, we can run
+ # the block now, even if it queues a Sidekiq job.
+ Sidekiq::Worker.skipping_transaction_check do
+ instance_eval(&block)
+ end
+ end
else
instance_eval(&block)
end
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index f2b35a8fadf..2cad695d7c4 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -289,6 +289,18 @@ describe Issues::MoveService do
.to raise_error(StandardError, /Cannot move issue/)
end
end
+
+ context 'project issue hooks' do
+ let(:hook) { create(:project_hook, project: old_project, issues_events: true) }
+
+ it 'executes project issue hooks' do
+ # Ideally, we'd test that `WebHookWorker.jobs.size` increased by 1,
+ # but since the entire spec run takes place in a transaction, we never
+ # actually get to the `after_commit` hook that queues these jobs.
+ expect { move_service.execute(old_issue, new_project) }
+ .not_to raise_error # Sidekiq::Worker::EnqueueFromTransactionError
+ end
+ end
end
describe 'move permissions' do
--
cgit v1.2.1
From 5d6fea1bb98355081fc94f299a4b01cd986c6bdb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?=
Date: Fri, 22 Dec 2017 18:02:48 +0100
Subject: Reverted fix
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15788
---
app/models/event.rb | 2 +-
changelogs/unreleased/fix-event-target-author-preloading.yml | 5 -----
2 files changed, 1 insertion(+), 6 deletions(-)
delete mode 100644 changelogs/unreleased/fix-event-target-author-preloading.yml
diff --git a/app/models/event.rb b/app/models/event.rb
index 6053594fab5..0997b056c6a 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -72,7 +72,7 @@ class Event < ActiveRecord::Base
# We're using preload for "push_event_payload" as otherwise the association
# is not always available (depending on the query being built).
includes(:author, :project, project: :namespace)
- .preload(:push_event_payload, target: :author)
+ .preload(:target, :push_event_payload)
end
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
diff --git a/changelogs/unreleased/fix-event-target-author-preloading.yml b/changelogs/unreleased/fix-event-target-author-preloading.yml
deleted file mode 100644
index c6154cc0835..00000000000
--- a/changelogs/unreleased/fix-event-target-author-preloading.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix N+1 query when displaying events
-merge_request:
-author:
-type: performance
--
cgit v1.2.1
From 771bf9527ffd5fd8fe258381593f686d5d960a42 Mon Sep 17 00:00:00 2001
From: Douwe Maan
Date: Fri, 22 Dec 2017 12:49:56 +0100
Subject: Improve performance of DiffDiscussion#truncated_diff_lines and
DiffNote#diff_line by removing expensive diff position calculation and
comparison
---
app/models/concerns/discussion_on_diff.rb | 10 ++++------
app/models/concerns/note_on_diff.rb | 4 ----
app/models/diff_note.rb | 6 +-----
app/models/legacy_diff_note.rb | 6 +-----
.../unreleased/dm-diff-note-for-line-performance.yml | 5 +++++
lib/gitlab/diff/file.rb | 4 +++-
spec/models/diff_note_spec.rb | 16 ----------------
7 files changed, 14 insertions(+), 37 deletions(-)
create mode 100644 changelogs/unreleased/dm-diff-note-for-line-performance.yml
diff --git a/app/models/concerns/discussion_on_diff.rb b/app/models/concerns/discussion_on_diff.rb
index 4b4d519f3df..db9770fabf4 100644
--- a/app/models/concerns/discussion_on_diff.rb
+++ b/app/models/concerns/discussion_on_diff.rb
@@ -9,7 +9,6 @@ module DiscussionOnDiff
:original_line_code,
:diff_file,
:diff_line,
- :for_line?,
:active?,
:created_at_diff?,
@@ -39,17 +38,16 @@ module DiscussionOnDiff
# Returns an array of at most 16 highlighted lines above a diff note
def truncated_diff_lines(highlight: true)
lines = highlight ? highlighted_diff_lines : diff_lines
+
+ initial_line_index = [diff_line.index - NUMBER_OF_TRUNCATED_DIFF_LINES + 1, 0].max
+
prev_lines = []
- lines.each do |line|
+ lines[initial_line_index..diff_line.index].each do |line|
if line.meta?
prev_lines.clear
else
prev_lines << line
-
- break if for_line?(line)
-
- prev_lines.shift if prev_lines.length >= NUMBER_OF_TRUNCATED_DIFF_LINES
end
end
diff --git a/app/models/concerns/note_on_diff.rb b/app/models/concerns/note_on_diff.rb
index f734952fa6c..510b8868462 100644
--- a/app/models/concerns/note_on_diff.rb
+++ b/app/models/concerns/note_on_diff.rb
@@ -14,10 +14,6 @@ module NoteOnDiff
raise NotImplementedError
end
- def for_line?(line)
- raise NotImplementedError
- end
-
def original_line_code
raise NotImplementedError
end
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index b53d44cda95..15122cbc693 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -21,7 +21,7 @@ class DiffNote < Note
before_validation :set_original_position, on: :create
before_validation :update_position, on: :create, if: :on_text?
- before_validation :set_line_code
+ before_validation :set_line_code, if: :on_text?
after_save :keep_around_commits
def discussion_class(*)
@@ -61,10 +61,6 @@ class DiffNote < Note
@diff_line ||= diff_file&.line_for_position(self.original_position)
end
- def for_line?(line)
- diff_file.position(line) == self.original_position
- end
-
def original_line_code
return unless on_text?
diff --git a/app/models/legacy_diff_note.rb b/app/models/legacy_diff_note.rb
index c36be956ff0..d90cafd14b4 100644
--- a/app/models/legacy_diff_note.rb
+++ b/app/models/legacy_diff_note.rb
@@ -38,11 +38,7 @@ class LegacyDiffNote < Note
end
def diff_line
- @diff_line ||= diff_file.line_for_line_code(self.line_code) if diff_file
- end
-
- def for_line?(line)
- line.discussable? && diff_file.line_code(line) == self.line_code
+ @diff_line ||= diff_file&.line_for_line_code(self.line_code)
end
def original_line_code
diff --git a/changelogs/unreleased/dm-diff-note-for-line-performance.yml b/changelogs/unreleased/dm-diff-note-for-line-performance.yml
new file mode 100644
index 00000000000..cbc418ab103
--- /dev/null
+++ b/changelogs/unreleased/dm-diff-note-for-line-performance.yml
@@ -0,0 +1,5 @@
+---
+title: Improve performance of MR discussions on large diffs
+merge_request:
+author:
+type: performance
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index d0cfe2386ca..cd490aaa291 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -61,7 +61,9 @@ module Gitlab
end
def line_for_position(pos)
- diff_lines.find { |line| position(line) == pos }
+ return nil unless pos.position_type == 'text'
+
+ diff_lines.find { |line| line.old_line == pos.old_line && line.new_line == pos.new_line }
end
def position_for_line_code(code)
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 4d0b3245a13..2705421e540 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -112,22 +112,6 @@ describe DiffNote do
end
end
- describe "#for_line?" do
- context "when provided the correct diff line" do
- it "returns true" do
- expect(subject.for_line?(subject.diff_line)).to be true
- end
- end
-
- context "when provided a different diff line" do
- it "returns false" do
- some_line = subject.diff_file.diff_lines.first
-
- expect(subject.for_line?(some_line)).to be false
- end
- end
- end
-
describe "#active?" do
context "when noteable is a commit" do
subject { build(:diff_note_on_commit, project: project, position: position) }
--
cgit v1.2.1
From 26b3a0b34b94d4961ff9f7596cd512fb08c1dd67 Mon Sep 17 00:00:00 2001
From: Marcia Ramos
Date: Fri, 22 Dec 2017 17:15:08 +0000
Subject: Docs: move article LDAP-CE to its topic-related folder
---
.../img/gitlab_ou.png | Bin 0 -> 27877 bytes
.../img/ldap_ou.gif | Bin 0 -> 222162 bytes
.../img/user_auth.gif | Bin 0 -> 110971 bytes
.../auth/how_to_configure_ldap_gitlab_ce/index.md | 267 ++++++++++++++++++++
doc/administration/auth/ldap.md | 3 +
.../img/gitlab_ou.png | Bin 27877 -> 0 bytes
.../img/ldap_ou.gif | Bin 222162 -> 0 bytes
.../img/user_auth.gif | Bin 110971 -> 0 bytes
.../how_to_configure_ldap_gitlab_ce/index.md | 268 +--------------------
doc/articles/index.md | 10 -
doc/topics/authentication/index.md | 2 +-
11 files changed, 272 insertions(+), 278 deletions(-)
create mode 100644 doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png
create mode 100644 doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif
create mode 100644 doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/user_auth.gif
create mode 100644 doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
delete mode 100644 doc/articles/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png
delete mode 100644 doc/articles/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif
delete mode 100644 doc/articles/how_to_configure_ldap_gitlab_ce/img/user_auth.gif
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png
new file mode 100644
index 00000000000..11ce324f938
Binary files /dev/null and b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png differ
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif
new file mode 100644
index 00000000000..a6727a3d85f
Binary files /dev/null and b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif differ
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/user_auth.gif b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/user_auth.gif
new file mode 100644
index 00000000000..36e6085259f
Binary files /dev/null and b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/user_auth.gif differ
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
new file mode 100644
index 00000000000..9b9b8ca89e5
--- /dev/null
+++ b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
@@ -0,0 +1,267 @@
+# How to configure LDAP with GitLab CE
+
+> **[Article Type](../../../development/writing_documentation.html#types-of-technical-articles):** admin guide ||
+> **Level:** intermediary ||
+> **Author:** [Chris Wilson](https://gitlab.com/MrChrisW) ||
+> **Publication date:** 2017-05-03
+
+## Introduction
+
+Managing a large number of users in GitLab can become a burden for system administrators. As an organization grows so do user accounts. Keeping these user accounts in sync across multiple enterprise applications often becomes a time consuming task.
+
+In this guide we will focus on configuring GitLab with Active Directory. [Active Directory](https://en.wikipedia.org/wiki/Active_Directory) is a popular LDAP compatible directory service provided by Microsoft, included in all modern Windows Server operating systems.
+
+GitLab has supported LDAP integration since [version 2.2](https://about.gitlab.com/2012/02/22/gitlab-version-2-2/). With GitLab LDAP [group syncing](#group-syncing-ee) being added to GitLab Enterprise Edition in [version 6.0](https://about.gitlab.com/2013/08/20/gitlab-6-dot-0-released/). LDAP integration has become one of the most popular features in GitLab.
+
+## Getting started
+
+### Choosing an LDAP Server
+
+The main reason organizations choose to utilize a LDAP server is to keep the entire organization's user base consolidated into a central repository. Users can access multiple applications and systems across the IT environment using a single login. Because LDAP is an open, vendor-neutral, industry standard application protocol, the number of applications using LDAP authentication continues to increase.
+
+There are many commercial and open source [directory servers](https://en.wikipedia.org/wiki/Directory_service#LDAP_implementations) that support the LDAP protocol. Deciding on the right directory server highly depends on the existing IT environment in which the server will be integrated with.
+
+For example, [Active Directory](https://technet.microsoft.com/en-us/library/hh831484(v=ws.11).aspx) is generally favored in a primarily Windows environment, as this allows quick integration with existing services. Other popular directory services include:
+
+- [Oracle Internet Directory](http://www.oracle.com/technetwork/middleware/id-mgmt/overview/index-082035.html)
+- [OpenLDAP](http://www.openldap.org/)
+- [389 Directory](http://directory.fedoraproject.org/)
+- [OpenDJ](https://forgerock.org/opendj/)
+- [ApacheDS](https://directory.apache.org/)
+
+> GitLab uses the [Net::LDAP](https://rubygems.org/gems/net-ldap) library under the hood. This means it supports all [IETF](https://tools.ietf.org/html/rfc2251) compliant LDAPv3 servers.
+
+### Active Directory (AD)
+
+We won't cover the installation and configuration of Windows Server or Active Directory Domain Services in this tutorial. There are a number of resources online to guide you through this process:
+
+- Install Windows Server 2012 - (_technet.microsoft.com_) - [Installing Windows Server 2012 ](https://technet.microsoft.com/en-us/library/jj134246(v=ws.11).aspx)
+
+- Install Active Directory Domain Services (AD DS) (_technet.microsoft.com_)- [Install Active Directory Domain Services](https://technet.microsoft.com/windows-server-docs/identity/ad-ds/deploy/install-active-directory-domain-services--level-100-#BKMK_PS)
+
+> **Shortcut:** You can quickly install AD DS via PowerShell using
+`Install-WindowsFeature AD-Domain-Services -IncludeManagementTools`
+
+### Creating an AD **OU** structure
+
+Configuring organizational units (**OU**s) is an important part of setting up Active Directory. **OU**s form the base for an entire organizational structure. Using GitLab as an example we have designed the **OU** structure below using the geographic **OU** model. In the Geographic Model we separate **OU**s for different geographic regions.
+
+| GitLab **OU** Design | GitLab AD Structure |
+| :----------------------------: | :------------------------------: |
+| ![GitLab OU Design][gitlab_ou] | ![GitLab AD Structure][ldap_ou] |
+
+[gitlab_ou]: img/gitlab_ou.png
+[ldap_ou]: img/ldap_ou.gif
+
+Using PowerShell you can output the **OU** structure as a table (_all names are examples only_):
+
+```ps
+Get-ADObject -LDAPFilter "(objectClass=*)" -SearchBase 'OU=GitLab INT,DC=GitLab,DC=org' -Properties CanonicalName | Format-Table Name,CanonicalName -A
+```
+
+```
+OU CanonicalName
+---- -------------
+GitLab INT GitLab.org/GitLab INT
+United States GitLab.org/GitLab INT/United States
+Developers GitLab.org/GitLab INT/United States/Developers
+Gary Johnson GitLab.org/GitLab INT/United States/Developers/Gary Johnson
+Ellis Matthews GitLab.org/GitLab INT/United States/Developers/Ellis Matthews
+William Collins GitLab.org/GitLab INT/United States/Developers/William Collins
+People Ops GitLab.org/GitLab INT/United States/People Ops
+Margaret Baker GitLab.org/GitLab INT/United States/People Ops/Margaret Baker
+Libby Hartzler GitLab.org/GitLab INT/United States/People Ops/Libby Hartzler
+Victoria Ryles GitLab.org/GitLab INT/United States/People Ops/Victoria Ryles
+The Netherlands GitLab.org/GitLab INT/The Netherlands
+Developers GitLab.org/GitLab INT/The Netherlands/Developers
+John Doe GitLab.org/GitLab INT/The Netherlands/Developers/John Doe
+Jon Mealy GitLab.org/GitLab INT/The Netherlands/Developers/Jon Mealy
+Jane Weingarten GitLab.org/GitLab INT/The Netherlands/Developers/Jane Weingarten
+Production GitLab.org/GitLab INT/The Netherlands/Production
+Sarah Konopka GitLab.org/GitLab INT/The Netherlands/Production/Sarah Konopka
+Cynthia Bruno GitLab.org/GitLab INT/The Netherlands/Production/Cynthia Bruno
+David George GitLab.org/GitLab INT/The Netherlands/Production/David George
+United Kingdom GitLab.org/GitLab INT/United Kingdom
+Developers GitLab.org/GitLab INT/United Kingdom/Developers
+Leroy Fox GitLab.org/GitLab INT/United Kingdom/Developers/Leroy Fox
+Christopher Alley GitLab.org/GitLab INT/United Kingdom/Developers/Christopher Alley
+Norris Morita GitLab.org/GitLab INT/United Kingdom/Developers/Norris Morita
+Support GitLab.org/GitLab INT/United Kingdom/Support
+Laura Stanley GitLab.org/GitLab INT/United Kingdom/Support/Laura Stanley
+Nikki Schuman GitLab.org/GitLab INT/United Kingdom/Support/Nikki Schuman
+Harriet Butcher GitLab.org/GitLab INT/United Kingdom/Support/Harriet Butcher
+Global Groups GitLab.org/GitLab INT/Global Groups
+DevelopersNL GitLab.org/GitLab INT/Global Groups/DevelopersNL
+DevelopersUK GitLab.org/GitLab INT/Global Groups/DevelopersUK
+DevelopersUS GitLab.org/GitLab INT/Global Groups/DevelopersUS
+ProductionNL GitLab.org/GitLab INT/Global Groups/ProductionNL
+SupportUK GitLab.org/GitLab INT/Global Groups/SupportUK
+People Ops US GitLab.org/GitLab INT/Global Groups/People Ops US
+Global Admins GitLab.org/GitLab INT/Global Groups/Global Admins
+```
+
+> See [more information](https://technet.microsoft.com/en-us/library/ff730967.aspx) on searching Active Directory with Windows PowerShell from [The Scripting Guys](https://technet.microsoft.com/en-us/scriptcenter/dd901334.aspx)
+
+## GitLab LDAP configuration
+
+The initial configuration of LDAP in GitLab requires changes to the `gitlab.rb` configuration file. Below is an example of a complete configuration using an Active Directory.
+
+The two Active Directory specific values are `active_directory: true` and `uid: 'sAMAccountName'`. `sAMAccountName` is an attribute returned by Active Directory used for GitLab usernames. See the example output from `ldapsearch` for a full list of attributes a "person" object (user) has in **AD** - [`ldapsearch` example](#using-ldapsearch-unix)
+
+> Both group_base and admin_group configuration options are only available in GitLab Enterprise Edition. See [GitLab EE - LDAP Features](#gitlab-enterprise-edition---ldap-features)
+
+### Example `gitlab.rb` LDAP
+
+```
+gitlab_rails['ldap_enabled'] = true
+gitlab_rails['ldap_servers'] = {
+'main' => {
+ 'label' => 'GitLab AD',
+ 'host' => 'ad.example.org',
+ 'port' => 636,
+ 'uid' => 'sAMAccountName',
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true,
+ 'bind_dn' => 'CN=GitLabSRV,CN=Users,DC=GitLab,DC=org',
+ 'password' => 'Password1',
+ 'active_directory' => true,
+ 'base' => 'OU=GitLab INT,DC=GitLab,DC=org',
+ 'group_base' => 'OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org',
+ 'admin_group' => 'Global Admins'
+ }
+}
+```
+
+> **Note:** Remember to run `gitlab-ctl reconfigure` after modifying `gitlab.rb`
+
+## Security improvements (LDAPS)
+
+Security is an important aspect when deploying an LDAP server. By default, LDAP traffic is transmitted unsecured. LDAP can be secured using SSL/TLS called LDAPS, or commonly "LDAP over SSL".
+
+Securing LDAP (enabling LDAPS) on Windows Server 2012 involves installing a valid SSL certificate. For full details see Microsoft's guide [How to enable LDAP over SSL with a third-party certification authority](https://support.microsoft.com/en-us/help/321051/how-to-enable-ldap-over-ssl-with-a-third-party-certification-authority)
+
+> By default a LDAP service listens for connections on TCP and UDP port 389. LDAPS (LDAP over SSL) listens on port 636
+
+### Testing you AD server
+
+#### Using **AdFind** (Windows)
+
+You can use the [`AdFind`](https://social.technet.microsoft.com/wiki/contents/articles/7535.adfind-command-examples.aspx) utility (on Windows based systems) to test that your LDAP server is accessible and authentication is working correctly. This is a freeware utility built by [Joe Richards](http://www.joeware.net/freetools/tools/adfind/index.htm).
+
+**Return all objects**
+
+You can use the filter `objectclass=*` to return all directory objects.
+
+```sh
+adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (objectClass=*)
+```
+
+**Return single object using filter**
+
+You can also retrieve a single object by **specifying** the object name or full **DN**. In this example we specify the object name only `CN=Leroy Fox`.
+
+```sh
+adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (&(objectcategory=person)(CN=Leroy Fox))”
+```
+
+#### Using **ldapsearch** (Unix)
+
+You can use the `ldapsearch` utility (on Unix based systems) to test that your LDAP server is accessible and authentication is working correctly. This utility is included in the [`ldap-utils`](https://wiki.debian.org/LDAP/LDAPUtils) package.
+
+**Return all objects**
+
+You can use the filter `objectclass=*` to return all directory objects.
+
+```sh
+ldapsearch -D "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" \
+-w Password1 -p 636 -h ad.example.org \
+-b "OU=GitLab INT,DC=GitLab,DC=org" -Z \
+-s sub "(objectclass=*)"
+```
+
+**Return single object using filter**
+
+You can also retrieve a single object by **specifying** the object name or full **DN**. In this example we specify the object name only `CN=Leroy Fox`.
+
+```sh
+ldapsearch -D "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -w Password1 -p 389 -h ad.example.org -b "OU=GitLab INT,DC=GitLab,DC=org" -Z -s sub "CN=Leroy Fox"
+```
+
+**Full output of `ldapsearch` command:** - Filtering for _CN=Leroy Fox_
+
+```
+# LDAPv3
+# base with scope subtree
+# filter: CN=Leroy Fox
+# requesting: ALL
+#
+
+# Leroy Fox, Developers, United Kingdom, GitLab INT, GitLab.org
+dn: CN=Leroy Fox,OU=Developers,OU=United Kingdom,OU=GitLab INT,DC=GitLab,DC=or
+ g
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+cn: Leroy Fox
+sn: Fox
+givenName: Leroy
+distinguishedName: CN=Leroy Fox,OU=Developers,OU=United Kingdom,OU=GitLab INT,
+ DC=GitLab,DC=org
+instanceType: 4
+whenCreated: 20170210030500.0Z
+whenChanged: 20170213050128.0Z
+displayName: Leroy Fox
+uSNCreated: 16790
+memberOf: CN=DevelopersUK,OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org
+uSNChanged: 20812
+name: Leroy Fox
+objectGUID:: rBCAo6NR6E6vfSKgzcUILg==
+userAccountControl: 512
+badPwdCount: 0
+codePage: 0
+countryCode: 0
+badPasswordTime: 0
+lastLogoff: 0
+lastLogon: 0
+pwdLastSet: 131311695009850084
+primaryGroupID: 513
+objectSid:: AQUAAAAAAAUVAAAA9GMAb7tdJZvsATf7ZwQAAA==
+accountExpires: 9223372036854775807
+logonCount: 0
+sAMAccountName: Leroyf
+sAMAccountType: 805306368
+userPrincipalName: Leroyf@GitLab.org
+objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=GitLab,DC=org
+dSCorePropagationData: 16010101000000.0Z
+lastLogonTimestamp: 131314356887754250
+
+# search result
+search: 2
+result: 0 Success
+
+# numResponses: 2
+# numEntries: 1
+```
+
+## Basic user authentication
+
+After configuring LDAP, basic authentication will be available. Users can then login using their directory credentials. An extra tab is added to the GitLab login screen for the configured LDAP server (e.g "**GitLab AD**").
+
+
+
+Users that are removed from the LDAP base group (e.g `OU=GitLab INT,DC=GitLab,DC=org`) will be **blocked** in GitLab. [More information](../ldap.md#security) on LDAP security.
+
+If `allow_username_or_email_login` is enabled in the LDAP configuration, GitLab will ignore everything after the first '@' in the LDAP username used on login. Example: The username `jon.doe@example.com` is converted to `jon.doe` when authenticating with the LDAP server. Disable this setting if you use `userPrincipalName` as the `uid`.
+
+## LDAP extended features on GitLab EE
+
+With [GitLab Enterprise Edition (EE)](https://about.gitlab.com/gitlab-ee/), besides everything we just described, you'll
+have extended functionalities with LDAP, such as:
+
+- Group sync
+- Group permissions
+- Updating user permissions
+- Multiple LDAP servers
+
+Read through the article on [LDAP for GitLab EE](https://docs.gitlab.com/ee/administration/auth/how_to_configure_ldap_gitlab_ee/) for an overview.
diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index 6b5a0f139c5..881b6a827f4 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -38,6 +38,9 @@ in the application settings.
## Configuration
+For a complete guide on configuring LDAP with GitLab Community Edition, please check
+the admin guide [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md).
+
To enable LDAP integration you need to add your LDAP server settings in
`/etc/gitlab/gitlab.rb` or `/home/git/gitlab/config/gitlab.yml`.
diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png b/doc/articles/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png
deleted file mode 100644
index 11ce324f938..00000000000
Binary files a/doc/articles/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png and /dev/null differ
diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif b/doc/articles/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif
deleted file mode 100644
index a6727a3d85f..00000000000
Binary files a/doc/articles/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif and /dev/null differ
diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/img/user_auth.gif b/doc/articles/how_to_configure_ldap_gitlab_ce/img/user_auth.gif
deleted file mode 100644
index 36e6085259f..00000000000
Binary files a/doc/articles/how_to_configure_ldap_gitlab_ce/img/user_auth.gif and /dev/null differ
diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md b/doc/articles/how_to_configure_ldap_gitlab_ce/index.md
index 25a24bc1d32..a8320c12e6b 100644
--- a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md
+++ b/doc/articles/how_to_configure_ldap_gitlab_ce/index.md
@@ -1,267 +1 @@
-# How to configure LDAP with GitLab CE
-
-> **Article [Type](../../development/writing_documentation.html#types-of-technical-articles):** admin guide ||
-> **Level:** intermediary ||
-> **Author:** [Chris Wilson](https://gitlab.com/MrChrisW) ||
-> **Publication date:** 2017-05-03
-
-## Introduction
-
-Managing a large number of users in GitLab can become a burden for system administrators. As an organization grows so do user accounts. Keeping these user accounts in sync across multiple enterprise applications often becomes a time consuming task.
-
-In this guide we will focus on configuring GitLab with Active Directory. [Active Directory](https://en.wikipedia.org/wiki/Active_Directory) is a popular LDAP compatible directory service provided by Microsoft, included in all modern Windows Server operating systems.
-
-GitLab has supported LDAP integration since [version 2.2](https://about.gitlab.com/2012/02/22/gitlab-version-2-2/). With GitLab LDAP [group syncing](#group-syncing-ee) being added to GitLab Enterprise Edition in [version 6.0](https://about.gitlab.com/2013/08/20/gitlab-6-dot-0-released/). LDAP integration has become one of the most popular features in GitLab.
-
-## Getting started
-
-### Choosing an LDAP Server
-
-The main reason organizations choose to utilize a LDAP server is to keep the entire organization's user base consolidated into a central repository. Users can access multiple applications and systems across the IT environment using a single login. Because LDAP is an open, vendor-neutral, industry standard application protocol, the number of applications using LDAP authentication continues to increase.
-
-There are many commercial and open source [directory servers](https://en.wikipedia.org/wiki/Directory_service#LDAP_implementations) that support the LDAP protocol. Deciding on the right directory server highly depends on the existing IT environment in which the server will be integrated with.
-
-For example, [Active Directory](https://technet.microsoft.com/en-us/library/hh831484(v=ws.11).aspx) is generally favored in a primarily Windows environment, as this allows quick integration with existing services. Other popular directory services include:
-
-- [Oracle Internet Directory](http://www.oracle.com/technetwork/middleware/id-mgmt/overview/index-082035.html)
-- [OpenLDAP](http://www.openldap.org/)
-- [389 Directory](http://directory.fedoraproject.org/)
-- [OpenDJ](https://forgerock.org/opendj/)
-- [ApacheDS](https://directory.apache.org/)
-
-> GitLab uses the [Net::LDAP](https://rubygems.org/gems/net-ldap) library under the hood. This means it supports all [IETF](https://tools.ietf.org/html/rfc2251) compliant LDAPv3 servers.
-
-### Active Directory (AD)
-
-We won't cover the installation and configuration of Windows Server or Active Directory Domain Services in this tutorial. There are a number of resources online to guide you through this process:
-
-- Install Windows Server 2012 - (_technet.microsoft.com_) - [Installing Windows Server 2012 ](https://technet.microsoft.com/en-us/library/jj134246(v=ws.11).aspx)
-
-- Install Active Directory Domain Services (AD DS) (_technet.microsoft.com_)- [Install Active Directory Domain Services](https://technet.microsoft.com/windows-server-docs/identity/ad-ds/deploy/install-active-directory-domain-services--level-100-#BKMK_PS)
-
-> **Shortcut:** You can quickly install AD DS via PowerShell using
-`Install-WindowsFeature AD-Domain-Services -IncludeManagementTools`
-
-### Creating an AD **OU** structure
-
-Configuring organizational units (**OU**s) is an important part of setting up Active Directory. **OU**s form the base for an entire organizational structure. Using GitLab as an example we have designed the **OU** structure below using the geographic **OU** model. In the Geographic Model we separate **OU**s for different geographic regions.
-
-| GitLab **OU** Design | GitLab AD Structure |
-| :----------------------------: | :------------------------------: |
-| ![GitLab OU Design][gitlab_ou] | ![GitLab AD Structure][ldap_ou] |
-
-[gitlab_ou]: img/gitlab_ou.png
-[ldap_ou]: img/ldap_ou.gif
-
-Using PowerShell you can output the **OU** structure as a table (_all names are examples only_):
-
-```ps
-Get-ADObject -LDAPFilter "(objectClass=*)" -SearchBase 'OU=GitLab INT,DC=GitLab,DC=org' -Properties CanonicalName | Format-Table Name,CanonicalName -A
-```
-
-```
-OU CanonicalName
----- -------------
-GitLab INT GitLab.org/GitLab INT
-United States GitLab.org/GitLab INT/United States
-Developers GitLab.org/GitLab INT/United States/Developers
-Gary Johnson GitLab.org/GitLab INT/United States/Developers/Gary Johnson
-Ellis Matthews GitLab.org/GitLab INT/United States/Developers/Ellis Matthews
-William Collins GitLab.org/GitLab INT/United States/Developers/William Collins
-People Ops GitLab.org/GitLab INT/United States/People Ops
-Margaret Baker GitLab.org/GitLab INT/United States/People Ops/Margaret Baker
-Libby Hartzler GitLab.org/GitLab INT/United States/People Ops/Libby Hartzler
-Victoria Ryles GitLab.org/GitLab INT/United States/People Ops/Victoria Ryles
-The Netherlands GitLab.org/GitLab INT/The Netherlands
-Developers GitLab.org/GitLab INT/The Netherlands/Developers
-John Doe GitLab.org/GitLab INT/The Netherlands/Developers/John Doe
-Jon Mealy GitLab.org/GitLab INT/The Netherlands/Developers/Jon Mealy
-Jane Weingarten GitLab.org/GitLab INT/The Netherlands/Developers/Jane Weingarten
-Production GitLab.org/GitLab INT/The Netherlands/Production
-Sarah Konopka GitLab.org/GitLab INT/The Netherlands/Production/Sarah Konopka
-Cynthia Bruno GitLab.org/GitLab INT/The Netherlands/Production/Cynthia Bruno
-David George GitLab.org/GitLab INT/The Netherlands/Production/David George
-United Kingdom GitLab.org/GitLab INT/United Kingdom
-Developers GitLab.org/GitLab INT/United Kingdom/Developers
-Leroy Fox GitLab.org/GitLab INT/United Kingdom/Developers/Leroy Fox
-Christopher Alley GitLab.org/GitLab INT/United Kingdom/Developers/Christopher Alley
-Norris Morita GitLab.org/GitLab INT/United Kingdom/Developers/Norris Morita
-Support GitLab.org/GitLab INT/United Kingdom/Support
-Laura Stanley GitLab.org/GitLab INT/United Kingdom/Support/Laura Stanley
-Nikki Schuman GitLab.org/GitLab INT/United Kingdom/Support/Nikki Schuman
-Harriet Butcher GitLab.org/GitLab INT/United Kingdom/Support/Harriet Butcher
-Global Groups GitLab.org/GitLab INT/Global Groups
-DevelopersNL GitLab.org/GitLab INT/Global Groups/DevelopersNL
-DevelopersUK GitLab.org/GitLab INT/Global Groups/DevelopersUK
-DevelopersUS GitLab.org/GitLab INT/Global Groups/DevelopersUS
-ProductionNL GitLab.org/GitLab INT/Global Groups/ProductionNL
-SupportUK GitLab.org/GitLab INT/Global Groups/SupportUK
-People Ops US GitLab.org/GitLab INT/Global Groups/People Ops US
-Global Admins GitLab.org/GitLab INT/Global Groups/Global Admins
-```
-
-> See [more information](https://technet.microsoft.com/en-us/library/ff730967.aspx) on searching Active Directory with Windows PowerShell from [The Scripting Guys](https://technet.microsoft.com/en-us/scriptcenter/dd901334.aspx)
-
-## GitLab LDAP configuration
-
-The initial configuration of LDAP in GitLab requires changes to the `gitlab.rb` configuration file. Below is an example of a complete configuration using an Active Directory.
-
-The two Active Directory specific values are `active_directory: true` and `uid: 'sAMAccountName'`. `sAMAccountName` is an attribute returned by Active Directory used for GitLab usernames. See the example output from `ldapsearch` for a full list of attributes a "person" object (user) has in **AD** - [`ldapsearch` example](#using-ldapsearch-unix)
-
-> Both group_base and admin_group configuration options are only available in GitLab Enterprise Edition. See [GitLab EE - LDAP Features](#gitlab-enterprise-edition---ldap-features)
-
-### Example `gitlab.rb` LDAP
-
-```
-gitlab_rails['ldap_enabled'] = true
-gitlab_rails['ldap_servers'] = {
-'main' => {
- 'label' => 'GitLab AD',
- 'host' => 'ad.example.org',
- 'port' => 636,
- 'uid' => 'sAMAccountName',
- 'encryption' => 'simple_tls',
- 'verify_certificates' => true,
- 'bind_dn' => 'CN=GitLabSRV,CN=Users,DC=GitLab,DC=org',
- 'password' => 'Password1',
- 'active_directory' => true,
- 'base' => 'OU=GitLab INT,DC=GitLab,DC=org',
- 'group_base' => 'OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org',
- 'admin_group' => 'Global Admins'
- }
-}
-```
-
-> **Note:** Remember to run `gitlab-ctl reconfigure` after modifying `gitlab.rb`
-
-## Security improvements (LDAPS)
-
-Security is an important aspect when deploying an LDAP server. By default, LDAP traffic is transmitted unsecured. LDAP can be secured using SSL/TLS called LDAPS, or commonly "LDAP over SSL".
-
-Securing LDAP (enabling LDAPS) on Windows Server 2012 involves installing a valid SSL certificate. For full details see Microsoft's guide [How to enable LDAP over SSL with a third-party certification authority](https://support.microsoft.com/en-us/help/321051/how-to-enable-ldap-over-ssl-with-a-third-party-certification-authority)
-
-> By default a LDAP service listens for connections on TCP and UDP port 389. LDAPS (LDAP over SSL) listens on port 636
-
-### Testing you AD server
-
-#### Using **AdFind** (Windows)
-
-You can use the [`AdFind`](https://social.technet.microsoft.com/wiki/contents/articles/7535.adfind-command-examples.aspx) utility (on Windows based systems) to test that your LDAP server is accessible and authentication is working correctly. This is a freeware utility built by [Joe Richards](http://www.joeware.net/freetools/tools/adfind/index.htm).
-
-**Return all objects**
-
-You can use the filter `objectclass=*` to return all directory objects.
-
-```sh
-adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (objectClass=*)
-```
-
-**Return single object using filter**
-
-You can also retrieve a single object by **specifying** the object name or full **DN**. In this example we specify the object name only `CN=Leroy Fox`.
-
-```sh
-adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (&(objectcategory=person)(CN=Leroy Fox))”
-```
-
-#### Using **ldapsearch** (Unix)
-
-You can use the `ldapsearch` utility (on Unix based systems) to test that your LDAP server is accessible and authentication is working correctly. This utility is included in the [`ldap-utils`](https://wiki.debian.org/LDAP/LDAPUtils) package.
-
-**Return all objects**
-
-You can use the filter `objectclass=*` to return all directory objects.
-
-```sh
-ldapsearch -D "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" \
--w Password1 -p 636 -h ad.example.org \
--b "OU=GitLab INT,DC=GitLab,DC=org" -Z \
--s sub "(objectclass=*)"
-```
-
-**Return single object using filter**
-
-You can also retrieve a single object by **specifying** the object name or full **DN**. In this example we specify the object name only `CN=Leroy Fox`.
-
-```sh
-ldapsearch -D "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -w Password1 -p 389 -h ad.example.org -b "OU=GitLab INT,DC=GitLab,DC=org" -Z -s sub "CN=Leroy Fox"
-```
-
-**Full output of `ldapsearch` command:** - Filtering for _CN=Leroy Fox_
-
-```
-# LDAPv3
-# base with scope subtree
-# filter: CN=Leroy Fox
-# requesting: ALL
-#
-
-# Leroy Fox, Developers, United Kingdom, GitLab INT, GitLab.org
-dn: CN=Leroy Fox,OU=Developers,OU=United Kingdom,OU=GitLab INT,DC=GitLab,DC=or
- g
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: Leroy Fox
-sn: Fox
-givenName: Leroy
-distinguishedName: CN=Leroy Fox,OU=Developers,OU=United Kingdom,OU=GitLab INT,
- DC=GitLab,DC=org
-instanceType: 4
-whenCreated: 20170210030500.0Z
-whenChanged: 20170213050128.0Z
-displayName: Leroy Fox
-uSNCreated: 16790
-memberOf: CN=DevelopersUK,OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org
-uSNChanged: 20812
-name: Leroy Fox
-objectGUID:: rBCAo6NR6E6vfSKgzcUILg==
-userAccountControl: 512
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 0
-pwdLastSet: 131311695009850084
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAA9GMAb7tdJZvsATf7ZwQAAA==
-accountExpires: 9223372036854775807
-logonCount: 0
-sAMAccountName: Leroyf
-sAMAccountType: 805306368
-userPrincipalName: Leroyf@GitLab.org
-objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=GitLab,DC=org
-dSCorePropagationData: 16010101000000.0Z
-lastLogonTimestamp: 131314356887754250
-
-# search result
-search: 2
-result: 0 Success
-
-# numResponses: 2
-# numEntries: 1
-```
-
-## Basic user authentication
-
-After configuring LDAP, basic authentication will be available. Users can then login using their directory credentials. An extra tab is added to the GitLab login screen for the configured LDAP server (e.g "**GitLab AD**").
-
-
-
-Users that are removed from the LDAP base group (e.g `OU=GitLab INT,DC=GitLab,DC=org`) will be **blocked** in GitLab. [More information](../../administration/auth/ldap.md#security) on LDAP security.
-
-If `allow_username_or_email_login` is enabled in the LDAP configuration, GitLab will ignore everything after the first '@' in the LDAP username used on login. Example: The username `jon.doe@example.com` is converted to `jon.doe` when authenticating with the LDAP server. Disable this setting if you use `userPrincipalName` as the `uid`.
-
-## LDAP extended features on GitLab EE
-
-With [GitLab Enterprise Edition (EE)](https://about.gitlab.com/gitlab-ee/), besides everything we just described, you'll
-have extended functionalities with LDAP, such as:
-
-- Group sync
-- Group permissions
-- Updating user permissions
-- Multiple LDAP servers
-
-Read through the article on [LDAP for GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) for an overview.
+This document was moved to [another location](../../administration/auth/how_to_configure_ldap_gitlab_ce/index.md).
diff --git a/doc/articles/index.md b/doc/articles/index.md
index 7b60ce1d8b9..06675e15d76 100644
--- a/doc/articles/index.md
+++ b/doc/articles/index.md
@@ -10,16 +10,6 @@ They are written by members of the GitLab Team and by
Part of the articles listed below link to the [GitLab Blog](https://about.gitlab.com/blog/),
where they were originally published.
-## Authentication
-
-Explore GitLab's supported [authentications methods](../topics/authentication/index.md):
-
-| Article title | Category | Publishing date |
-| :------------ | :------: | --------------: |
-| **LDAP** |
-| [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md)| Admin guide | 2017-05-03 |
-| [How to configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) | Admin guide | 2017-05-03 |
-
## Build, test, and deploy with GitLab CI/CD
Build, test, and deploy the software you develop with [GitLab CI/CD](../ci/README.md):
diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md
index 1f30909b0aa..a8aa11265d0 100644
--- a/doc/topics/authentication/index.md
+++ b/doc/topics/authentication/index.md
@@ -20,7 +20,7 @@ This page gathers all the resources for the topic **Authentication** within GitL
- [LDAP (Enterprise Edition)](https://docs.gitlab.com/ee/administration/auth/ldap-ee.html)
- [Enforce Two-factor Authentication (2FA)](../../security/two_factor_authentication.md#enforce-two-factor-authentication-2fa)
- **Articles:**
- - [How to Configure LDAP with GitLab CE](../../articles/how_to_configure_ldap_gitlab_ce/index.md)
+ - [How to Configure LDAP with GitLab CE](../../administration/auth/how_to_configure_ldap_gitlab_ce/index.md)
- [How to Configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/)
- [Feature Highlight: LDAP Integration](https://about.gitlab.com/2014/07/10/feature-highlight-ldap-sync/)
- [Debugging LDAP](https://about.gitlab.com/handbook/support/workflows/ldap/debugging_ldap.html)
--
cgit v1.2.1
From 0d4548026f3060ca0a8f7aa8d8fc89838bc66130 Mon Sep 17 00:00:00 2001
From: Mayra Cabrera
Date: Fri, 22 Dec 2017 17:23:43 +0000
Subject: Extend Cluster Applications to allow installation of Prometheus
---
app/assets/javascripts/clusters/clusters_bundle.js | 2 +
.../clusters/components/applications.vue | 20 +++
.../clusters/services/clusters_service.js | 1 +
.../javascripts/clusters/stores/clusters_store.js | 7 ++
app/assets/stylesheets/pages/clusters.scss | 2 +-
app/models/clusters/applications/helm.rb | 17 +--
app/models/clusters/applications/ingress.rb | 23 +---
app/models/clusters/applications/prometheus.rb | 26 ++++
app/models/clusters/cluster.rb | 7 +-
app/models/clusters/concerns/application_core.rb | 29 +++++
.../clusters/applications/base_helm_service.rb | 2 +-
app/views/projects/clusters/show.html.haml | 1 +
...applications-to-allow-install-to-prometheus.yml | 5 +
...3433_create_clusters_applications_prometheus.rb | 18 +++
db/schema.rb | 9 ++
lib/gitlab/kubernetes/helm.rb | 90 +-------------
lib/gitlab/kubernetes/helm/api.rb | 42 +++++++
lib/gitlab/kubernetes/helm/install_command.rb | 53 ++++++++
lib/gitlab/kubernetes/helm/pod.rb | 69 +++++++++++
.../clusters/applications_controller_spec.rb | 2 +-
spec/factories/clusters/applications/helm.rb | 5 +-
spec/factories/clusters/applications/ingress.rb | 35 ------
.../projects/clusters/applications_spec.rb | 2 +-
.../clusters/components/applications_spec.js | 5 +
spec/javascripts/clusters/services/mock_data.js | 6 +
.../clusters/stores/clusters_store_spec.js | 7 ++
spec/lib/gitlab/kubernetes/helm/api_spec.rb | 69 +++++++++++
.../gitlab/kubernetes/helm/install_command_spec.rb | 111 +++++++++++++++++
spec/lib/gitlab/kubernetes/helm/pod_spec.rb | 86 +++++++++++++
spec/lib/gitlab/kubernetes/helm_spec.rb | 100 ---------------
spec/models/clusters/applications/helm_spec.rb | 12 +-
spec/models/clusters/applications/ingress_spec.rb | 102 +---------------
.../clusters/applications/prometheus_spec.rb | 16 +++
spec/models/clusters/cluster_spec.rb | 10 +-
.../serializers/cluster_application_entity_spec.rb | 4 +-
.../check_installation_progress_service_spec.rb | 4 +-
.../clusters/applications/install_service_spec.rb | 12 +-
.../schedule_installation_service_spec.rb | 2 +-
spec/support/cluster_application_spec.rb | 105 ++++++++++++++++
vendor/prometheus/values.yaml | 134 +++++++++++++++++++++
40 files changed, 865 insertions(+), 387 deletions(-)
create mode 100644 app/models/clusters/applications/prometheus.rb
create mode 100644 app/models/clusters/concerns/application_core.rb
create mode 100644 changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml
create mode 100644 db/migrate/20171212203433_create_clusters_applications_prometheus.rb
create mode 100644 lib/gitlab/kubernetes/helm/api.rb
create mode 100644 lib/gitlab/kubernetes/helm/install_command.rb
create mode 100644 lib/gitlab/kubernetes/helm/pod.rb
delete mode 100644 spec/factories/clusters/applications/ingress.rb
create mode 100644 spec/lib/gitlab/kubernetes/helm/api_spec.rb
create mode 100644 spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
create mode 100644 spec/lib/gitlab/kubernetes/helm/pod_spec.rb
delete mode 100644 spec/lib/gitlab/kubernetes/helm_spec.rb
create mode 100644 spec/models/clusters/applications/prometheus_spec.rb
create mode 100644 spec/support/cluster_application_spec.rb
create mode 100644 vendor/prometheus/values.yaml
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 2cfd6179a25..637d0dbde23 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -30,6 +30,7 @@ export default class Clusters {
installHelmPath,
installIngressPath,
installRunnerPath,
+ installPrometheusPath,
clusterStatus,
clusterStatusReason,
helpPath,
@@ -44,6 +45,7 @@ export default class Clusters {
installHelmEndpoint: installHelmPath,
installIngressEndpoint: installIngressPath,
installRunnerEndpoint: installRunnerPath,
+ installPrometheusEndpoint: installPrometheusPath,
});
this.toggle = this.toggle.bind(this);
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index e5ae439d26e..cd58b88db69 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -67,6 +67,16 @@ export default {
and send the results back to GitLab.`,
));
},
+ prometheusDescription() {
+ return sprintf(
+ _.escape(s__('ClusterIntegration|Prometheus is an open-source monitoring system with %{gitlabIntegrationLink} to monitor deployed applications.')), {
+ gitlabIntegrationLink: `
+ ${_.escape(s__('ClusterIntegration|Gitlab Integration'))}
+ `,
+ },
+ false,
+ );
+ },
},
};
@@ -105,6 +115,16 @@ export default {
:status-reason="applications.ingress.statusReason"
:request-status="applications.ingress.requestStatus"
:request-reason="applications.ingress.requestReason"
+ />
+
diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js
index 755c2981c2e..13468578f4f 100644
--- a/app/assets/javascripts/clusters/services/clusters_service.js
+++ b/app/assets/javascripts/clusters/services/clusters_service.js
@@ -7,6 +7,7 @@ export default class ClusterService {
helm: this.options.installHelmEndpoint,
ingress: this.options.installIngressEndpoint,
runner: this.options.installRunnerEndpoint,
+ prometheus: this.options.installPrometheusEndpoint,
};
}
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index e731cdc3042..bd4a1fb37f9 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -28,6 +28,13 @@ export default class ClusterStore {
requestStatus: null,
requestReason: null,
},
+ prometheus: {
+ title: s__('ClusterIntegration|Prometheus'),
+ status: null,
+ statusReason: null,
+ requestStatus: null,
+ requestReason: null,
+ },
},
};
}
diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss
index 88d44131d5b..7b8ee026357 100644
--- a/app/assets/stylesheets/pages/clusters.scss
+++ b/app/assets/stylesheets/pages/clusters.scss
@@ -6,7 +6,7 @@
.cluster-applications-table {
// Wait for the Vue to kick-in and render the applications block
- min-height: 302px;
+ min-height: 400px;
}
.clusters-dropdown-menu {
diff --git a/app/models/clusters/applications/helm.rb b/app/models/clusters/applications/helm.rb
index c7949d11ef8..193bb48e54d 100644
--- a/app/models/clusters/applications/helm.rb
+++ b/app/models/clusters/applications/helm.rb
@@ -3,32 +3,19 @@ module Clusters
class Helm < ActiveRecord::Base
self.table_name = 'clusters_applications_helm'
+ include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
- belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id
-
default_value_for :version, Gitlab::Kubernetes::Helm::HELM_VERSION
- validates :cluster, presence: true
-
- after_initialize :set_initial_status
-
- def self.application_name
- self.to_s.demodulize.underscore
- end
-
def set_initial_status
return unless not_installable?
self.status = 'installable' if cluster&.platform_kubernetes_active?
end
- def name
- self.class.application_name
- end
-
def install_command
- Gitlab::Kubernetes::Helm::InstallCommand.new(name, true)
+ Gitlab::Kubernetes::Helm::InstallCommand.new(name, install_helm: true)
end
end
end
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index 44bd979741e..9024f1df1cd 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -3,41 +3,22 @@ module Clusters
class Ingress < ActiveRecord::Base
self.table_name = 'clusters_applications_ingress'
+ include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
- belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id
-
- validates :cluster, presence: true
-
default_value_for :ingress_type, :nginx
default_value_for :version, :nginx
- after_initialize :set_initial_status
-
enum ingress_type: {
nginx: 1
}
- def self.application_name
- self.to_s.demodulize.underscore
- end
-
- def set_initial_status
- return unless not_installable?
-
- self.status = 'installable' if cluster&.application_helm_installed?
- end
-
- def name
- self.class.application_name
- end
-
def chart
'stable/nginx-ingress'
end
def install_command
- Gitlab::Kubernetes::Helm::InstallCommand.new(name, false, chart)
+ Gitlab::Kubernetes::Helm::InstallCommand.new(name, chart: chart)
end
end
end
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
new file mode 100644
index 00000000000..9b0787ee6ca
--- /dev/null
+++ b/app/models/clusters/applications/prometheus.rb
@@ -0,0 +1,26 @@
+module Clusters
+ module Applications
+ class Prometheus < ActiveRecord::Base
+ VERSION = "2.0.0".freeze
+
+ self.table_name = 'clusters_applications_prometheus'
+
+ include ::Clusters::Concerns::ApplicationCore
+ include ::Clusters::Concerns::ApplicationStatus
+
+ default_value_for :version, VERSION
+
+ def chart
+ 'stable/prometheus'
+ end
+
+ def chart_values_file
+ "#{Rails.root}/vendor/#{name}/values.yaml"
+ end
+
+ def install_command
+ Gitlab::Kubernetes::Helm::InstallCommand.new(name, chart: chart, chart_values_file: chart_values_file)
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 55419189282..5ecbd4cbceb 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -6,7 +6,8 @@ module Clusters
APPLICATIONS = {
Applications::Helm.application_name => Applications::Helm,
- Applications::Ingress.application_name => Applications::Ingress
+ Applications::Ingress.application_name => Applications::Ingress,
+ Applications::Prometheus.application_name => Applications::Prometheus
}.freeze
belongs_to :user
@@ -21,6 +22,7 @@ module Clusters
has_one :application_helm, class_name: 'Clusters::Applications::Helm'
has_one :application_ingress, class_name: 'Clusters::Applications::Ingress'
+ has_one :application_prometheus, class_name: 'Clusters::Applications::Prometheus'
accepts_nested_attributes_for :provider_gcp, update_only: true
accepts_nested_attributes_for :platform_kubernetes, update_only: true
@@ -62,7 +64,8 @@ module Clusters
def applications
[
application_helm || build_application_helm,
- application_ingress || build_application_ingress
+ application_ingress || build_application_ingress,
+ application_prometheus || build_application_prometheus
]
end
diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb
new file mode 100644
index 00000000000..a98fa85a5ff
--- /dev/null
+++ b/app/models/clusters/concerns/application_core.rb
@@ -0,0 +1,29 @@
+module Clusters
+ module Concerns
+ module ApplicationCore
+ extend ActiveSupport::Concern
+
+ included do
+ belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id
+
+ validates :cluster, presence: true
+
+ after_initialize :set_initial_status
+
+ def set_initial_status
+ return unless not_installable?
+
+ self.status = 'installable' if cluster&.application_helm_installed?
+ end
+
+ def self.application_name
+ self.to_s.demodulize.underscore
+ end
+
+ def name
+ self.class.application_name
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/applications/base_helm_service.rb b/app/services/clusters/applications/base_helm_service.rb
index 9a4ce31cb39..cba1b920f7c 100644
--- a/app/services/clusters/applications/base_helm_service.rb
+++ b/app/services/clusters/applications/base_helm_service.rb
@@ -18,7 +18,7 @@ module Clusters
end
def helm_api
- @helm_api ||= Gitlab::Kubernetes::Helm.new(kubeclient)
+ @helm_api ||= Gitlab::Kubernetes::Helm::Api.new(kubeclient)
end
def install_command
diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml
index fe6dacf1f0d..0115c64c076 100644
--- a/app/views/projects/clusters/show.html.haml
+++ b/app/views/projects/clusters/show.html.haml
@@ -9,6 +9,7 @@
.edit-cluster-form.js-edit-cluster-form{ data: { status_path: status_path,
install_helm_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :helm),
install_ingress_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :ingress),
+ install_prometheus_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :prometheus),
toggle_status: @cluster.enabled? ? 'true': 'false',
cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason,
diff --git a/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml b/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml
new file mode 100644
index 00000000000..ffb79d7d79f
--- /dev/null
+++ b/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml
@@ -0,0 +1,5 @@
+---
+title: Add Prometheus to available Cluster applications
+merge_request: 15895
+author:
+type: added
diff --git a/db/migrate/20171212203433_create_clusters_applications_prometheus.rb b/db/migrate/20171212203433_create_clusters_applications_prometheus.rb
new file mode 100644
index 00000000000..dc2531d2691
--- /dev/null
+++ b/db/migrate/20171212203433_create_clusters_applications_prometheus.rb
@@ -0,0 +1,18 @@
+class CreateClustersApplicationsPrometheus < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ create_table :clusters_applications_prometheus do |t|
+ t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
+
+ t.integer :status, null: false
+ t.string :version, null: false
+
+ t.text :status_reason
+
+ t.timestamps_with_timezone null: false
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 81b594cd0c1..aa5db5da4f0 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -568,6 +568,15 @@ ActiveRecord::Schema.define(version: 20171220191323) do
t.text "status_reason"
end
+ create_table "clusters_applications_prometheus", force: :cascade do |t|
+ t.integer "cluster_id", null: false
+ t.integer "status", null: false
+ t.string "version", null: false
+ t.text "status_reason"
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ end
+
create_table "container_repositories", force: :cascade do |t|
t.integer "project_id", null: false
t.string "name", null: false
diff --git a/lib/gitlab/kubernetes/helm.rb b/lib/gitlab/kubernetes/helm.rb
index 407cdefc04d..0f0588b8b23 100644
--- a/lib/gitlab/kubernetes/helm.rb
+++ b/lib/gitlab/kubernetes/helm.rb
@@ -1,96 +1,8 @@
module Gitlab
module Kubernetes
- class Helm
+ module Helm
HELM_VERSION = '2.7.0'.freeze
NAMESPACE = 'gitlab-managed-apps'.freeze
- INSTALL_DEPS = <<-EOS.freeze
- set -eo pipefail
- apk add -U ca-certificates openssl >/dev/null
- wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
- mv /tmp/linux-amd64/helm /usr/bin/
- EOS
-
- InstallCommand = Struct.new(:name, :install_helm, :chart) do
- def pod_name
- "install-#{name}"
- end
- end
-
- def initialize(kubeclient)
- @kubeclient = kubeclient
- @namespace = Gitlab::Kubernetes::Namespace.new(NAMESPACE, kubeclient)
- end
-
- def install(command)
- @namespace.ensure_exists!
- @kubeclient.create_pod(pod_resource(command))
- end
-
- ##
- # Returns Pod phase
- #
- # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
- #
- # values: "Pending", "Running", "Succeeded", "Failed", "Unknown"
- #
- def installation_status(pod_name)
- @kubeclient.get_pod(pod_name, @namespace.name).status.phase
- end
-
- def installation_log(pod_name)
- @kubeclient.get_pod_log(pod_name, @namespace.name).body
- end
-
- def delete_installation_pod!(pod_name)
- @kubeclient.delete_pod(pod_name, @namespace.name)
- end
-
- private
-
- def pod_resource(command)
- labels = { 'gitlab.org/action': 'install', 'gitlab.org/application': command.name }
- metadata = { name: command.pod_name, namespace: @namespace.name, labels: labels }
- container = {
- name: 'helm',
- image: 'alpine:3.6',
- env: generate_pod_env(command),
- command: %w(/bin/sh),
- args: %w(-c $(COMMAND_SCRIPT))
- }
- spec = { containers: [container], restartPolicy: 'Never' }
-
- ::Kubeclient::Resource.new(metadata: metadata, spec: spec)
- end
-
- def generate_pod_env(command)
- {
- HELM_VERSION: HELM_VERSION,
- TILLER_NAMESPACE: @namespace.name,
- COMMAND_SCRIPT: generate_script(command)
- }.map { |key, value| { name: key, value: value } }
- end
-
- def generate_script(command)
- [
- INSTALL_DEPS,
- helm_init_command(command),
- helm_install_command(command)
- ].join("\n")
- end
-
- def helm_init_command(command)
- if command.install_helm
- 'helm init >/dev/null'
- else
- 'helm init --client-only >/dev/null'
- end
- end
-
- def helm_install_command(command)
- return if command.chart.nil?
-
- "helm install #{command.chart} --name #{command.name} --namespace #{@namespace.name} >/dev/null"
- end
end
end
end
diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb
new file mode 100644
index 00000000000..ebd7dc1b100
--- /dev/null
+++ b/lib/gitlab/kubernetes/helm/api.rb
@@ -0,0 +1,42 @@
+module Gitlab
+ module Kubernetes
+ module Helm
+ class Api
+ def initialize(kubeclient)
+ @kubeclient = kubeclient
+ @namespace = Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, kubeclient)
+ end
+
+ def install(command)
+ @namespace.ensure_exists!
+ @kubeclient.create_pod(pod_resource(command))
+ end
+
+ ##
+ # Returns Pod phase
+ #
+ # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
+ #
+ # values: "Pending", "Running", "Succeeded", "Failed", "Unknown"
+ #
+ def installation_status(pod_name)
+ @kubeclient.get_pod(pod_name, @namespace.name).status.phase
+ end
+
+ def installation_log(pod_name)
+ @kubeclient.get_pod_log(pod_name, @namespace.name).body
+ end
+
+ def delete_installation_pod!(pod_name)
+ @kubeclient.delete_pod(pod_name, @namespace.name)
+ end
+
+ private
+
+ def pod_resource(command)
+ Pod.new(command, @namespace.name, @kubeclient).generate
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb
new file mode 100644
index 00000000000..8d8c441a4b1
--- /dev/null
+++ b/lib/gitlab/kubernetes/helm/install_command.rb
@@ -0,0 +1,53 @@
+module Gitlab
+ module Kubernetes
+ module Helm
+ class InstallCommand
+ attr_reader :name, :install_helm, :chart, :chart_values_file
+
+ def initialize(name, install_helm: false, chart: false, chart_values_file: false)
+ @name = name
+ @install_helm = install_helm
+ @chart = chart
+ @chart_values_file = chart_values_file
+ end
+
+ def pod_name
+ "install-#{name}"
+ end
+
+ def generate_script(namespace_name)
+ [
+ install_dps_command,
+ init_command,
+ complete_command(namespace_name)
+ ].join("\n")
+ end
+
+ private
+
+ def init_command
+ if install_helm
+ 'helm init >/dev/null'
+ else
+ 'helm init --client-only >/dev/null'
+ end
+ end
+
+ def complete_command(namespace_name)
+ return unless chart
+
+ "helm install #{chart} --name #{name} --namespace #{namespace_name} >/dev/null"
+ end
+
+ def install_dps_command
+ <<~HEREDOC
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v#{Gitlab::Kubernetes::Helm::HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+ HEREDOC
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/kubernetes/helm/pod.rb b/lib/gitlab/kubernetes/helm/pod.rb
new file mode 100644
index 00000000000..233f6bf6227
--- /dev/null
+++ b/lib/gitlab/kubernetes/helm/pod.rb
@@ -0,0 +1,69 @@
+module Gitlab
+ module Kubernetes
+ module Helm
+ class Pod
+ def initialize(command, namespace_name, kubeclient)
+ @command = command
+ @namespace_name = namespace_name
+ @kubeclient = kubeclient
+ end
+
+ def generate
+ spec = { containers: [container_specification], restartPolicy: 'Never' }
+ if command.chart_values_file
+ generate_config_map
+ spec['volumes'] = volumes_specification
+ end
+ ::Kubeclient::Resource.new(metadata: metadata, spec: spec)
+ end
+
+ private
+
+ attr_reader :command, :namespace_name, :kubeclient
+
+ def container_specification
+ container = {
+ name: 'helm',
+ image: 'alpine:3.6',
+ env: generate_pod_env(command),
+ command: %w(/bin/sh),
+ args: %w(-c $(COMMAND_SCRIPT))
+ }
+ container[:volumeMounts] = volume_mounts_specification if command.chart_values_file
+ container
+ end
+
+ def labels
+ { 'gitlab.org/action': 'install', 'gitlab.org/application': command.name }
+ end
+
+ def metadata
+ { name: command.pod_name, namespace: namespace_name, labels: labels }
+ end
+
+ def volume_mounts_specification
+ [{ name: 'config-volume', mountPath: '/etc/config' }]
+ end
+
+ def volumes_specification
+ [{ name: 'config-volume', configMap: { name: 'values-config' } }]
+ end
+
+ def generate_pod_env(command)
+ {
+ HELM_VERSION: Gitlab::Kubernetes::Helm::HELM_VERSION,
+ TILLER_NAMESPACE: namespace_name,
+ COMMAND_SCRIPT: command.generate_script(namespace_name)
+ }.map { |key, value| { name: key, value: value } }
+ end
+
+ def generate_config_map
+ resource = ::Kubeclient::Resource.new
+ resource.metadata = { name: 'values-config', namespace: namespace_name }
+ resource.data = YAML.load_file(command.chart_values_file)
+ kubeclient.create_config_map(resource)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/clusters/applications_controller_spec.rb b/spec/controllers/projects/clusters/applications_controller_spec.rb
index 8b460646059..99fdff5f846 100644
--- a/spec/controllers/projects/clusters/applications_controller_spec.rb
+++ b/spec/controllers/projects/clusters/applications_controller_spec.rb
@@ -52,7 +52,7 @@ describe Projects::Clusters::ApplicationsController do
context 'when application is already installing' do
before do
- create(:cluster_applications_helm, :installing, cluster: cluster)
+ create(:clusters_applications_helm, :installing, cluster: cluster)
end
it 'returns 400' do
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index d82fa8e34aa..775fbb3d27b 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -1,5 +1,5 @@
FactoryBot.define do
- factory :cluster_applications_helm, class: Clusters::Applications::Helm do
+ factory :clusters_applications_helm, class: Clusters::Applications::Helm do
cluster factory: %i(cluster provided_by_gcp)
trait :not_installable do
@@ -31,5 +31,8 @@ FactoryBot.define do
installing
updated_at ClusterWaitForAppInstallationWorker::TIMEOUT.ago
end
+
+ factory :clusters_applications_ingress, class: Clusters::Applications::Ingress
+ factory :clusters_applications_prometheus, class: Clusters::Applications::Prometheus
end
end
diff --git a/spec/factories/clusters/applications/ingress.rb b/spec/factories/clusters/applications/ingress.rb
deleted file mode 100644
index 85f54a9d744..00000000000
--- a/spec/factories/clusters/applications/ingress.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-FactoryBot.define do
- factory :cluster_applications_ingress, class: Clusters::Applications::Ingress do
- cluster factory: %i(cluster provided_by_gcp)
-
- trait :not_installable do
- status(-2)
- end
-
- trait :installable do
- status 0
- end
-
- trait :scheduled do
- status 1
- end
-
- trait :installing do
- status 2
- end
-
- trait :installed do
- status 3
- end
-
- trait :errored do
- status(-1)
- status_reason 'something went wrong'
- end
-
- trait :timeouted do
- installing
- updated_at ClusterWaitForAppInstallationWorker::TIMEOUT.ago
- end
- end
-end
diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb
index b34cd061ec6..9c4abec115f 100644
--- a/spec/features/projects/clusters/applications_spec.rb
+++ b/spec/features/projects/clusters/applications_spec.rb
@@ -73,7 +73,7 @@ feature 'Clusters Applications', :js do
before do
allow(ClusterInstallAppWorker).to receive(:perform_async).and_return(nil)
- create(:cluster_applications_helm, :installed, cluster: cluster)
+ create(:clusters_applications_helm, :installed, cluster: cluster)
page.within('.js-cluster-application-row-ingress') do
page.find(:css, '.js-cluster-application-install-button').click
diff --git a/spec/javascripts/clusters/components/applications_spec.js b/spec/javascripts/clusters/components/applications_spec.js
index 7460da031c4..1a8affad4e3 100644
--- a/spec/javascripts/clusters/components/applications_spec.js
+++ b/spec/javascripts/clusters/components/applications_spec.js
@@ -21,6 +21,7 @@ describe('Applications', () => {
helm: { title: 'Helm Tiller' },
ingress: { title: 'Ingress' },
runner: { title: 'GitLab Runner' },
+ prometheus: { title: 'Prometheus' },
},
});
});
@@ -33,6 +34,10 @@ describe('Applications', () => {
expect(vm.$el.querySelector('.js-cluster-application-row-ingress')).toBeDefined();
});
+ it('renders a row for Prometheus', () => {
+ expect(vm.$el.querySelector('.js-cluster-application-row-prometheus')).toBeDefined();
+ });
+
/* * /
it('renders a row for GitLab Runner', () => {
expect(vm.$el.querySelector('.js-cluster-application-row-runner')).toBeDefined();
diff --git a/spec/javascripts/clusters/services/mock_data.js b/spec/javascripts/clusters/services/mock_data.js
index af6b6a73819..253b3c45243 100644
--- a/spec/javascripts/clusters/services/mock_data.js
+++ b/spec/javascripts/clusters/services/mock_data.js
@@ -22,6 +22,11 @@ const CLUSTERS_MOCK_DATA = {
name: 'runner',
status: APPLICATION_INSTALLING,
status_reason: null,
+ },
+ {
+ name: 'prometheus',
+ status: APPLICATION_ERROR,
+ status_reason: 'Cannot connect',
}],
},
},
@@ -30,6 +35,7 @@ const CLUSTERS_MOCK_DATA = {
'/gitlab-org/gitlab-shell/clusters/1/applications/helm': { },
'/gitlab-org/gitlab-shell/clusters/1/applications/ingress': { },
'/gitlab-org/gitlab-shell/clusters/1/applications/runner': { },
+ '/gitlab-org/gitlab-shell/clusters/1/applications/prometheus': { },
},
};
diff --git a/spec/javascripts/clusters/stores/clusters_store_spec.js b/spec/javascripts/clusters/stores/clusters_store_spec.js
index cb8b3d38e2e..ec2889355e6 100644
--- a/spec/javascripts/clusters/stores/clusters_store_spec.js
+++ b/spec/javascripts/clusters/stores/clusters_store_spec.js
@@ -82,6 +82,13 @@ describe('Clusters Store', () => {
requestStatus: null,
requestReason: null,
},
+ prometheus: {
+ title: 'Prometheus',
+ status: mockResponseData.applications[3].status,
+ statusReason: mockResponseData.applications[3].status_reason,
+ requestStatus: null,
+ requestReason: null,
+ },
},
});
});
diff --git a/spec/lib/gitlab/kubernetes/helm/api_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb
new file mode 100644
index 00000000000..69112fe90b1
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb
@@ -0,0 +1,69 @@
+require 'spec_helper'
+
+describe Gitlab::Kubernetes::Helm::Api do
+ let(:client) { double('kubernetes client') }
+ let(:helm) { described_class.new(client) }
+ let(:gitlab_namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(gitlab_namespace, client) }
+ let(:install_helm) { true }
+ let(:chart) { 'stable/a_chart' }
+ let(:application_name) { 'app_name' }
+ let(:command) { Gitlab::Kubernetes::Helm::InstallCommand.new(application_name, install_helm: install_helm, chart: chart) }
+ subject { helm }
+
+ before do
+ allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client).and_return(namespace)
+ end
+
+ describe '#initialize' do
+ it 'creates a namespace object' do
+ expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client)
+
+ subject
+ end
+ end
+
+ describe '#install' do
+ before do
+ allow(client).to receive(:create_pod).and_return(nil)
+ allow(namespace).to receive(:ensure_exists!).once
+ end
+
+ it 'ensures the namespace exists before creating the POD' do
+ expect(namespace).to receive(:ensure_exists!).once.ordered
+ expect(client).to receive(:create_pod).once.ordered
+
+ subject.install(command)
+ end
+ end
+
+ describe '#installation_status' do
+ let(:phase) { Gitlab::Kubernetes::Pod::RUNNING }
+ let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation
+
+ it 'fetches POD phase from kubernetes cluster' do
+ expect(client).to receive(:get_pod).with(command.pod_name, gitlab_namespace).once.and_return(pod)
+
+ expect(subject.installation_status(command.pod_name)).to eq(phase)
+ end
+ end
+
+ describe '#installation_log' do
+ let(:log) { 'some output' }
+ let(:response) { RestClient::Response.new(log) }
+
+ it 'fetches POD phase from kubernetes cluster' do
+ expect(client).to receive(:get_pod_log).with(command.pod_name, gitlab_namespace).once.and_return(response)
+
+ expect(subject.installation_log(command.pod_name)).to eq(log)
+ end
+ end
+
+ describe '#delete_installation_pod!' do
+ it 'deletes the POD from kubernetes cluster' do
+ expect(client).to receive(:delete_pod).with(command.pod_name, gitlab_namespace).once
+
+ subject.delete_installation_pod!(command.pod_name)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
new file mode 100644
index 00000000000..4afe48e72ad
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
@@ -0,0 +1,111 @@
+require 'rails_helper'
+
+describe Gitlab::Kubernetes::Helm::InstallCommand do
+ let(:prometheus) { create(:clusters_applications_prometheus) }
+
+ describe "#initialize" do
+ context "With all the params" do
+ subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart, chart_values_file: prometheus.chart_values_file) }
+
+ it 'should assign all parameters' do
+ expect(subject.name).to eq(prometheus.name)
+ expect(subject.install_helm).to be_truthy
+ expect(subject.chart).to eq(prometheus.chart)
+ expect(subject.chart_values_file).to eq("#{Rails.root}/vendor/prometheus/values.yaml")
+ end
+ end
+
+ context 'when install_helm is not set' do
+ subject { described_class.new(prometheus.name, chart: prometheus.chart, chart_values_file: true) }
+
+ it 'should set install_helm as false' do
+ expect(subject.install_helm).to be_falsy
+ end
+ end
+
+ context 'when chart is not set' do
+ subject { described_class.new(prometheus.name, install_helm: true) }
+
+ it 'should set chart as nil' do
+ expect(subject.chart).to be_falsy
+ end
+ end
+
+ context 'when chart_values_file is not set' do
+ subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart) }
+
+ it 'should set chart_values_file as nil' do
+ expect(subject.chart_values_file).to be_falsy
+ end
+ end
+ end
+
+ describe "#generate_script" do
+ let(:install_command) { described_class.new(prometheus.name, install_helm: install_helm) }
+ let(:client) { double('kubernetes client') }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, client) }
+ subject { install_command.send(:generate_script, namespace.name) }
+
+ context 'when install helm is true' do
+ let(:install_helm) { true }
+ let(:command) do
+ <<~MSG
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+
+ context 'when install helm is false' do
+ let(:install_helm) { false }
+ let(:command) do
+ <<~MSG
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init --client-only >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+
+ context 'when chart is present' do
+ let(:install_command) { described_class.new(prometheus.name, chart: prometheus.chart) }
+ let(:command) do
+ <<~MSG.chomp
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init --client-only >/dev/null
+ helm install #{prometheus.chart} --name #{prometheus.name} --namespace #{namespace.name} >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+ end
+
+ describe "#pod_name" do
+ let(:install_command) { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart, chart_values_file: true) }
+ subject { install_command.send(:pod_name) }
+
+ it { is_expected.to eq('install-prometheus') }
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
new file mode 100644
index 00000000000..906b10b96d4
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
@@ -0,0 +1,86 @@
+require 'rails_helper'
+
+describe Gitlab::Kubernetes::Helm::Pod do
+ describe '#generate' do
+ let(:cluster) { create(:cluster) }
+ let(:app) { create(:clusters_applications_prometheus, cluster: cluster) }
+ let(:command) { app.install_command }
+ let(:client) { double('kubernetes client') }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, client) }
+ subject { described_class.new(command, namespace.name, client) }
+
+ before do
+ allow(client).to receive(:create_config_map).and_return(nil)
+ end
+
+ shared_examples 'helm pod' do
+ it 'should generate a Kubeclient::Resource' do
+ expect(subject.generate).to be_a_kind_of(Kubeclient::Resource)
+ end
+
+ it 'should generate the appropriate metadata' do
+ metadata = subject.generate.metadata
+ expect(metadata.name).to eq("install-#{app.name}")
+ expect(metadata.namespace).to eq('gitlab-managed-apps')
+ expect(metadata.labels['gitlab.org/action']).to eq('install')
+ expect(metadata.labels['gitlab.org/application']).to eq(app.name)
+ end
+
+ it 'should generate a container spec' do
+ spec = subject.generate.spec
+ expect(spec.containers.count).to eq(1)
+ end
+
+ it 'should generate the appropriate specifications for the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.name).to eq('helm')
+ expect(container.image).to eq('alpine:3.6')
+ expect(container.env.count).to eq(3)
+ expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT])
+ expect(container.command).to match_array(["/bin/sh"])
+ expect(container.args).to match_array(["-c", "$(COMMAND_SCRIPT)"])
+ end
+
+ it 'should include a never restart policy' do
+ spec = subject.generate.spec
+ expect(spec.restartPolicy).to eq('Never')
+ end
+ end
+
+ context 'with a configuration file' do
+ it_behaves_like 'helm pod'
+
+ it 'should include volumes for the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.volumeMounts.first['name']).to eq('config-volume')
+ expect(container.volumeMounts.first['mountPath']).to eq('/etc/config')
+ end
+
+ it 'should include a volume inside the specification' do
+ spec = subject.generate.spec
+ expect(spec.volumes.first['name']).to eq('config-volume')
+ end
+
+ it 'should mount configMap specification in the volume' do
+ spec = subject.generate.spec
+ expect(spec.volumes.first.configMap['name']).to eq('values-config')
+ end
+ end
+
+ context 'without a configuration file' do
+ let(:app) { create(:clusters_applications_ingress, cluster: cluster) }
+
+ it_behaves_like 'helm pod'
+
+ it 'should not include volumeMounts inside the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.volumeMounts).to be_nil
+ end
+
+ it 'should not a volume inside the specification' do
+ spec = subject.generate.spec
+ expect(spec.volumes).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes/helm_spec.rb b/spec/lib/gitlab/kubernetes/helm_spec.rb
deleted file mode 100644
index 15f99b0401f..00000000000
--- a/spec/lib/gitlab/kubernetes/helm_spec.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Kubernetes::Helm do
- let(:client) { double('kubernetes client') }
- let(:helm) { described_class.new(client) }
- let(:namespace) { Gitlab::Kubernetes::Namespace.new(described_class::NAMESPACE, client) }
- let(:install_helm) { true }
- let(:chart) { 'stable/a_chart' }
- let(:application_name) { 'app_name' }
- let(:command) { Gitlab::Kubernetes::Helm::InstallCommand.new(application_name, install_helm, chart) }
- subject { helm }
-
- before do
- allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(described_class::NAMESPACE, client).and_return(namespace)
- end
-
- describe '#initialize' do
- it 'creates a namespace object' do
- expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(described_class::NAMESPACE, client)
-
- subject
- end
- end
-
- describe '#install' do
- before do
- allow(client).to receive(:create_pod).and_return(nil)
- allow(namespace).to receive(:ensure_exists!).once
- end
-
- it 'ensures the namespace exists before creating the POD' do
- expect(namespace).to receive(:ensure_exists!).once.ordered
- expect(client).to receive(:create_pod).once.ordered
-
- subject.install(command)
- end
- end
-
- describe '#installation_status' do
- let(:phase) { Gitlab::Kubernetes::Pod::RUNNING }
- let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation
-
- it 'fetches POD phase from kubernetes cluster' do
- expect(client).to receive(:get_pod).with(command.pod_name, described_class::NAMESPACE).once.and_return(pod)
-
- expect(subject.installation_status(command.pod_name)).to eq(phase)
- end
- end
-
- describe '#installation_log' do
- let(:log) { 'some output' }
- let(:response) { RestClient::Response.new(log) }
-
- it 'fetches POD phase from kubernetes cluster' do
- expect(client).to receive(:get_pod_log).with(command.pod_name, described_class::NAMESPACE).once.and_return(response)
-
- expect(subject.installation_log(command.pod_name)).to eq(log)
- end
- end
-
- describe '#delete_installation_pod!' do
- it 'deletes the POD from kubernetes cluster' do
- expect(client).to receive(:delete_pod).with(command.pod_name, described_class::NAMESPACE).once
-
- subject.delete_installation_pod!(command.pod_name)
- end
- end
-
- describe '#helm_init_command' do
- subject { helm.send(:helm_init_command, command) }
-
- context 'when command.install_helm is true' do
- let(:install_helm) { true }
-
- it { is_expected.to eq('helm init >/dev/null') }
- end
-
- context 'when command.install_helm is false' do
- let(:install_helm) { false }
-
- it { is_expected.to eq('helm init --client-only >/dev/null') }
- end
- end
-
- describe '#helm_install_command' do
- subject { helm.send(:helm_install_command, command) }
-
- context 'when command.chart is nil' do
- let(:chart) { nil }
-
- it { is_expected.to be_nil }
- end
-
- context 'when command.chart is set' do
- let(:chart) { 'stable/a_chart' }
-
- it { is_expected.to eq("helm install #{chart} --name #{application_name} --namespace #{namespace.name} >/dev/null")}
- end
- end
-end
diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb
index f8855079842..eb57abaf6ef 100644
--- a/spec/models/clusters/applications/helm_spec.rb
+++ b/spec/models/clusters/applications/helm_spec.rb
@@ -40,13 +40,13 @@ describe Clusters::Applications::Helm do
describe '#install_command' do
it 'has all the needed information' do
- expect(subject.install_command).to have_attributes(name: subject.name, install_helm: true, chart: nil)
+ expect(subject.install_command).to have_attributes(name: subject.name, install_helm: true)
end
end
describe 'status state machine' do
describe '#make_installing' do
- subject { create(:cluster_applications_helm, :scheduled) }
+ subject { create(:clusters_applications_helm, :scheduled) }
it 'is installing' do
subject.make_installing!
@@ -56,7 +56,7 @@ describe Clusters::Applications::Helm do
end
describe '#make_installed' do
- subject { create(:cluster_applications_helm, :installing) }
+ subject { create(:clusters_applications_helm, :installing) }
it 'is installed' do
subject.make_installed
@@ -66,7 +66,7 @@ describe Clusters::Applications::Helm do
end
describe '#make_errored' do
- subject { create(:cluster_applications_helm, :installing) }
+ subject { create(:clusters_applications_helm, :installing) }
let(:reason) { 'some errors' }
it 'is errored' do
@@ -78,7 +78,7 @@ describe Clusters::Applications::Helm do
end
describe '#make_scheduled' do
- subject { create(:cluster_applications_helm, :installable) }
+ subject { create(:clusters_applications_helm, :installable) }
it 'is scheduled' do
subject.make_scheduled
@@ -87,7 +87,7 @@ describe Clusters::Applications::Helm do
end
describe 'when was errored' do
- subject { create(:cluster_applications_helm, :errored) }
+ subject { create(:clusters_applications_helm, :errored) }
it 'clears #status_reason' do
expect(subject.status_reason).not_to be_nil
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index b83472e1944..619c088b0bf 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -4,105 +4,5 @@ describe Clusters::Applications::Ingress do
it { is_expected.to belong_to(:cluster) }
it { is_expected.to validate_presence_of(:cluster) }
- describe '#name' do
- it 'is .application_name' do
- expect(subject.name).to eq(described_class.application_name)
- end
-
- it 'is recorded in Clusters::Cluster::APPLICATIONS' do
- expect(Clusters::Cluster::APPLICATIONS[subject.name]).to eq(described_class)
- end
- end
-
- describe '#status' do
- let(:cluster) { create(:cluster, :provided_by_gcp) }
-
- subject { described_class.new(cluster: cluster) }
-
- it 'defaults to :not_installable' do
- expect(subject.status_name).to be(:not_installable)
- end
-
- context 'when application helm is scheduled' do
- before do
- create(:cluster_applications_helm, :scheduled, cluster: cluster)
- end
-
- it 'defaults to :not_installable' do
- expect(subject.status_name).to be(:not_installable)
- end
- end
-
- context 'when application helm is installed' do
- before do
- create(:cluster_applications_helm, :installed, cluster: cluster)
- end
-
- it 'defaults to :installable' do
- expect(subject.status_name).to be(:installable)
- end
- end
- end
-
- describe '#install_command' do
- it 'has all the needed information' do
- expect(subject.install_command).to have_attributes(name: subject.name, install_helm: false, chart: subject.chart)
- end
- end
-
- describe 'status state machine' do
- describe '#make_installing' do
- subject { create(:cluster_applications_ingress, :scheduled) }
-
- it 'is installing' do
- subject.make_installing!
-
- expect(subject).to be_installing
- end
- end
-
- describe '#make_installed' do
- subject { create(:cluster_applications_ingress, :installing) }
-
- it 'is installed' do
- subject.make_installed
-
- expect(subject).to be_installed
- end
- end
-
- describe '#make_errored' do
- subject { create(:cluster_applications_ingress, :installing) }
- let(:reason) { 'some errors' }
-
- it 'is errored' do
- subject.make_errored(reason)
-
- expect(subject).to be_errored
- expect(subject.status_reason).to eq(reason)
- end
- end
-
- describe '#make_scheduled' do
- subject { create(:cluster_applications_ingress, :installable) }
-
- it 'is scheduled' do
- subject.make_scheduled
-
- expect(subject).to be_scheduled
- end
-
- describe 'when was errored' do
- subject { create(:cluster_applications_ingress, :errored) }
-
- it 'clears #status_reason' do
- expect(subject.status_reason).not_to be_nil
-
- subject.make_scheduled!
-
- expect(subject.status_reason).to be_nil
- end
- end
- end
- end
+ include_examples 'cluster application specs', described_class
end
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
new file mode 100644
index 00000000000..696099f7cf7
--- /dev/null
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -0,0 +1,16 @@
+require 'rails_helper'
+
+describe Clusters::Applications::Prometheus do
+ it { is_expected.to belong_to(:cluster) }
+ it { is_expected.to validate_presence_of(:cluster) }
+
+ include_examples 'cluster application specs', described_class
+
+ describe "#chart_values_file" do
+ subject { create(:clusters_applications_prometheus).chart_values_file }
+
+ it 'should return chart values file path' do
+ expect(subject).to eq("#{Rails.root}/vendor/prometheus/values.yaml")
+ end
+ end
+end
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 2683d21ddbe..799d7ced116 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -5,6 +5,9 @@ describe Clusters::Cluster do
it { is_expected.to have_many(:projects) }
it { is_expected.to have_one(:provider_gcp) }
it { is_expected.to have_one(:platform_kubernetes) }
+ it { is_expected.to have_one(:application_helm) }
+ it { is_expected.to have_one(:application_ingress) }
+ it { is_expected.to have_one(:application_prometheus) }
it { is_expected.to delegate_method(:status).to(:provider) }
it { is_expected.to delegate_method(:status_reason).to(:provider) }
it { is_expected.to delegate_method(:status_name).to(:provider) }
@@ -190,11 +193,12 @@ describe Clusters::Cluster do
end
context 'when applications are created' do
- let!(:helm) { create(:cluster_applications_helm, cluster: cluster) }
- let!(:ingress) { create(:cluster_applications_ingress, cluster: cluster) }
+ let!(:helm) { create(:clusters_applications_helm, cluster: cluster) }
+ let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) }
+ let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) }
it 'returns a list of created applications' do
- is_expected.to contain_exactly(helm, ingress)
+ is_expected.to contain_exactly(helm, ingress, prometheus)
end
end
end
diff --git a/spec/serializers/cluster_application_entity_spec.rb b/spec/serializers/cluster_application_entity_spec.rb
index 87c7b2ad36e..b5a55b4ef6e 100644
--- a/spec/serializers/cluster_application_entity_spec.rb
+++ b/spec/serializers/cluster_application_entity_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe ClusterApplicationEntity do
describe '#as_json' do
- let(:application) { build(:cluster_applications_helm) }
+ let(:application) { build(:clusters_applications_helm) }
subject { described_class.new(application).as_json }
it 'has name' do
@@ -18,7 +18,7 @@ describe ClusterApplicationEntity do
end
context 'when application is errored' do
- let(:application) { build(:cluster_applications_helm, :errored) }
+ let(:application) { build(:clusters_applications_helm, :errored) }
it 'has corresponded data' do
expect(subject[:status]).to eq(:errored)
diff --git a/spec/services/clusters/applications/check_installation_progress_service_spec.rb b/spec/services/clusters/applications/check_installation_progress_service_spec.rb
index 75fc05d36e9..6894c1797b0 100644
--- a/spec/services/clusters/applications/check_installation_progress_service_spec.rb
+++ b/spec/services/clusters/applications/check_installation_progress_service_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Clusters::Applications::CheckInstallationProgressService do
RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze
- let(:application) { create(:cluster_applications_helm, :installing) }
+ let(:application) { create(:clusters_applications_helm, :installing) }
let(:service) { described_class.new(application) }
let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN }
let(:errors) { nil }
@@ -33,7 +33,7 @@ describe Clusters::Applications::CheckInstallationProgressService do
end
context 'when timeouted' do
- let(:application) { create(:cluster_applications_helm, :timeouted) }
+ let(:application) { create(:clusters_applications_helm, :timeouted) }
it_behaves_like 'a terminated installation'
diff --git a/spec/services/clusters/applications/install_service_spec.rb b/spec/services/clusters/applications/install_service_spec.rb
index 054a49ffedf..ad175226e92 100644
--- a/spec/services/clusters/applications/install_service_spec.rb
+++ b/spec/services/clusters/applications/install_service_spec.rb
@@ -2,17 +2,19 @@ require 'spec_helper'
describe Clusters::Applications::InstallService do
describe '#execute' do
- let(:application) { create(:cluster_applications_helm, :scheduled) }
+ let(:application) { create(:clusters_applications_helm, :scheduled) }
+ let!(:install_command) { application.install_command }
let(:service) { described_class.new(application) }
- let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm) }
+ let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm::Api) }
before do
+ allow(service).to receive(:install_command).and_return(install_command)
allow(service).to receive(:helm_api).and_return(helm_client)
end
context 'when there are no errors' do
before do
- expect(helm_client).to receive(:install).with(application.install_command)
+ expect(helm_client).to receive(:install).with(install_command)
allow(ClusterWaitForAppInstallationWorker).to receive(:perform_in).and_return(nil)
end
@@ -33,7 +35,7 @@ describe Clusters::Applications::InstallService do
context 'when k8s cluster communication fails' do
before do
error = KubeException.new(500, 'system failure', nil)
- expect(helm_client).to receive(:install).with(application.install_command).and_raise(error)
+ expect(helm_client).to receive(:install).with(install_command).and_raise(error)
end
it 'make the application errored' do
@@ -45,7 +47,7 @@ describe Clusters::Applications::InstallService do
end
context 'when application cannot be persisted' do
- let(:application) { build(:cluster_applications_helm, :scheduled) }
+ let(:application) { build(:clusters_applications_helm, :scheduled) }
it 'make the application errored' do
expect(application).to receive(:make_installing!).once.and_raise(ActiveRecord::RecordInvalid)
diff --git a/spec/services/clusters/applications/schedule_installation_service_spec.rb b/spec/services/clusters/applications/schedule_installation_service_spec.rb
index 047a6e44dab..473dbcbb692 100644
--- a/spec/services/clusters/applications/schedule_installation_service_spec.rb
+++ b/spec/services/clusters/applications/schedule_installation_service_spec.rb
@@ -34,7 +34,7 @@ describe Clusters::Applications::ScheduleInstallationService do
end
context 'when installation is already in progress' do
- let(:application) { create(:cluster_applications_helm, :installing) }
+ let(:application) { create(:clusters_applications_helm, :installing) }
let(:cluster) { application.cluster }
it_behaves_like 'a failing service'
diff --git a/spec/support/cluster_application_spec.rb b/spec/support/cluster_application_spec.rb
new file mode 100644
index 00000000000..ab77910a050
--- /dev/null
+++ b/spec/support/cluster_application_spec.rb
@@ -0,0 +1,105 @@
+shared_examples 'cluster application specs' do
+ let(:factory_name) { described_class.to_s.downcase.gsub("::", "_") }
+
+ describe '#name' do
+ it 'is .application_name' do
+ expect(subject.name).to eq(described_class.application_name)
+ end
+
+ it 'is recorded in Clusters::Cluster::APPLICATIONS' do
+ expect(Clusters::Cluster::APPLICATIONS[subject.name]).to eq(described_class)
+ end
+ end
+
+ describe '#status' do
+ let(:cluster) { create(:cluster, :provided_by_gcp) }
+
+ subject { described_class.new(cluster: cluster) }
+
+ it 'defaults to :not_installable' do
+ expect(subject.status_name).to be(:not_installable)
+ end
+
+ context 'when application helm is scheduled' do
+ before do
+ create(factory_name, :scheduled, cluster: cluster)
+ end
+
+ it 'defaults to :not_installable' do
+ expect(subject.status_name).to be(:not_installable)
+ end
+ end
+
+ context 'when application helm is installed' do
+ before do
+ create(:clusters_applications_helm, :installed, cluster: cluster)
+ end
+
+ it 'defaults to :installable' do
+ expect(subject.status_name).to be(:installable)
+ end
+ end
+ end
+
+ describe '#install_command' do
+ it 'has all the needed information' do
+ expect(subject.install_command).to have_attributes(name: subject.name, install_helm: false)
+ end
+ end
+
+ describe 'status state machine' do
+ describe '#make_installing' do
+ subject { create(factory_name, :scheduled) }
+
+ it 'is installing' do
+ subject.make_installing!
+
+ expect(subject).to be_installing
+ end
+ end
+
+ describe '#make_installed' do
+ subject { create(factory_name, :installing) }
+
+ it 'is installed' do
+ subject.make_installed
+
+ expect(subject).to be_installed
+ end
+ end
+
+ describe '#make_errored' do
+ subject { create(factory_name, :installing) }
+ let(:reason) { 'some errors' }
+
+ it 'is errored' do
+ subject.make_errored(reason)
+
+ expect(subject).to be_errored
+ expect(subject.status_reason).to eq(reason)
+ end
+ end
+
+ describe '#make_scheduled' do
+ subject { create(factory_name, :installable) }
+
+ it 'is scheduled' do
+ subject.make_scheduled
+
+ expect(subject).to be_scheduled
+ end
+
+ describe 'when was errored' do
+ subject { create(factory_name, :errored) }
+
+ it 'clears #status_reason' do
+ expect(subject.status_reason).not_to be_nil
+
+ subject.make_scheduled!
+
+ expect(subject.status_reason).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/prometheus/values.yaml b/vendor/prometheus/values.yaml
new file mode 100644
index 00000000000..dd9496deb4d
--- /dev/null
+++ b/vendor/prometheus/values.yaml
@@ -0,0 +1,134 @@
+alertmanager: |
+ enabled: false
+
+kubeStateMetrics: |
+ enabled: 'false'
+
+nodeExporter: |
+ enabled: 'false'
+
+pushgateway: |
+ enabled: 'false'
+
+serverFiles: |
+ alerts: ''
+ rules: ''
+
+ prometheus.yml: |-
+ rule_files: |
+ - /etc/config/rules
+ - /etc/config/alerts
+ scrape_configs: |
+ - job_name: prometheus
+ static_configs: |
+ - targets:
+ - localhost:9090
+
+ - job_name: 'kubernetes-apiservers'
+ kubernetes_sd_configs: |
+ - role: endpoints
+ scheme: https
+
+ tls_config:
+ ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecure_skip_verify: true
+ bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+ relabel_configs:
+ - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
+ action: keep
+ regex: default;kubernetes;https
+ - job_name: 'kubernetes-nodes'
+ scheme: https
+ tls_config:
+ ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecure_skip_verify: true
+ bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+ kubernetes_sd_configs:
+ - role: node
+ relabel_configs:
+ - action: labelmap
+ regex: __meta_kubernetes_node_label_(.+)
+ - target_label: __address__
+ replacement: kubernetes.default.svc:443
+ - source_labels: [__meta_kubernetes_node_name]
+ regex: (.+)
+ target_label: __metrics_path__
+ replacement: /api/v1/nodes/${1}/proxy/metrics
+
+ - job_name: 'kubernetes-service-endpoints'
+ kubernetes_sd_configs:
+ - role: endpoints
+ relabel_configs: |
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
+ action: keep
+ regex: 'true'
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
+ action: replace
+ target_label: __scheme__
+ regex: (https?)
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
+ action: replace
+ target_label: __metrics_path__
+ regex: (.+)
+ - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
+ action: replace
+ target_label: __address__
+ regex: (.+)(?::\d+);(\d+)
+ replacement: $1:$2
+ - action: labelmap
+ regex: __meta_kubernetes_service_label_(.+)
+ - source_labels: [__meta_kubernetes_namespace]
+ action: replace
+ target_label: kubernetes_namespace
+ - source_labels: [__meta_kubernetes_service_name]
+ action: replace
+ target_label: kubernetes_name
+ - job_name: 'prometheus-pushgateway'
+ honor_labels: true
+ kubernetes_sd_configs: |
+ - role: service
+ relabel_configs: |
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
+ action: keep
+ regex: pushgateway
+ - job_name: 'kubernetes-services'
+ metrics_path: /probe
+ params: |
+ module: [http_2xx]
+ kubernetes_sd_configs: |
+ - role: service
+ relabel_configs: |
+ - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
+ action: keep
+ regex: 'true'
+ - source_labels: [__address__]
+ target_label: __param_target
+ - target_label: __address__
+ replacement: blackbox
+ - source_labels: [__param_target]
+ target_label: instance
+ - action: labelmap
+ regex: __meta_kubernetes_service_label_(.+)
+ - source_labels: [__meta_kubernetes_namespace]
+ target_label: kubernetes_namespace
+ - source_labels: [__meta_kubernetes_service_name]
+ target_label: kubernetes_name
+ - job_name: 'kubernetes-pods'
+ kubernetes_sd_configs:
+ - role: pod
+ relabel_configs:
+ - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
+ action: keep
+ regex: 'true'
+ - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
+ action: replace
+ target_label: __metrics_path__
+ regex: (.+)
+ - action: labelmap
+ regex: __meta_kubernetes_pod_label_(.+)
+ - source_labels: [__meta_kubernetes_namespace]
+ action: replace
+ target_label: kubernetes_namespace
+ - source_labels: [__meta_kubernetes_pod_name]
+ action: replace
+ target_label: kubernetes_pod_name
--
cgit v1.2.1
From 86c0bb49b79217e318122e8921f92ef78ee7a1cf Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Fri, 22 Dec 2017 18:23:14 +0000
Subject: Uniform style between all upload forms
---
app/views/groups/edit.html.haml | 4 ++--
app/views/profiles/show.html.haml | 13 +++++------
app/views/projects/edit.html.haml | 25 +++++++++++-----------
.../shared/_choose_group_avatar_button.html.haml | 11 ++++------
4 files changed, 23 insertions(+), 30 deletions(-)
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 16038ef2f79..76a8099d7c0 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -13,13 +13,13 @@
= group_icon(@group, alt: '', class: 'avatar group-avatar s160')
%p.light
- if @group.avatar?
- You can change your group avatar here
+ You can change the group avatar here
- else
You can upload a group avatar here
= render 'shared/choose_group_avatar_button', f: f
- if @group.avatar?
%hr
- = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
+ = link_to _('Remove avatar'), group_avatar_path(@group.to_param), data: { confirm: _("Avatar will be removed. Are you sure?")}, method: :delete, class: "btn btn-danger btn-inverted"
= render 'shared/visibility_level', f: f, visibility_level: @group.visibility_level, can_change_visibility_level: can_change_group_visibility_level?(@group), form_model: @group
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index f9dae310e01..0f773933ac2 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -22,18 +22,15 @@
.clearfix.avatar-image.append-bottom-default
= link_to avatar_icon(@user, 400), target: '_blank', rel: 'noopener noreferrer' do
= image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160'
- %h5.prepend-top-0
- Upload new avatar
+ %h5.prepend-top-0= _("Upload new avatar")
.prepend-top-5.append-bottom-10
- %a.btn.js-choose-user-avatar-button
- Choose file...
- %span.avatar-file-name.prepend-left-default.js-avatar-filename No file chosen
+ %button.btn.js-choose-user-avatar-button{ type: 'button' }= _("Choose file...")
+ %span.avatar-file-name.prepend-left-default.js-avatar-filename= _("No file chosen")
= f.file_field_without_bootstrap :avatar, class: 'js-user-avatar-input hidden', accept: 'image/*'
- .help-block
- The maximum file size allowed is 200KB.
+ .help-block= _("The maximum file size allowed is 200KB.")
- if @user.avatar?
%hr
- = link_to 'Remove avatar', profile_avatar_path, data: { confirm: 'Avatar will be removed. Are you sure?' }, method: :delete, class: 'btn btn-gray'
+ = link_to _('Remove avatar'), profile_avatar_path, data: { confirm: _('Avatar will be removed. Are you sure?') }, method: :delete, class: 'btn btn-danger btn-inverted'
%hr
.row
.col-lg-4.profile-settings-sidebar
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 9d0d525a292..e16d132f869 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -42,24 +42,23 @@
= f.text_field :tag_list, value: @project.tag_list.sort.join(', '), maxlength: 2000, class: "form-control"
%p.help-block Separate tags with commas.
%fieldset.features
- %h5.prepend-top-0
- Project avatar
+ %h5.prepend-top-0= _("Project avatar")
.form-group
- if @project.avatar?
- .avatar-container.s160
+ .avatar-container.s160.append-bottom-15
= project_icon(@project.full_path, alt: '', class: 'avatar project-avatar s160')
- %p.light
- - if @project.avatar_in_git
- Project avatar in repository: #{ @project.avatar_in_git }
- %a.choose-btn.btn.js-choose-project-avatar-button
- Choose file...
- %span.file_name.prepend-left-default.js-avatar-filename No file chosen
- = f.file_field :avatar, class: "js-project-avatar-input hidden"
- .help-block The maximum file size allowed is 200KB.
+ - if @project.avatar_in_git
+ %p.light
+ = _("Project avatar in repository: %{link}").html_safe % { link: @project.avatar_in_git }
+ .prepend-top-5.append-bottom-10
+ %button.btn.js-choose-project-avatar-button{ type: 'button' }= _("Choose file...")
+ %span.file_name.prepend-left-default.js-avatar-filename= _("No file chosen")
+ = f.file_field :avatar, class: "js-project-avatar-input hidden"
+ .help-block= _("The maximum file size allowed is 200KB.")
- if @project.avatar?
%hr
- = link_to 'Remove avatar', project_avatar_path(@project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
- = f.submit 'Save changes', class: "btn btn-save"
+ = link_to _('Remove avatar'), project_avatar_path(@project), data: { confirm: _("Avatar will be removed. Are you sure?") }, method: :delete, class: "btn btn-danger btn-inverted"
+ = f.submit 'Save changes', class: "btn btn-success"
%section.settings.sharing-permissions.no-animate{ class: ('expanded' if expanded) }
.settings-header
diff --git a/app/views/shared/_choose_group_avatar_button.html.haml b/app/views/shared/_choose_group_avatar_button.html.haml
index 94295970acf..75c65520350 100644
--- a/app/views/shared/_choose_group_avatar_button.html.haml
+++ b/app/views/shared/_choose_group_avatar_button.html.haml
@@ -1,7 +1,4 @@
-%button.choose-btn.btn.btn-sm.js-choose-group-avatar-button{ type: 'button' }
- %i.fa.fa-paperclip
- %span Choose File ...
-
-%span.file_name.js-avatar-filename File name...
-= f.file_field :avatar, class: 'js-group-avatar-input hidden'
-.light The maximum file size allowed is 200KB.
+%button.btn.js-choose-group-avatar-button{ type: 'button' }= _("Choose File ...")
+%span.file_name.js-avatar-filename= _("No file chosen")
+= f.file_field :avatar, class: "js-group-avatar-input hidden"
+.help-block= _("The maximum file size allowed is 200KB.")
--
cgit v1.2.1
From 705022d11422e42f5ff2473bdc1c80ddd0be9529 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 22 Dec 2017 20:07:49 +0100
Subject: Add cache_index migration
---
.../20171222183504_add_cache_index_to_project.rb | 19 +++++++++++++++++++
db/schema.rb | 3 ++-
2 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 db/migrate/20171222183504_add_cache_index_to_project.rb
diff --git a/db/migrate/20171222183504_add_cache_index_to_project.rb b/db/migrate/20171222183504_add_cache_index_to_project.rb
new file mode 100644
index 00000000000..f43be14fb42
--- /dev/null
+++ b/db/migrate/20171222183504_add_cache_index_to_project.rb
@@ -0,0 +1,19 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddCacheIndexToProject < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default(:projects, :cache_index, :integer, default: 0)
+ end
+
+ def down
+ remove_column(:projects, :cache_index)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index aa5db5da4f0..5ecfb0651c6 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20171220191323) do
+ActiveRecord::Schema.define(version: 20171222183504) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -1447,6 +1447,7 @@ ActiveRecord::Schema.define(version: 20171220191323) do
t.boolean "repository_read_only"
t.boolean "merge_requests_ff_only_enabled", default: false
t.boolean "merge_requests_rebase_enabled", default: false, null: false
+ t.integer "cache_index", default: 0, null: false
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
--
cgit v1.2.1
From f58cc2ee6044ab3445ff9a4438faa29b30b303fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 22 Dec 2017 20:22:29 +0100
Subject: Remove default value from cache_index migration
---
db/migrate/20171222183504_add_cache_index_to_project.rb | 10 ++--------
db/schema.rb | 2 +-
2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/db/migrate/20171222183504_add_cache_index_to_project.rb b/db/migrate/20171222183504_add_cache_index_to_project.rb
index f43be14fb42..e1d73db1ab0 100644
--- a/db/migrate/20171222183504_add_cache_index_to_project.rb
+++ b/db/migrate/20171222183504_add_cache_index_to_project.rb
@@ -7,13 +7,7 @@ class AddCacheIndexToProject < ActiveRecord::Migration
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:projects, :cache_index, :integer, default: 0)
- end
-
- def down
- remove_column(:projects, :cache_index)
+ def change
+ add_column :projects, :cache_index, :integer
end
end
diff --git a/db/schema.rb b/db/schema.rb
index 5ecfb0651c6..b7512f293a6 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1447,7 +1447,7 @@ ActiveRecord::Schema.define(version: 20171222183504) do
t.boolean "repository_read_only"
t.boolean "merge_requests_ff_only_enabled", default: false
t.boolean "merge_requests_rebase_enabled", default: false, null: false
- t.integer "cache_index", default: 0, null: false
+ t.integer "cache_index"
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
--
cgit v1.2.1
From 0a002e230badf96f5c89d55945ddd85113edd628 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 22 Dec 2017 21:28:25 +0100
Subject: Implement ResetProjectCacheService
---
app/services/reset_project_cache_service.rb | 1 +
spec/services/reset_project_cache_service_spec.rb | 20 ++++++++++++++++++--
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/app/services/reset_project_cache_service.rb b/app/services/reset_project_cache_service.rb
index 85ba6d953a2..0886c6b8315 100644
--- a/app/services/reset_project_cache_service.rb
+++ b/app/services/reset_project_cache_service.rb
@@ -1,4 +1,5 @@
class ResetProjectCacheService < BaseService
def execute
+ @project.increment!(:cache_index)
end
end
diff --git a/spec/services/reset_project_cache_service_spec.rb b/spec/services/reset_project_cache_service_spec.rb
index 9623035a5a4..df969d08f39 100644
--- a/spec/services/reset_project_cache_service_spec.rb
+++ b/spec/services/reset_project_cache_service_spec.rb
@@ -6,7 +6,23 @@ describe ResetProjectCacheService do
subject { described_class.new(project, user).execute }
- it "resets project cache" do
- fail
+ context 'when project cache_index is nil' do
+ before do
+ project.cache_index = nil
+ end
+
+ it 'sets project cache_index to one' do
+ expect { subject }.to change { project.reload.cache_index }.from(nil).to(1)
+ end
+ end
+
+ context 'when project cache_index is a numeric value' do
+ before do
+ project.update_attributes(cache_index: 1)
+ end
+
+ it 'increments project cache index' do
+ expect { subject }.to change { project.reload.cache_index }.by(1)
+ end
end
end
--
cgit v1.2.1
From 771b97394a16ae8dcd9acc84ab6a076f68726fd9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 22 Dec 2017 23:06:15 +0100
Subject: Use Project.cache_index in Build#cache
---
app/models/ci/build.rb | 6 +++++-
spec/models/ci/build_spec.rb | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 83fe23606d1..e4ca74f87f2 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -461,7 +461,11 @@ module Ci
end
def cache
- [options[:cache]]
+ if options[:cache] && project.cache_index
+ options[:cache].merge(key: "#{options[:cache][:key]}:#{project.cache_index}")
+ else
+ [options[:cache]]
+ end
end
def credentials
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 871e8b47650..96513281994 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -255,6 +255,42 @@ describe Ci::Build do
end
end
+ describe '#cache' do
+ let(:options) { { cache: { key: "key", paths: ["public"], policy: "pull-push" } } }
+
+ subject { build.cache }
+
+ context 'when build has cache' do
+ before do
+ allow(build).to receive(:options).and_return(options)
+ end
+
+ context 'when project has cache_index' do
+ before do
+ allow_any_instance_of(Project).to receive(:cache_index).and_return(1)
+ end
+
+ it { is_expected.to include(key: "key:1") }
+ end
+
+ context 'when project does not have cache_index' do
+ before do
+ allow_any_instance_of(Project).to receive(:cache_index).and_return(nil)
+ end
+
+ it { is_expected.to eq([options[:cache]]) }
+ end
+ end
+
+ context 'when build does not have cache' do
+ before do
+ allow(build).to receive(:options).and_return({})
+ end
+
+ it { is_expected.to eq([nil]) }
+ end
+ end
+
describe '#depends_on_builds' do
let!(:build) { create(:ci_build, pipeline: pipeline, name: 'build', stage_idx: 0, stage: 'build') }
let!(:rspec_test) { create(:ci_build, pipeline: pipeline, name: 'rspec', stage_idx: 1, stage: 'test') }
--
cgit v1.2.1
From 7354c9f75dfbf4c495d2869b5dd4f0dd4f5c9612 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?=
Date: Wed, 20 Dec 2017 16:54:09 -0300
Subject: Remove unused method `remote_exists?`
---
app/models/repository.rb | 4 ----
lib/gitlab/git/repository.rb | 5 -----
spec/lib/gitlab/git/repository_spec.rb | 15 ---------------
3 files changed, 24 deletions(-)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index a34f5e5439b..b1fd981965c 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1010,10 +1010,6 @@ class Repository
raw_repository.fetch_source_branch!(source_repository.raw_repository, source_branch, local_ref)
end
- def remote_exists?(name)
- raw_repository.remote_exists?(name)
- end
-
def compare_source_branch(target_branch_name, source_repository, source_branch_name, straight:)
raw_repository.compare_source_branch(target_branch_name, source_repository.raw_repository, source_branch_name, straight: straight)
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 044c60caa05..4fc37b63085 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -940,11 +940,6 @@ module Gitlab
false
end
- # Returns true if a remote exists.
- def remote_exists?(name)
- rugged.remotes[name].present?
- end
-
# Update the specified remote using the values in the +options+ hash
#
# Example
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 03a9cc488ca..ad16f9af0f1 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -701,21 +701,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#remote_exists?' do
- before(:all) do
- @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
- @repo.add_remote("new_remote", SeedHelper::GITLAB_GIT_TEST_REPO_URL)
- end
-
- it 'returns true for an existing remote' do
- expect(@repo.remote_exists?('new_remote')).to eq(true)
- end
-
- it 'returns false for a non-existing remote' do
- expect(@repo.remote_exists?('foo')).to eq(false)
- end
- end
-
describe "#log" do
let(:commit_with_old_name) do
Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id)
--
cgit v1.2.1
From 2694355bb6f6bf174b42127db35aa2c912501a9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?=
Date: Wed, 20 Dec 2017 17:17:28 -0300
Subject: Incorporate Gitaly's RemoteService RPCs
---
GITALY_SERVER_VERSION | 2 +-
Gemfile | 2 +-
Gemfile.lock | 4 +-
lib/gitlab/git/repository.rb | 56 +++++++++++++++-------
lib/gitlab/gitaly_client/remote_service.rb | 28 +++++++++++
spec/lib/gitlab/git/repository_spec.rb | 56 ++++++++++++++++++++++
.../gitlab/gitaly_client/remote_service_spec.rb | 34 +++++++++++++
7 files changed, 162 insertions(+), 20 deletions(-)
create mode 100644 lib/gitlab/gitaly_client/remote_service.rb
create mode 100644 spec/lib/gitlab/gitaly_client/remote_service_spec.rb
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 7e750b4ebf3..d4f16f06004 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.60.0
+0.64.0
diff --git a/Gemfile b/Gemfile
index b6ffaf80f24..a9a50ec084c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -400,7 +400,7 @@ group :ed25519 do
end
# Gitaly GRPC client
-gem 'gitaly-proto', '~> 0.61.0', require: 'gitaly'
+gem 'gitaly-proto', '~> 0.62.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index a6e3c9e27cc..64f8c955391 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -284,7 +284,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
- gitaly-proto (0.61.0)
+ gitaly-proto (0.62.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
@@ -1042,7 +1042,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
- gitaly-proto (~> 0.61.0)
+ gitaly-proto (~> 0.62.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.6.2)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 4fc37b63085..3ddd8fbe873 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -918,26 +918,23 @@ module Gitlab
# If `mirror_refmap` is present the remote is set as mirror with that mapping
def add_remote(remote_name, url, mirror_refmap: nil)
- rugged.remotes.create(remote_name, url)
-
- set_remote_as_mirror(remote_name, refmap: mirror_refmap) if mirror_refmap
- rescue Rugged::ConfigError
- remote_update(remote_name, url: url)
+ gitaly_migrate(:operation_user_add_tag) do |is_enabled|
+ if is_enabled
+ gitaly_remote_client.add_remote(remote_name, url, mirror_refmap)
+ else
+ rugged_add_remote(remote_name, url, mirror_refmap)
+ end
+ end
end
def remove_remote(remote_name)
- # When a remote is deleted all its remote refs are deleted too, but in
- # the case of mirrors we map its refs (that would usualy go under
- # [remote_name]/) to the top level namespace. We clean the mapping so
- # those don't get deleted.
- if rugged.config["remote.#{remote_name}.mirror"]
- rugged.config.delete("remote.#{remote_name}.fetch")
+ gitaly_migrate(:operation_user_add_tag) do |is_enabled|
+ if is_enabled
+ gitaly_remote_client.remove_remote(remote_name)
+ else
+ rugged_remove_remote(remote_name)
+ end
end
-
- rugged.remotes.delete(remote_name)
- true
- rescue Rugged::ConfigError
- false
end
# Update the specified remote using the values in the +options+ hash
@@ -1292,6 +1289,10 @@ module Gitlab
@gitaly_operation_client ||= Gitlab::GitalyClient::OperationService.new(self)
end
+ def gitaly_remote_client
+ @gitaly_remote_client ||= Gitlab::GitalyClient::RemoteService.new(self)
+ end
+
def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block)
Gitlab::GitalyClient.migrate(method, status: status, &block)
rescue GRPC::NotFound => e
@@ -1911,6 +1912,29 @@ module Gitlab
raise ArgumentError, 'Invalid merge source'
end
+ def rugged_add_remote(remote_name, url, mirror_refmap)
+ rugged.remotes.create(remote_name, url)
+
+ set_remote_as_mirror(remote_name, refmap: mirror_refmap) if mirror_refmap
+ rescue Rugged::ConfigError
+ remote_update(remote_name, url: url)
+ end
+
+ def rugged_remove_remote(remote_name)
+ # When a remote is deleted all its remote refs are deleted too, but in
+ # the case of mirrors we map its refs (that would usualy go under
+ # [remote_name]/) to the top level namespace. We clean the mapping so
+ # those don't get deleted.
+ if rugged.config["remote.#{remote_name}.mirror"]
+ rugged.config.delete("remote.#{remote_name}.fetch")
+ end
+
+ rugged.remotes.delete(remote_name)
+ true
+ rescue Rugged::ConfigError
+ false
+ end
+
def fetch_remote(remote_name = 'origin', env: nil)
run_git(['fetch', remote_name], env: env).last.zero?
end
diff --git a/lib/gitlab/gitaly_client/remote_service.rb b/lib/gitlab/gitaly_client/remote_service.rb
new file mode 100644
index 00000000000..9218f6cfd68
--- /dev/null
+++ b/lib/gitlab/gitaly_client/remote_service.rb
@@ -0,0 +1,28 @@
+module Gitlab
+ module GitalyClient
+ class RemoteService
+ def initialize(repository)
+ @repository = repository
+ @gitaly_repo = repository.gitaly_repository
+ @storage = repository.storage
+ end
+
+ def add_remote(name, url, mirror_refmap)
+ request = Gitaly::AddRemoteRequest.new(
+ repository: @gitaly_repo, name: name, url: url,
+ mirror_refmap: mirror_refmap.to_s
+ )
+
+ GitalyClient.call(@storage, :remote_service, :add_remote, request)
+ end
+
+ def remove_remote(name)
+ request = Gitaly::RemoveRemoteRequest.new(repository: @gitaly_repo, name: name)
+
+ response = GitalyClient.call(@storage, :remote_service, :remove_remote, request)
+
+ response.result
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index ad16f9af0f1..cf14f7d2207 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1828,6 +1828,62 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe 'remotes' do
+ let(:repository) do
+ Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
+ end
+ let(:remote_name) { 'my-remote' }
+
+ after do
+ ensure_seeds
+ end
+
+ describe '#add_remote' do
+ let(:url) { 'http://my-repo.git' }
+ let(:mirror_refmap) { '+refs/*:refs/*' }
+
+ it 'creates a new remote via Gitaly' do
+ expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
+ .to receive(:add_remote).with(remote_name, url, mirror_refmap)
+
+ repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap)
+ end
+
+ context 'with Gitaly disabled', :skip_gitaly_mock do
+ it 'creates a new remote via Rugged' do
+ expect_any_instance_of(Rugged::RemoteCollection).to receive(:create)
+ .with(remote_name, url)
+ expect_any_instance_of(Rugged::Config).to receive(:[]=)
+ .with("remote.#{remote_name}.mirror", true)
+ expect_any_instance_of(Rugged::Config).to receive(:[]=)
+ .with("remote.#{remote_name}.prune", true)
+ expect_any_instance_of(Rugged::Config).to receive(:[]=)
+ .with("remote.#{remote_name}.fetch", mirror_refmap)
+
+ repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap)
+ end
+ end
+ end
+
+ describe '#remove_remote' do
+ it 'removes the remote via Gitaly' do
+ expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
+ .to receive(:remove_remote).with(remote_name)
+
+ repository.remove_remote(remote_name)
+ end
+
+ context 'with Gitaly disabled', :skip_gitaly_mock do
+ it 'removes the remote via Rugged' do
+ expect_any_instance_of(Rugged::RemoteCollection).to receive(:delete)
+ .with(remote_name)
+
+ repository.remove_remote(remote_name)
+ end
+ end
+ end
+ end
+
def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
source_branch = repository.branches.find { |branch| branch.name == source_branch_name }
rugged = repository.rugged
diff --git a/spec/lib/gitlab/gitaly_client/remote_service_spec.rb b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb
new file mode 100644
index 00000000000..69c6f054016
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::RemoteService do
+ let(:project) { create(:project) }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.disk_path + '.git' }
+ let(:remote_name) { 'my-remote' }
+ let(:client) { described_class.new(project.repository) }
+
+ describe '#add_remote' do
+ let(:url) { 'http://my-repo.git' }
+ let(:mirror_refmap) { :all_refs }
+
+ it 'sends an add_remote message' do
+ expect_any_instance_of(Gitaly::RemoteService::Stub)
+ .to receive(:add_remote)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return(double(:add_remote_response))
+
+ client.add_remote(remote_name, url, mirror_refmap)
+ end
+ end
+
+ describe '#remove_remote' do
+ it 'sends an remove_remote message and returns the result value' do
+ expect_any_instance_of(Gitaly::RemoteService::Stub)
+ .to receive(:remove_remote)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return(double(result: true))
+
+ expect(client.remove_remote(remote_name)).to be(true)
+ end
+ end
+end
--
cgit v1.2.1
From f20581773a12b5653ad43d9e908d756935dcf62c Mon Sep 17 00:00:00 2001
From: blackst0ne
Date: Sat, 23 Dec 2017 12:53:13 +1100
Subject: Return exception messages in scripts/lint-changelog-yaml
---
scripts/lint-changelog-yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/scripts/lint-changelog-yaml b/scripts/lint-changelog-yaml
index cce5f1c7667..6553e02ffca 100755
--- a/scripts/lint-changelog-yaml
+++ b/scripts/lint-changelog-yaml
@@ -8,11 +8,13 @@ invalid_changelogs = Dir['changelogs/**/*'].reject do |changelog|
begin
YAML.load_file(changelog)
- rescue
+ rescue => exception
+ puts exception
end
end
if invalid_changelogs.any?
+ puts
puts "Invalid changelogs found!\n"
puts invalid_changelogs.sort
exit 1
--
cgit v1.2.1
From 0faf772b6cfd691e16d529051a8901627a660a7a Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Fri, 22 Dec 2017 23:19:57 -0800
Subject: Gracefully handle garbled URIs in Markdown
There are certain inputs that look like valid URIs that are accepted by URI
but not Addressable::URI. Handle the case where the latter fails.
Closes #41442
---
changelogs/unreleased/sh-catch-invalid-uri-markdown.yml | 5 +++++
lib/banzai/filter/relative_link_filter.rb | 2 +-
spec/lib/banzai/filter/relative_link_filter_spec.rb | 5 +++++
3 files changed, 11 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/sh-catch-invalid-uri-markdown.yml
diff --git a/changelogs/unreleased/sh-catch-invalid-uri-markdown.yml b/changelogs/unreleased/sh-catch-invalid-uri-markdown.yml
new file mode 100644
index 00000000000..9b0233fe988
--- /dev/null
+++ b/changelogs/unreleased/sh-catch-invalid-uri-markdown.yml
@@ -0,0 +1,5 @@
+---
+title: Gracefully handle garbled URIs in Markdown
+merge_request:
+author:
+type: fixed
diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb
index c1f933ec54b..5c197afd782 100644
--- a/lib/banzai/filter/relative_link_filter.rb
+++ b/lib/banzai/filter/relative_link_filter.rb
@@ -66,7 +66,7 @@ module Banzai
if uri.relative? && uri.path.present?
html_attr.value = rebuild_relative_uri(uri).to_s
end
- rescue URI::Error
+ rescue URI::Error, Addressable::URI::InvalidURIError
# noop
end
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index ef306f1cd4a..f38f0776303 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -76,6 +76,11 @@ describe Banzai::Filter::RelativeLinkFilter do
expect { filter(act) }.not_to raise_error
end
+ it 'does not raise an exception with a garbled path' do
+ act = link("open(/var/tmp/):%20/location%0Afrom:%20/test")
+ expect { filter(act) }.not_to raise_error
+ end
+
it 'ignores ref if commit is passed' do
doc = filter(link('non/existent.file'), commit: project.commit('empty-branch') )
expect(doc.at_css('a')['href'])
--
cgit v1.2.1
From ef82cbef90c59a8d1d59f05d4acf75a2ecbb42c9 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets
Date: Sat, 23 Dec 2017 14:18:39 +0000
Subject: Remove security checks from static analysis and add sast job
---
.gitlab-ci.yml | 8 ++++++++
scripts/static-analysis | 2 --
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4b149b13178..6ca2fb471aa 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -600,6 +600,14 @@ codequality:
artifacts:
paths: [codeclimate.json]
+sast:
+ image: registry.gitlab.com/gitlab-org/gl-sast:latest
+ before_script: []
+ script:
+ - /app/bin/run .
+ artifacts:
+ paths: [gl-sast-report.json]
+
qa:internal:
<<: *dedicated-runner
<<: *except-docs
diff --git a/scripts/static-analysis b/scripts/static-analysis
index 51a2fd81a79..2a2bc67800d 100755
--- a/scripts/static-analysis
+++ b/scripts/static-analysis
@@ -3,12 +3,10 @@
require ::File.expand_path('../lib/gitlab/popen', __dir__)
tasks = [
- %w[bundle exec bundle-audit check --update],
%w[bundle exec rake config_lint],
%w[bundle exec rake flay],
%w[bundle exec rake haml_lint],
%w[bundle exec rake scss_lint],
- %w[bundle exec rake brakeman],
%w[bundle exec license_finder],
%w[yarn run eslint],
%w[bundle exec rubocop --parallel],
--
cgit v1.2.1
From 6185ce0c84b5674abf4f54576fec44fece571565 Mon Sep 17 00:00:00 2001
From: Jacopo
Date: Thu, 21 Dec 2017 22:15:50 +0100
Subject: Rendering of emoji's in Group-Overview
Allows rendering of emoji's in the Group Overview.
---
app/assets/javascripts/groups/components/group_item.vue | 3 ++-
app/assets/javascripts/groups/store/groups_store.js | 2 +-
app/serializers/group_child_entity.rb | 9 +++++++++
.../unreleased/40549-render-emoj-in-groups-overview.yml | 5 +++++
spec/features/groups/show_spec.rb | 16 ++++++++++++++++
spec/serializers/group_child_entity_spec.rb | 12 +++++++++++-
6 files changed, 44 insertions(+), 3 deletions(-)
create mode 100644 changelogs/unreleased/40549-render-emoj-in-groups-overview.yml
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index 6421547bbde..ad01c261b7f 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -139,7 +139,8 @@ export default {
- {{group.description}}
+
+
😄
')
+ end
+ end
+
it_behaves_like 'group child json'
end
end
--
cgit v1.2.1
From 36bdf3dc9ac290058b73ab54abeb9ba84b211b29 Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Sun, 24 Dec 2017 09:03:58 -0800
Subject: Gracefully handle orphaned write deploy keys in
/internal/post_receive
On GitLab.com, there are write deploy keys with no associated users.
Pushes with these deploy keys end with an Error 500 since we attempt
to look up redirect message. If there is no user, don't attempt
to display a redirect message.
Closes #41466
---
changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml | 5 +++++
lib/api/internal.rb | 9 ++++++---
spec/requests/api/internal_spec.rb | 10 ++++++++++
3 files changed, 21 insertions(+), 3 deletions(-)
create mode 100644 changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml
diff --git a/changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml b/changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml
new file mode 100644
index 00000000000..7d3b622534e
--- /dev/null
+++ b/changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml
@@ -0,0 +1,5 @@
+---
+title: Gracefully handle orphaned write deploy keys in /internal/post_receive
+merge_request:
+author:
+type: fixed
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index ccaaeca10d4..79b302aae70 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -190,9 +190,12 @@ module API
project = Gitlab::GlRepository.parse(params[:gl_repository]).first
user = identify(params[:identifier])
- redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id)
- if redirect_message
- output[:redirected_message] = redirect_message
+
+ # A user is not guaranteed to be returned; an orphaned write deploy
+ # key could be used
+ if user
+ redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id)
+ output[:redirected_message] = redirect_message if redirect_message
end
output
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index bbcd1194ae5..7b25047ea8f 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -784,6 +784,16 @@ describe API::Internal do
expect(json_response["redirected_message"]).to eq(project_moved.redirect_message)
end
end
+
+ context 'with an orphaned write deploy key' do
+ it 'does not try to notify that project moved' do
+ allow_any_instance_of(Gitlab::Identifier).to receive(:identify).and_return(nil)
+
+ post api("/internal/post_receive"), valid_params
+
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
end
describe 'POST /internal/pre_receive' do
--
cgit v1.2.1
From 7b52a3482ec696320e4a101a80537e4e61118b5c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Sun, 24 Dec 2017 22:35:18 +0100
Subject: Add cache_index to list of safe Project attributes
---
spec/lib/gitlab/import_export/safe_model_attributes.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index ec8fa99e0da..7e09f486854 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -459,6 +459,7 @@ Project:
- delete_error
- merge_requests_ff_only_enabled
- merge_requests_rebase_enabled
+- cache_index
Author:
- name
ProjectFeature:
--
cgit v1.2.1
From b762430795230aca5e949c24f7c06b172750ebb6 Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Sun, 24 Dec 2017 09:35:30 -0800
Subject: Fix namespace ambiguity with Kubernetes Pod definitions
This was causing a spec failure between Gitlab::Kubernetes::Helm::Pod and
Gitlab::Kubernetes::Helm::Api::Pod if one spec loaded the former
definition first.
Closes #41458
---
lib/gitlab/kubernetes/helm/api.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb
index ebd7dc1b100..737081ddc5b 100644
--- a/lib/gitlab/kubernetes/helm/api.rb
+++ b/lib/gitlab/kubernetes/helm/api.rb
@@ -34,7 +34,7 @@ module Gitlab
private
def pod_resource(command)
- Pod.new(command, @namespace.name, @kubeclient).generate
+ Gitlab::Kubernetes::Helm::Pod.new(command, @namespace.name, @kubeclient).generate
end
end
end
--
cgit v1.2.1
From 40264b87af1c8a228a6b943367d6cd06d9f8d812 Mon Sep 17 00:00:00 2001
From: Semyon Pupkov
Date: Sun, 24 Dec 2017 17:03:38 +0500
Subject: Move invites spinach test to Rspec
https://gitlab.com/gitlab-org/gitlab-ce/issues/23036
---
features/invites.feature | 45 --------------------
features/steps/invites.rb | 80 -----------------------------------
spec/features/invites_spec.rb | 97 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 97 insertions(+), 125 deletions(-)
delete mode 100644 features/invites.feature
delete mode 100644 features/steps/invites.rb
create mode 100644 spec/features/invites_spec.rb
diff --git a/features/invites.feature b/features/invites.feature
deleted file mode 100644
index dc8eefaeaed..00000000000
--- a/features/invites.feature
+++ /dev/null
@@ -1,45 +0,0 @@
-Feature: Invites
- Background:
- Given "John Doe" is owner of group "Owned"
- And "John Doe" has invited "user@example.com" to group "Owned"
-
- Scenario: Viewing invitation when signed out
- When I visit the invitation page
- Then I should be redirected to the sign in page
- And I should see a notice telling me to sign in
-
- Scenario: Signing in to view invitation
- When I visit the invitation page
- And I sign in as "Mary Jane"
- Then I should be redirected to the invitation page
-
- Scenario: Viewing invitation when signed in
- Given I sign in as "Mary Jane"
- And I visit the invitation page
- Then I should see the invitation details
- And I should see an "Accept invitation" button
- And I should see a "Decline" button
-
- Scenario: Viewing invitation as an existing member
- Given I sign in as "John Doe"
- And I visit the invitation page
- Then I should see a message telling me I'm already a member
-
- Scenario: Accepting the invitation
- Given I sign in as "Mary Jane"
- And I visit the invitation page
- And I click the "Accept invitation" button
- Then I should be redirected to the group page
- And I should see a notice telling me I have access
-
- Scenario: Declining the application when signed in
- Given I sign in as "Mary Jane"
- And I visit the invitation page
- And I click the "Decline" button
- Then I should be redirected to the dashboard
- And I should see a notice telling me I have declined
-
- Scenario: Declining the application when signed out
- When I visit the invitation's decline page
- Then I should be redirected to the sign in page
- And I should see a notice telling me I have declined
diff --git a/features/steps/invites.rb b/features/steps/invites.rb
deleted file mode 100644
index dac972172aa..00000000000
--- a/features/steps/invites.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-class Spinach::Features::Invites < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedUser
- include SharedGroup
-
- step '"John Doe" has invited "user@example.com" to group "Owned"' do
- user = User.find_by(name: "John Doe")
- group = Group.find_by(name: "Owned")
- group.add_developer("user@example.com", user)
- end
-
- step 'I visit the invitation page' do
- group = Group.find_by(name: "Owned")
- invite = group.group_members.invite.last
- invite.generate_invite_token!
- @raw_invite_token = invite.raw_invite_token
- visit invite_path(@raw_invite_token)
- end
-
- step 'I should be redirected to the sign in page' do
- expect(current_path).to eq(new_user_session_path)
- end
-
- step 'I should see a notice telling me to sign in' do
- expect(page).to have_content "To accept this invitation, sign in"
- end
-
- step 'I should be redirected to the invitation page' do
- expect(current_path).to eq(invite_path(@raw_invite_token))
- end
-
- step 'I should see the invitation details' do
- expect(page).to have_content("You have been invited by John Doe to join group Owned as Developer.")
- end
-
- step "I should see a message telling me I'm already a member" do
- expect(page).to have_content("However, you are already a member of this group.")
- end
-
- step 'I should see an "Accept invitation" button' do
- expect(page).to have_link("Accept invitation")
- end
-
- step 'I should see a "Decline" button' do
- expect(page).to have_link("Decline")
- end
-
- step 'I click the "Accept invitation" button' do
- page.click_link "Accept invitation"
- end
-
- step 'I should be redirected to the group page' do
- group = Group.find_by(name: "Owned")
- expect(current_path).to eq(group_path(group))
- end
-
- step 'I should see a notice telling me I have access' do
- expect(page).to have_content("You have been granted Developer access to group Owned.")
- end
-
- step 'I click the "Decline" button' do
- page.click_link "Decline"
- end
-
- step 'I should be redirected to the dashboard' do
- expect(current_path).to eq(dashboard_projects_path)
- end
-
- step 'I should see a notice telling me I have declined' do
- expect(page).to have_content("You have declined the invitation to join group Owned.")
- end
-
- step "I visit the invitation's decline page" do
- group = Group.find_by(name: "Owned")
- invite = group.group_members.invite.last
- invite.generate_invite_token!
- @raw_invite_token = invite.raw_invite_token
- visit decline_invite_path(@raw_invite_token)
- end
-end
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
new file mode 100644
index 00000000000..e4be6193b8b
--- /dev/null
+++ b/spec/features/invites_spec.rb
@@ -0,0 +1,97 @@
+require 'spec_helper'
+
+describe 'Invites' do
+ let(:user) { create(:user) }
+ let(:owner) { create(:user, name: 'John Doe') }
+ let(:group) { create(:group, name: 'Owned') }
+ let(:project) { create(:project, :repository, namespace: group) }
+ let(:invite) { group.group_members.invite.last }
+
+ before do
+ project.add_master(owner)
+ group.add_user(owner, Gitlab::Access::OWNER)
+ group.add_developer('user@example.com', owner)
+ invite.generate_invite_token!
+ end
+
+ context 'when signed out' do
+ before do
+ visit invite_path(invite.raw_invite_token)
+ end
+
+ it 'renders sign in page with sign in notice' do
+ expect(current_path).to eq(new_user_session_path)
+ expect(page).to have_content('To accept this invitation, sign in')
+ end
+
+ it 'sign in and redirects to invitation page' do
+ fill_in 'user_login', with: user.email
+ fill_in 'user_password', with: user.password
+ check 'user_remember_me'
+ click_button 'Sign in'
+
+ expect(current_path).to eq(invite_path(invite.raw_invite_token))
+ expect(page).to have_content(
+ 'You have been invited by John Doe to join group Owned as Developer.'
+ )
+ expect(page).to have_link('Accept invitation')
+ expect(page).to have_link('Decline')
+ end
+ end
+
+ context 'when signed in as an exists member' do
+ before do
+ sign_in(owner)
+ end
+
+ it 'shows message user already a member' do
+ visit invite_path(invite.raw_invite_token)
+ expect(page).to have_content('However, you are already a member of this group.')
+ end
+ end
+
+ describe 'accepting the invitation' do
+ before do
+ sign_in(user)
+ visit invite_path(invite.raw_invite_token)
+ end
+
+ it 'grants access and redirects to group page' do
+ page.click_link 'Accept invitation'
+ expect(current_path).to eq(group_path(group))
+ expect(page).to have_content(
+ 'You have been granted Developer access to group Owned.'
+ )
+ end
+ end
+
+ describe 'declining the application' do
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ visit invite_path(invite.raw_invite_token)
+ end
+
+ it 'declines application and redirects to dashboard' do
+ page.click_link 'Decline'
+ expect(current_path).to eq(dashboard_projects_path)
+ expect(page).to have_content(
+ 'You have declined the invitation to join group Owned.'
+ )
+ end
+ end
+
+ context 'when signed out' do
+ before do
+ visit decline_invite_path(invite.raw_invite_token)
+ end
+
+ it 'declines application and redirects to sign in page' do
+ expect(current_path).to eq(new_user_session_path)
+ expect(page).to have_content(
+ 'You have declined the invitation to join group Owned.'
+ )
+ end
+ end
+ end
+end
--
cgit v1.2.1
From 7a815d7585a8a433359297f37b349604bfbcf2c8 Mon Sep 17 00:00:00 2001
From: Semyon Pupkov
Date: Sun, 24 Dec 2017 22:46:30 +0500
Subject: Move explore groups spinach test to RSpec
https://gitlab.com/gitlab-org/gitlab-ce/issues/23036
---
features/explore/groups.feature | 105 -----------------------------------
features/steps/explore/groups.rb | 88 -----------------------------
spec/features/explore/groups_spec.rb | 87 +++++++++++++++++++++++++++++
3 files changed, 87 insertions(+), 193 deletions(-)
delete mode 100644 features/explore/groups.feature
delete mode 100644 features/steps/explore/groups.rb
create mode 100644 spec/features/explore/groups_spec.rb
diff --git a/features/explore/groups.feature b/features/explore/groups.feature
deleted file mode 100644
index 830810615e0..00000000000
--- a/features/explore/groups.feature
+++ /dev/null
@@ -1,105 +0,0 @@
-@public
-Feature: Explore Groups
- Background:
- Given group "TestGroup" has private project "Enterprise"
-
- @javascript
- Scenario: I should see group with private and internal projects as user
- Given group "TestGroup" has internal project "Internal"
- When I sign in as a user
- And I visit group "TestGroup" page
- Then I should see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group issues for internal project as user
- Given group "TestGroup" has internal project "Internal"
- When I sign in as a user
- And I visit group "TestGroup" issues page
- Then I should see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group merge requests for internal project as user
- Given group "TestGroup" has internal project "Internal"
- When I sign in as a user
- And I visit group "TestGroup" merge requests page
- Then I should see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group with private, internal and public projects as visitor
- Given group "TestGroup" has internal project "Internal"
- Given group "TestGroup" has public project "Community"
- When I visit group "TestGroup" page
- Then I should see project "Community" items
- And I should not see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group issues for public project as visitor
- Given group "TestGroup" has internal project "Internal"
- Given group "TestGroup" has public project "Community"
- When I visit group "TestGroup" issues page
- Then I should see project "Community" items
- And I should not see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group merge requests for public project as visitor
- Given group "TestGroup" has internal project "Internal"
- Given group "TestGroup" has public project "Community"
- When I visit group "TestGroup" merge requests page
- Then I should see project "Community" items
- And I should not see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group with private, internal and public projects as user
- Given group "TestGroup" has internal project "Internal"
- Given group "TestGroup" has public project "Community"
- When I sign in as a user
- And I visit group "TestGroup" page
- Then I should see project "Community" items
- And I should see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group issues for internal and public projects as user
- Given group "TestGroup" has internal project "Internal"
- Given group "TestGroup" has public project "Community"
- When I sign in as a user
- And I visit group "TestGroup" issues page
- Then I should see project "Community" items
- And I should see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group merge requests for internal and public projects as user
- Given group "TestGroup" has internal project "Internal"
- Given group "TestGroup" has public project "Community"
- When I sign in as a user
- And I visit group "TestGroup" merge requests page
- Then I should see project "Community" items
- And I should see project "Internal" items
- And I should not see project "Enterprise" items
-
- @javascript
- Scenario: I should see group with public project in public groups area
- Given group "TestGroup" has public project "Community"
- When I visit the public groups area
- Then I should see group "TestGroup"
-
- @javascript
- Scenario: I should see group with public project in public groups area as user
- Given group "TestGroup" has public project "Community"
- When I sign in as a user
- And I visit the public groups area
- Then I should see group "TestGroup"
-
- @javascript
- Scenario: I should see group with internal project in public groups area as user
- Given group "TestGroup" has internal project "Internal"
- When I sign in as a user
- And I visit the public groups area
- Then I should see group "TestGroup"
diff --git a/features/steps/explore/groups.rb b/features/steps/explore/groups.rb
deleted file mode 100644
index 409bf0cb416..00000000000
--- a/features/steps/explore/groups.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-class Spinach::Features::ExploreGroups < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedGroup
- include SharedProject
-
- step 'group "TestGroup" has private project "Enterprise"' do
- group_has_project("TestGroup", "Enterprise", Gitlab::VisibilityLevel::PRIVATE)
- end
-
- step 'group "TestGroup" has internal project "Internal"' do
- group_has_project("TestGroup", "Internal", Gitlab::VisibilityLevel::INTERNAL)
- end
-
- step 'group "TestGroup" has public project "Community"' do
- group_has_project("TestGroup", "Community", Gitlab::VisibilityLevel::PUBLIC)
- end
-
- step '"John Doe" is owner of group "TestGroup"' do
- group = Group.find_by(name: "TestGroup") || create(:group, name: "TestGroup")
- user = create(:user, name: "John Doe")
- group.add_owner(user)
- end
-
- step 'I visit group "TestGroup" page' do
- visit group_path(Group.find_by(name: "TestGroup"))
- end
-
- step 'I visit group "TestGroup" issues page' do
- visit issues_group_path(Group.find_by(name: "TestGroup"))
- end
-
- step 'I visit group "TestGroup" merge requests page' do
- visit merge_requests_group_path(Group.find_by(name: "TestGroup"))
- end
-
- step 'I visit group "TestGroup" members page' do
- visit group_group_members_path(Group.find_by(name: "TestGroup"))
- end
-
- step 'I should not see project "Enterprise" items' do
- expect(page).not_to have_content "Enterprise"
- end
-
- step 'I should see project "Internal" items' do
- expect(page).to have_content "Internal"
- end
-
- step 'I should not see project "Internal" items' do
- expect(page).not_to have_content "Internal"
- end
-
- step 'I should see project "Community" items' do
- expect(page).to have_content "Community"
- end
-
- step 'I change filter to Everyone\'s' do
- click_link "Everyone's"
- end
-
- step 'I should see group member "John Doe"' do
- expect(page).to have_content "John Doe"
- end
-
- protected
-
- def group_has_project(groupname, projectname, visibility_level)
- group = Group.find_by(name: groupname) || create(:group, name: groupname)
- project = create(:project,
- namespace: group,
- name: projectname,
- path: "#{groupname}-#{projectname}",
- visibility_level: visibility_level
- )
- create(:issue,
- title: "#{projectname} feature",
- project: project
- )
- create(:merge_request,
- title: "#{projectname} feature implemented",
- source_project: project,
- target_project: project
- )
- create(:closed_issue_event,
- project: project
- )
- end
-end
diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb
new file mode 100644
index 00000000000..e4ef47d88dd
--- /dev/null
+++ b/spec/features/explore/groups_spec.rb
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+describe 'Explore Groups', :js do
+ let(:user) { create :user }
+ let(:group) { create :group }
+ let!(:private_project) do
+ create :project, :private, namespace: group do |project|
+ create(:issue, project: internal_project)
+ create(:merge_request, source_project: project, target_project: project)
+ end
+ end
+
+ let!(:internal_project) do
+ create :project, :internal, namespace: group do |project|
+ create(:issue, project: project)
+ create(:merge_request, source_project: project, target_project: project)
+ end
+ end
+
+ let!(:public_project) do
+ create(:project, :public, namespace: group) do |project|
+ create(:issue, project: project)
+ create(:merge_request, source_project: project, target_project: project)
+ end
+ end
+
+ shared_examples 'renders public and internal projects' do
+ it do
+ visit_page
+ expect(page).to have_content(public_project.name)
+ expect(page).to have_content(internal_project.name)
+ expect(page).not_to have_content(private_project.name)
+ end
+ end
+
+ shared_examples 'renders only public project' do
+ it do
+ visit_page
+ expect(page).to have_content(public_project.name)
+ expect(page).not_to have_content(internal_project.name)
+ expect(page).not_to have_content(private_project.name)
+ end
+ end
+
+ shared_examples 'renders group in public groups area' do
+ it do
+ visit explore_groups_path
+ expect(page).to have_content(group.name)
+ end
+ end
+
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
+
+ it_behaves_like 'renders public and internal projects' do
+ subject(:visit_page) { visit group_path(group) }
+ end
+
+ it_behaves_like 'renders public and internal projects' do
+ subject(:visit_page) { visit issues_group_path(group) }
+ end
+
+ it_behaves_like 'renders public and internal projects' do
+ subject(:visit_page) { visit merge_requests_group_path(group) }
+ end
+
+ it_behaves_like 'renders group in public groups area'
+ end
+
+ context 'when signed out' do
+ it_behaves_like 'renders only public project' do
+ subject(:visit_page) { visit group_path(group) }
+ end
+
+ it_behaves_like 'renders only public project' do
+ subject(:visit_page) { visit issues_group_path(group) }
+ end
+
+ it_behaves_like 'renders only public project' do
+ subject(:visit_page) { visit merge_requests_group_path(group) }
+ end
+
+ it_behaves_like 'renders group in public groups area'
+ end
+end
--
cgit v1.2.1
From 0960c703c0a7e37c2177aaf32b64c316f531fe15 Mon Sep 17 00:00:00 2001
From: Jonathan Duck
Date: Mon, 25 Dec 2017 12:48:48 +0000
Subject: Update code_climate recommended usage.
---
doc/ci/examples/code_climate.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/doc/ci/examples/code_climate.md b/doc/ci/examples/code_climate.md
index 4d0ba8bfef3..6a5821762cc 100644
--- a/doc/ci/examples/code_climate.md
+++ b/doc/ci/examples/code_climate.md
@@ -16,8 +16,7 @@ codequality:
- docker:dind
script:
- docker pull codeclimate/codeclimate
- - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate init
- - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > codeclimate.json
+ - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > codeclimate.json || true
artifacts:
paths: [codeclimate.json]
```
--
cgit v1.2.1
From a83c41f6c6e0035c40916b3cbdda7fdd4f7e925f Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Sun, 24 Dec 2017 09:35:30 -0800
Subject: Fix Error 500s with anonymous clones for a project that has moved
Closes #41457
---
.../unreleased/sh-handle-anonymous-clones-project-moved.yml | 5 +++++
lib/gitlab/checks/project_moved.rb | 13 ++++++++++---
spec/lib/gitlab/checks/project_moved_spec.rb | 7 +++++++
3 files changed, 22 insertions(+), 3 deletions(-)
create mode 100644 changelogs/unreleased/sh-handle-anonymous-clones-project-moved.yml
diff --git a/changelogs/unreleased/sh-handle-anonymous-clones-project-moved.yml b/changelogs/unreleased/sh-handle-anonymous-clones-project-moved.yml
new file mode 100644
index 00000000000..a0860871152
--- /dev/null
+++ b/changelogs/unreleased/sh-handle-anonymous-clones-project-moved.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Error 500s with anonymous clones for a project that has moved
+merge_request:
+author:
+type: fixed
diff --git a/lib/gitlab/checks/project_moved.rb b/lib/gitlab/checks/project_moved.rb
index 3a1c0a3455e..c1da2471b54 100644
--- a/lib/gitlab/checks/project_moved.rb
+++ b/lib/gitlab/checks/project_moved.rb
@@ -2,6 +2,7 @@ module Gitlab
module Checks
class ProjectMoved
REDIRECT_NAMESPACE = "redirect_namespace".freeze
+ ANONYMOUS_ID_KEY = 'anonymous'.freeze
def initialize(project, user, redirected_path, protocol)
@project = project
@@ -22,7 +23,7 @@ module Gitlab
def add_redirect_message
Gitlab::Redis::SharedState.with do |redis|
- key = self.class.redirect_message_key(user.id, project.id)
+ key = self.class.redirect_message_key(user_identifier, project.id)
redis.setex(key, 5.minutes, redirect_message)
end
end
@@ -45,8 +46,14 @@ module Gitlab
attr_reader :project, :redirected_path, :protocol, :user
- def self.redirect_message_key(user_id, project_id)
- "#{REDIRECT_NAMESPACE}:#{user_id}:#{project_id}"
+ def self.redirect_message_key(user_identifier, project_id)
+ "#{REDIRECT_NAMESPACE}:#{user_identifier}:#{project_id}"
+ end
+
+ def user_identifier
+ return ANONYMOUS_ID_KEY unless user.present?
+
+ user.id
end
def remote_url_message(rejected)
diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb
index fa1575e2177..3d72e78332d 100644
--- a/spec/lib/gitlab/checks/project_moved_spec.rb
+++ b/spec/lib/gitlab/checks/project_moved_spec.rb
@@ -35,6 +35,13 @@ describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do
project_moved = described_class.new(project, user, 'foo/bar', 'http')
expect(project_moved.add_redirect_message).to eq("OK")
end
+
+ it 'should handle anonymous clones' do
+ project_moved = described_class.new(project, nil, 'foo/bar', 'http')
+
+ expect(project_moved.add_redirect_message).to eq("OK")
+ expect(Gitlab::Redis::SharedState.with { |redis| redis.get("redirect_namespace:anonymous:#{project.id}") }).not_to be_nil
+ end
end
describe '#redirect_message' do
--
cgit v1.2.1
From b6c711fd38f65d78bbd02ad9ad05f22bcb5033c5 Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Mon, 25 Dec 2017 05:33:32 -0800
Subject: Disable redirect messages for anonymous clones
---
lib/gitlab/checks/project_moved.rb | 17 +++++++----------
spec/lib/gitlab/checks/project_moved_spec.rb | 3 +--
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/lib/gitlab/checks/project_moved.rb b/lib/gitlab/checks/project_moved.rb
index c1da2471b54..dfb2f4d4054 100644
--- a/lib/gitlab/checks/project_moved.rb
+++ b/lib/gitlab/checks/project_moved.rb
@@ -2,7 +2,6 @@ module Gitlab
module Checks
class ProjectMoved
REDIRECT_NAMESPACE = "redirect_namespace".freeze
- ANONYMOUS_ID_KEY = 'anonymous'.freeze
def initialize(project, user, redirected_path, protocol)
@project = project
@@ -22,8 +21,12 @@ module Gitlab
end
def add_redirect_message
+ # Don't bother with sending a redirect message for anonymous clones
+ # because they never see it via the `/internal/post_receive` endpoint
+ return unless user.present? && project.present?
+
Gitlab::Redis::SharedState.with do |redis|
- key = self.class.redirect_message_key(user_identifier, project.id)
+ key = self.class.redirect_message_key(user.id, project.id)
redis.setex(key, 5.minutes, redirect_message)
end
end
@@ -46,14 +49,8 @@ module Gitlab
attr_reader :project, :redirected_path, :protocol, :user
- def self.redirect_message_key(user_identifier, project_id)
- "#{REDIRECT_NAMESPACE}:#{user_identifier}:#{project_id}"
- end
-
- def user_identifier
- return ANONYMOUS_ID_KEY unless user.present?
-
- user.id
+ def self.redirect_message_key(user_id, project_id)
+ "#{REDIRECT_NAMESPACE}:#{user_id}:#{project_id}"
end
def remote_url_message(rejected)
diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb
index 3d72e78332d..f90c2d6aded 100644
--- a/spec/lib/gitlab/checks/project_moved_spec.rb
+++ b/spec/lib/gitlab/checks/project_moved_spec.rb
@@ -39,8 +39,7 @@ describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do
it 'should handle anonymous clones' do
project_moved = described_class.new(project, nil, 'foo/bar', 'http')
- expect(project_moved.add_redirect_message).to eq("OK")
- expect(Gitlab::Redis::SharedState.with { |redis| redis.get("redirect_namespace:anonymous:#{project.id}") }).not_to be_nil
+ expect(project_moved.add_redirect_message).to eq(nil)
end
end
--
cgit v1.2.1
From 8ae129954ffb5850d1804b5bd6a907696f6d77ee Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Fri, 22 Dec 2017 12:28:44 +0530
Subject: Reduce font size for 24px identicon
---
app/assets/stylesheets/framework/avatar.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index 26db2386879..077d0424093 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -71,7 +71,7 @@
vertical-align: top;
&.s16 { font-size: 12px; line-height: 1.33; }
- &.s24 { font-size: 14px; line-height: 1.8; }
+ &.s24 { font-size: 13px; line-height: 1.8; }
&.s26 { font-size: 20px; line-height: 1.33; }
&.s32 { font-size: 20px; line-height: 30px; }
&.s40 { font-size: 16px; line-height: 38px; }
--
cgit v1.2.1
From 86e0d931abc34600ea65f86e92d8d2423664150a Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Fri, 22 Dec 2017 12:29:09 +0530
Subject: Add `updatedAt` prop for Projects
---
app/assets/javascripts/groups/store/groups_store.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/assets/javascripts/groups/store/groups_store.js b/app/assets/javascripts/groups/store/groups_store.js
index a1689f4c5cc..ffc86175548 100644
--- a/app/assets/javascripts/groups/store/groups_store.js
+++ b/app/assets/javascripts/groups/store/groups_store.js
@@ -91,6 +91,7 @@ export default class GroupsStore {
subgroupCount: rawGroupItem.subgroup_count,
memberCount: rawGroupItem.number_users_with_delimiter,
starCount: rawGroupItem.star_count,
+ updatedAt: rawGroupItem.updated_at,
};
}
--
cgit v1.2.1
From 95ff461314a23a21a52f4dc240fa91873b91226c Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Fri, 22 Dec 2017 12:30:07 +0530
Subject: Use SVG sprite icons
---
.../javascripts/groups/components/item_actions.vue | 18 +++++++-----------
.../javascripts/groups/components/item_type_icon.vue | 13 +++++++------
2 files changed, 14 insertions(+), 17 deletions(-)
diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue
index 58ba5aff7cf..d3817cae6dc 100644
--- a/app/assets/javascripts/groups/components/item_actions.vue
+++ b/app/assets/javascripts/groups/components/item_actions.vue
@@ -1,14 +1,14 @@
+
+
+
+
+
+ {{value}}
+
+
+
diff --git a/spec/javascripts/groups/components/item_stats_value_spec.js b/spec/javascripts/groups/components/item_stats_value_spec.js
new file mode 100644
index 00000000000..e990870aaa6
--- /dev/null
+++ b/spec/javascripts/groups/components/item_stats_value_spec.js
@@ -0,0 +1,81 @@
+import Vue from 'vue';
+
+import itemStatsValueComponent from '~/groups/components/item_stats_value.vue';
+
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+const createComponent = ({ title, cssClass, iconName, tooltipPlacement, value }) => {
+ const Component = Vue.extend(itemStatsValueComponent);
+
+ return mountComponent(Component, {
+ title,
+ cssClass,
+ iconName,
+ tooltipPlacement,
+ value,
+ });
+};
+
+describe('ItemStatsValueComponent', () => {
+ describe('computed', () => {
+ let vm;
+ const itemConfig = {
+ title: 'Subgroups',
+ cssClass: 'number-subgroups',
+ iconName: 'folder',
+ tooltipPlacement: 'left',
+ };
+
+ describe('isValuePresent', () => {
+ it('returns true if non-empty `value` is present', () => {
+ vm = createComponent(Object.assign({}, itemConfig, { value: 10 }));
+ expect(vm.isValuePresent).toBeTruthy();
+ });
+
+ it('returns false if empty `value` is present', () => {
+ vm = createComponent(itemConfig);
+ expect(vm.isValuePresent).toBeFalsy();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+ });
+ });
+
+ describe('template', () => {
+ let vm;
+ beforeEach(() => {
+ vm = createComponent({
+ title: 'Subgroups',
+ cssClass: 'number-subgroups',
+ iconName: 'folder',
+ tooltipPlacement: 'left',
+ value: 10,
+ });
+ });
+
+ it('renders component element correctly', () => {
+ expect(vm.$el.classList.contains('number-subgroups')).toBeTruthy();
+ expect(vm.$el.querySelectorAll('svg').length > 0).toBeTruthy();
+ expect(vm.$el.querySelectorAll('.stat-value').length > 0).toBeTruthy();
+ });
+
+ it('renders element tooltip correctly', () => {
+ expect(vm.$el.dataset.originalTitle).toBe('Subgroups');
+ expect(vm.$el.dataset.placement).toBe('left');
+ });
+
+ it('renders element icon correctly', () => {
+ expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('folder');
+ });
+
+ it('renders value count correctly', () => {
+ expect(vm.$el.querySelector('.stat-value').innerText.trim()).toContain('10');
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+ });
+});
--
cgit v1.2.1
From f39f5d2f230d0b99852a6f5e40c2150a51022856 Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Fri, 22 Dec 2017 13:05:10 +0530
Subject: Use ItemStatsValue Component, add `updatedAt` info for projects
---
.../javascripts/groups/components/item_stats.vue | 88 +++++++++-------------
1 file changed, 37 insertions(+), 51 deletions(-)
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index 9f8ac138fc3..fbe129913fe 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -1,10 +1,14 @@
+
+
+
+
+
+
+
diff --git a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
new file mode 100644
index 00000000000..9ffbaae3ea5
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
@@ -0,0 +1,589 @@
+const fileExtensionIcons = {
+ html: 'html',
+ htm: 'html',
+ html_vm: 'html',
+ asp: 'html',
+ jade: 'pug',
+ pug: 'pug',
+ md: 'markdown',
+ 'md.rendered': 'markdown',
+ markdown: 'markdown',
+ 'markdown.rendered': 'markdown',
+ rst: 'markdown',
+ blink: 'blink',
+ css: 'css',
+ scss: 'sass',
+ sass: 'sass',
+ less: 'less',
+ json: 'json',
+ yaml: 'yaml',
+ 'YAML-tmLanguage': 'yaml',
+ yml: 'yaml',
+ xml: 'xml',
+ plist: 'xml',
+ xsd: 'xml',
+ dtd: 'xml',
+ xsl: 'xml',
+ xslt: 'xml',
+ resx: 'xml',
+ iml: 'xml',
+ xquery: 'xml',
+ tmLanguage: 'xml',
+ manifest: 'xml',
+ project: 'xml',
+ png: 'image',
+ jpeg: 'image',
+ jpg: 'image',
+ gif: 'image',
+ svg: 'image',
+ ico: 'image',
+ tif: 'image',
+ tiff: 'image',
+ psd: 'image',
+ psb: 'image',
+ ami: 'image',
+ apx: 'image',
+ bmp: 'image',
+ bpg: 'image',
+ brk: 'image',
+ cur: 'image',
+ dds: 'image',
+ dng: 'image',
+ exr: 'image',
+ fpx: 'image',
+ gbr: 'image',
+ img: 'image',
+ jbig2: 'image',
+ jb2: 'image',
+ jng: 'image',
+ jxr: 'image',
+ pbm: 'image',
+ pgf: 'image',
+ pic: 'image',
+ raw: 'image',
+ webp: 'image',
+ js: 'javascript',
+ ejs: 'javascript',
+ esx: 'javascript',
+ jsx: 'react',
+ tsx: 'react',
+ ini: 'settings',
+ dlc: 'settings',
+ dll: 'settings',
+ config: 'settings',
+ conf: 'settings',
+ properties: 'settings',
+ prop: 'settings',
+ settings: 'settings',
+ option: 'settings',
+ props: 'settings',
+ toml: 'settings',
+ prefs: 'settings',
+ 'sln.dotsettings': 'settings',
+ 'sln.dotsettings.user': 'settings',
+ ts: 'typescript',
+ 'd.ts': 'typescript-def',
+ marko: 'markojs',
+ pdf: 'pdf',
+ xlsx: 'table',
+ xls: 'table',
+ csv: 'table',
+ tsv: 'table',
+ vscodeignore: 'vscode',
+ vsixmanifest: 'vscode',
+ vsix: 'vscode',
+ 'code-workplace': 'vscode',
+ suo: 'visualstudio',
+ sln: 'visualstudio',
+ csproj: 'visualstudio',
+ vb: 'visualstudio',
+ pdb: 'database',
+ sql: 'database',
+ pks: 'database',
+ pkb: 'database',
+ accdb: 'database',
+ mdb: 'database',
+ sqlite: 'database',
+ cs: 'csharp',
+ zip: 'zip',
+ tar: 'zip',
+ gz: 'zip',
+ xz: 'zip',
+ bzip2: 'zip',
+ gzip: 'zip',
+ '7z': 'zip',
+ rar: 'zip',
+ tgz: 'zip',
+ exe: 'exe',
+ msi: 'exe',
+ java: 'java',
+ jar: 'java',
+ jsp: 'java',
+ c: 'c',
+ m: 'c',
+ h: 'h',
+ cc: 'cpp',
+ cpp: 'cpp',
+ mm: 'cpp',
+ cxx: 'cpp',
+ hpp: 'hpp',
+ go: 'go',
+ py: 'python',
+ url: 'url',
+ sh: 'console',
+ ksh: 'console',
+ csh: 'console',
+ tcsh: 'console',
+ zsh: 'console',
+ bash: 'console',
+ bat: 'console',
+ cmd: 'console',
+ ps1: 'powershell',
+ psm1: 'powershell',
+ psd1: 'powershell',
+ ps1xml: 'powershell',
+ psc1: 'powershell',
+ pssc: 'powershell',
+ gradle: 'gradle',
+ doc: 'word',
+ docx: 'word',
+ rtf: 'word',
+ cer: 'certificate',
+ cert: 'certificate',
+ crt: 'certificate',
+ pub: 'key',
+ key: 'key',
+ pem: 'key',
+ asc: 'key',
+ gpg: 'key',
+ woff: 'font',
+ woff2: 'font',
+ ttf: 'font',
+ eot: 'font',
+ suit: 'font',
+ otf: 'font',
+ bmap: 'font',
+ fnt: 'font',
+ odttf: 'font',
+ ttc: 'font',
+ font: 'font',
+ fonts: 'font',
+ sui: 'font',
+ ntf: 'font',
+ mrf: 'font',
+ lib: 'lib',
+ bib: 'lib',
+ rb: 'ruby',
+ erb: 'ruby',
+ fs: 'fsharp',
+ fsx: 'fsharp',
+ fsi: 'fsharp',
+ fsproj: 'fsharp',
+ swift: 'swift',
+ ino: 'arduino',
+ dockerignore: 'docker',
+ dockerfile: 'docker',
+ tex: 'tex',
+ cls: 'tex',
+ sty: 'tex',
+ pptx: 'powerpoint',
+ ppt: 'powerpoint',
+ pptm: 'powerpoint',
+ potx: 'powerpoint',
+ pot: 'powerpoint',
+ potm: 'powerpoint',
+ ppsx: 'powerpoint',
+ ppsm: 'powerpoint',
+ pps: 'powerpoint',
+ ppam: 'powerpoint',
+ ppa: 'powerpoint',
+ webm: 'movie',
+ mkv: 'movie',
+ flv: 'movie',
+ vob: 'movie',
+ ogv: 'movie',
+ ogg: 'movie',
+ gifv: 'movie',
+ avi: 'movie',
+ mov: 'movie',
+ qt: 'movie',
+ wmv: 'movie',
+ yuv: 'movie',
+ rm: 'movie',
+ rmvb: 'movie',
+ mp4: 'movie',
+ m4v: 'movie',
+ mpg: 'movie',
+ mp2: 'movie',
+ mpeg: 'movie',
+ mpe: 'movie',
+ mpv: 'movie',
+ m2v: 'movie',
+ vdi: 'virtual',
+ vbox: 'virtual',
+ 'vbox-prev': 'virtual',
+ ics: 'email',
+ mp3: 'music',
+ flac: 'music',
+ m4a: 'music',
+ wma: 'music',
+ aiff: 'music',
+ coffee: 'coffee',
+ txt: 'document',
+ graphql: 'graphql',
+ rs: 'rust',
+ raml: 'raml',
+ xaml: 'xaml',
+ hs: 'haskell',
+ kt: 'kotlin',
+ kts: 'kotlin',
+ patch: 'git',
+ lua: 'lua',
+ clj: 'clojure',
+ cljs: 'clojure',
+ groovy: 'groovy',
+ r: 'r',
+ rmd: 'r',
+ dart: 'dart',
+ as: 'actionscript',
+ mxml: 'mxml',
+ ahk: 'autohotkey',
+ swf: 'flash',
+ swc: 'swc',
+ cmake: 'cmake',
+ asm: 'assembly',
+ a51: 'assembly',
+ inc: 'assembly',
+ nasm: 'assembly',
+ s: 'assembly',
+ ms: 'assembly',
+ agc: 'assembly',
+ ags: 'assembly',
+ aea: 'assembly',
+ argus: 'assembly',
+ mitigus: 'assembly',
+ binsource: 'assembly',
+ vue: 'vue',
+ ml: 'ocaml',
+ mli: 'ocaml',
+ cmx: 'ocaml',
+ 'js.map': 'javascript-map',
+ 'css.map': 'css-map',
+ lock: 'lock',
+ hbs: 'handlebars',
+ mustache: 'handlebars',
+ pl: 'perl',
+ pm: 'perl',
+ hx: 'haxe',
+ 'spec.ts': 'test-ts',
+ 'test.ts': 'test-ts',
+ 'ts.snap': 'test-ts',
+ 'spec.tsx': 'test-jsx',
+ 'test.tsx': 'test-jsx',
+ 'tsx.snap': 'test-jsx',
+ 'spec.jsx': 'test-jsx',
+ 'test.jsx': 'test-jsx',
+ 'jsx.snap': 'test-jsx',
+ 'spec.js': 'test-js',
+ 'test.js': 'test-js',
+ 'js.snap': 'test-js',
+ 'routing.ts': 'angular-routing',
+ 'routing.js': 'angular-routing',
+ 'module.ts': 'angular',
+ 'module.js': 'angular',
+ 'ng-template': 'angular',
+ 'component.ts': 'angular-component',
+ 'component.js': 'angular-component',
+ 'guard.ts': 'angular-guard',
+ 'guard.js': 'angular-guard',
+ 'service.ts': 'angular-service',
+ 'service.js': 'angular-service',
+ 'pipe.ts': 'angular-pipe',
+ 'pipe.js': 'angular-pipe',
+ 'filter.js': 'angular-pipe',
+ 'directive.ts': 'angular-directive',
+ 'directive.js': 'angular-directive',
+ 'resolver.ts': 'angular-resolver',
+ 'resolver.js': 'angular-resolver',
+ pp: 'puppet',
+ ex: 'elixir',
+ exs: 'elixir',
+ ls: 'livescript',
+ erl: 'erlang',
+ twig: 'twig',
+ jl: 'julia',
+ elm: 'elm',
+ pure: 'purescript',
+ tpl: 'smarty',
+ styl: 'stylus',
+ re: 'reason',
+ rei: 'reason',
+ cmj: 'bucklescript',
+ merlin: 'merlin',
+ v: 'verilog',
+ vhd: 'verilog',
+ sv: 'verilog',
+ svh: 'verilog',
+ nb: 'mathematica',
+ wl: 'wolframlanguage',
+ wls: 'wolframlanguage',
+ njk: 'nunjucks',
+ nunjucks: 'nunjucks',
+ robot: 'robot',
+ sol: 'solidity',
+ au3: 'autoit',
+ haml: 'haml',
+ yang: 'yang',
+ tf: 'terraform',
+ 'tf.json': 'terraform',
+ tfvars: 'terraform',
+ tfstate: 'terraform',
+ 'blade.php': 'laravel',
+ 'inky.php': 'laravel',
+ applescript: 'applescript',
+ cake: 'cake',
+ feature: 'cucumber',
+ nim: 'nim',
+ nimble: 'nim',
+ apib: 'apiblueprint',
+ apiblueprint: 'apiblueprint',
+ tag: 'riot',
+ vfl: 'vfl',
+ kl: 'kl',
+ pcss: 'postcss',
+ sss: 'postcss',
+ todo: 'todo',
+ cfml: 'coldfusion',
+ cfc: 'coldfusion',
+ lucee: 'coldfusion',
+ cabal: 'cabal',
+ nix: 'nix',
+ slim: 'slim',
+ http: 'http',
+ rest: 'http',
+ rql: 'restql',
+ restql: 'restql',
+ kv: 'kivy',
+ graphcool: 'graphcool',
+ sbt: 'sbt',
+ 'reducer.ts': 'ngrx-reducer',
+ 'rootReducer.ts': 'ngrx-reducer',
+ 'state.ts': 'ngrx-state',
+ 'actions.ts': 'ngrx-actions',
+ 'effects.ts': 'ngrx-effects',
+ cr: 'crystal',
+ 'drone.yml': 'drone',
+ cu: 'cuda',
+ cuh: 'cuda',
+ log: 'log',
+};
+
+const fileNameIcons = {
+ '.jscsrc': 'json',
+ '.jshintrc': 'json',
+ 'tsconfig.json': 'json',
+ 'tslint.json': 'json',
+ 'composer.lock': 'json',
+ '.jsbeautifyrc': 'json',
+ '.esformatter': 'json',
+ 'cdp.pid': 'json',
+ '.htaccess': 'xml',
+ '.jshintignore': 'settings',
+ '.buildignore': 'settings',
+ makefile: 'settings',
+ '.mrconfig': 'settings',
+ '.yardopts': 'settings',
+ 'gradle.properties': 'gradle',
+ gradlew: 'gradle',
+ 'gradle-wrapper.properties': 'gradle',
+ license: 'certificate',
+ 'license.md': 'certificate',
+ 'license.md.rendered': 'certificate',
+ 'license.txt': 'certificate',
+ licence: 'certificate',
+ 'licence.md': 'certificate',
+ 'licence.md.rendered': 'certificate',
+ 'licence.txt': 'certificate',
+ dockerfile: 'docker',
+ 'docker-compose.yml': 'docker',
+ '.mailmap': 'email',
+ '.gitignore': 'git',
+ '.gitconfig': 'git',
+ '.gitattributes': 'git',
+ '.gitmodules': 'git',
+ '.gitkeep': 'git',
+ 'git-history': 'git',
+ '.Rhistory': 'r',
+ 'cmakelists.txt': 'cmake',
+ 'cmakecache.txt': 'cmake',
+ 'angular-cli.json': 'angular',
+ '.angular-cli.json': 'angular',
+ '.vfl': 'vfl',
+ '.kl': 'kl',
+ 'postcss.config.js': 'postcss',
+ '.postcssrc.js': 'postcss',
+ 'project.graphcool': 'graphcool',
+ 'webpack.js': 'webpack',
+ 'webpack.ts': 'webpack',
+ 'webpack.base.js': 'webpack',
+ 'webpack.base.ts': 'webpack',
+ 'webpack.config.js': 'webpack',
+ 'webpack.config.ts': 'webpack',
+ 'webpack.common.js': 'webpack',
+ 'webpack.common.ts': 'webpack',
+ 'webpack.config.common.js': 'webpack',
+ 'webpack.config.common.ts': 'webpack',
+ 'webpack.config.common.babel.js': 'webpack',
+ 'webpack.config.common.babel.ts': 'webpack',
+ 'webpack.dev.js': 'webpack',
+ 'webpack.dev.ts': 'webpack',
+ 'webpack.config.dev.js': 'webpack',
+ 'webpack.config.dev.ts': 'webpack',
+ 'webpack.config.dev.babel.js': 'webpack',
+ 'webpack.config.dev.babel.ts': 'webpack',
+ 'webpack.prod.js': 'webpack',
+ 'webpack.prod.ts': 'webpack',
+ 'webpack.server.js': 'webpack',
+ 'webpack.server.ts': 'webpack',
+ 'webpack.client.js': 'webpack',
+ 'webpack.client.ts': 'webpack',
+ 'webpack.config.server.js': 'webpack',
+ 'webpack.config.server.ts': 'webpack',
+ 'webpack.config.client.js': 'webpack',
+ 'webpack.config.client.ts': 'webpack',
+ 'webpack.config.production.babel.js': 'webpack',
+ 'webpack.config.production.babel.ts': 'webpack',
+ 'webpack.config.prod.babel.js': 'webpack',
+ 'webpack.config.prod.babel.ts': 'webpack',
+ 'webpack.config.prod.js': 'webpack',
+ 'webpack.config.prod.ts': 'webpack',
+ 'webpack.config.production.js': 'webpack',
+ 'webpack.config.production.ts': 'webpack',
+ 'webpack.config.staging.js': 'webpack',
+ 'webpack.config.staging.ts': 'webpack',
+ 'webpack.config.babel.js': 'webpack',
+ 'webpack.config.babel.ts': 'webpack',
+ 'webpack.config.base.babel.js': 'webpack',
+ 'webpack.config.base.babel.ts': 'webpack',
+ 'webpack.config.base.js': 'webpack',
+ 'webpack.config.base.ts': 'webpack',
+ 'webpack.config.staging.babel.js': 'webpack',
+ 'webpack.config.staging.babel.ts': 'webpack',
+ 'webpack.config.coffee': 'webpack',
+ 'webpack.config.test.js': 'webpack',
+ 'webpack.config.test.ts': 'webpack',
+ 'webpack.config.vendor.js': 'webpack',
+ 'webpack.config.vendor.ts': 'webpack',
+ 'webpack.config.vendor.production.js': 'webpack',
+ 'webpack.config.vendor.production.ts': 'webpack',
+ 'webpack.test.js': 'webpack',
+ 'webpack.test.ts': 'webpack',
+ 'webpack.dist.js': 'webpack',
+ 'webpack.dist.ts': 'webpack',
+ 'webpackfile.js': 'webpack',
+ 'webpackfile.ts': 'webpack',
+ 'ionic.config.json': 'ionic',
+ '.io-config.json': 'ionic',
+ 'gulpfile.js': 'gulp',
+ 'gulpfile.ts': 'gulp',
+ 'gulpfile.babel.js': 'gulp',
+ 'package.json': 'nodejs',
+ 'package-lock.json': 'nodejs',
+ '.nvmrc': 'nodejs',
+ '.npmignore': 'npm',
+ '.npmrc': 'npm',
+ '.yarnrc': 'yarn',
+ 'yarn.lock': 'yarn',
+ '.yarnclean': 'yarn',
+ '.yarn-integrity': 'yarn',
+ 'yarn-error.log': 'yarn',
+ 'androidmanifest.xml': 'android',
+ '.env': 'tune',
+ '.env.example': 'tune',
+ '.babelrc': 'babel',
+ 'contributing.md': 'contributing',
+ 'contributing.md.rendered': 'contributing',
+ 'readme.md': 'readme',
+ 'readme.md.rendered': 'readme',
+ changelog: 'changelog',
+ 'changelog.md': 'changelog',
+ 'changelog.md.rendered': 'changelog',
+ CREDITS: 'credits',
+ 'credits.txt': 'credits',
+ 'credits.md': 'credits',
+ 'credits.md.rendered': 'credits',
+ '.flowconfig': 'flow',
+ 'favicon.ico': 'favicon',
+ 'karma.conf.js': 'karma',
+ 'karma.conf.ts': 'karma',
+ 'karma.conf.coffee': 'karma',
+ 'karma.config.js': 'karma',
+ 'karma.config.ts': 'karma',
+ 'karma-main.js': 'karma',
+ 'karma-main.ts': 'karma',
+ '.bithoundrc': 'bithound',
+ 'appveyor.yml': 'appveyor',
+ '.travis.yml': 'travis',
+ 'protractor.conf.js': 'protractor',
+ 'protractor.conf.ts': 'protractor',
+ 'protractor.conf.coffee': 'protractor',
+ 'protractor.config.js': 'protractor',
+ 'protractor.config.ts': 'protractor',
+ 'fuse.js': 'fusebox',
+ procfile: 'heroku',
+ '.editorconfig': 'editorconfig',
+ '.gitlab-ci.yml': 'gitlab',
+ '.bowerrc': 'bower',
+ 'bower.json': 'bower',
+ '.eslintrc.js': 'eslint',
+ '.eslintrc.yaml': 'eslint',
+ '.eslintrc.yml': 'eslint',
+ '.eslintrc.json': 'eslint',
+ '.eslintrc': 'eslint',
+ '.eslintignore': 'eslint',
+ 'code_of_conduct.md': 'conduct',
+ 'code_of_conduct.md.rendered': 'conduct',
+ '.watchmanconfig': 'watchman',
+ 'aurelia.json': 'aurelia',
+ 'mocha.opts': 'mocha',
+ jenkinsfile: 'jenkins',
+ 'firebase.json': 'firebase',
+ '.firebaserc': 'firebase',
+ 'rollup.config.js': 'rollup',
+ 'rollup.config.ts': 'rollup',
+ 'rollup-config.js': 'rollup',
+ 'rollup-config.ts': 'rollup',
+ 'rollup.config.prod.js': 'rollup',
+ 'rollup.config.prod.ts': 'rollup',
+ 'rollup.config.dev.js': 'rollup',
+ 'rollup.config.dev.ts': 'rollup',
+ 'rollup.config.prod.vendor.js': 'rollup',
+ 'rollup.config.prod.vendor.ts': 'rollup',
+ '.hhconfig': 'hack',
+ '.stylelintrc': 'stylelint',
+ 'stylelint.config.js': 'stylelint',
+ '.stylelintrc.json': 'stylelint',
+ '.stylelintrc.yaml': 'stylelint',
+ '.stylelintrc.yml': 'stylelint',
+ '.stylelintrc.js': 'stylelint',
+ '.stylelintignore': 'stylelint',
+ '.codeclimate.yml': 'code-climate',
+ '.prettierrc': 'prettier',
+ 'prettier.config.js': 'prettier',
+ '.prettierrc.js': 'prettier',
+ '.prettierrc.json': 'prettier',
+ '.prettierrc.yaml': 'prettier',
+ '.prettierrc.yml': 'prettier',
+ 'nodemon.json': 'nodemon',
+ '.sonarrc': 'sonar',
+ browserslist: 'browserlist',
+ '.browserslistrc': 'browserlist',
+ '.snyk': 'snyk',
+ '.drone.yml': 'drone',
+};
+
+export default function getIconForFile(name) {
+ return fileNameIcons[name] ||
+ fileExtensionIcons[name ? name.split('.').pop() : ''] ||
+ '';
+}
diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss
index da3c2d7fa5d..51cc1729d9a 100644
--- a/app/assets/stylesheets/pages/repo.scss
+++ b/app/assets/stylesheets/pages/repo.scss
@@ -96,8 +96,14 @@
padding: 6px 12px;
}
-.multi-file-table-name {
+table.table tr td.multi-file-table-name {
width: 350px;
+ padding: 6px 12px;
+
+ svg {
+ vertical-align: middle;
+ margin-right: 2px;
+ }
}
.multi-file-table-col-commit-message {
@@ -132,6 +138,10 @@
border-bottom: 1px solid $white-dark;
cursor: pointer;
+ svg {
+ vertical-align: middle;
+ }
+
&.active {
background-color: $white-light;
border-bottom-color: $white-light;
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index c6a83f21ceb..c5522ff7a69 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -30,6 +30,13 @@ module IconsHelper
ActionController::Base.helpers.image_path('icons.svg', host: sprite_base_url)
end
+ def sprite_file_icons_path
+ # SVG Sprites currently don't work across domains, so in the case of a CDN
+ # we have to set the current path deliberately to prevent addition of asset_host
+ sprite_base_url = Gitlab.config.gitlab.url if ActionController::Base.asset_host
+ ActionController::Base.helpers.image_path('file_icons.svg', host: sprite_base_url)
+ end
+
def sprite_icon(icon_name, size: nil, css_class: nil)
css_classes = size ? "s#{size}" : ""
css_classes << " #{css_class}" unless css_class.blank?
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index dfcdfc307b6..9148d7571f2 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -21,6 +21,7 @@ module Gitlab
gon.revision = Gitlab::REVISION
gon.gitlab_logo = ActionController::Base.helpers.asset_path('gitlab_logo.png')
gon.sprite_icons = IconsHelper.sprite_icon_path
+ gon.sprite_file_icons = IconsHelper.sprite_file_icons_path
if current_user
gon.current_user_id = current_user.id
diff --git a/spec/javascripts/repo/components/repo_file_spec.js b/spec/javascripts/repo/components/repo_file_spec.js
index e8b370f97b4..0810da87e80 100644
--- a/spec/javascripts/repo/components/repo_file_spec.js
+++ b/spec/javascripts/repo/components/repo_file_spec.js
@@ -32,13 +32,9 @@ describe('RepoFile', () => {
vm.$mount();
const name = vm.$el.querySelector('.repo-file-name');
- const fileIcon = vm.$el.querySelector('.file-icon');
- expect(vm.$el.querySelector(`.${vm.file.icon}`).style.marginLeft).toEqual('0px');
expect(name.href).toMatch('');
expect(name.textContent.trim()).toEqual(vm.file.name);
- expect(fileIcon.classList.contains(vm.file.icon)).toBeTruthy();
- expect(fileIcon.style.marginLeft).toEqual(`${vm.file.level * 10}px`);
});
it('does render if hasFiles is true and is loading tree', () => {
@@ -49,17 +45,6 @@ describe('RepoFile', () => {
expect(vm.$el.querySelector('.fa-spin.fa-spinner')).toBeFalsy();
});
- it('renders a spinner if the file is loading', () => {
- const f = file();
- f.loading = true;
- vm = createComponent({
- file: f,
- });
-
- expect(vm.$el.querySelector('.fa-spin.fa-spinner')).not.toBeNull();
- expect(vm.$el.querySelector('.fa-spin.fa-spinner').style.marginLeft).toEqual(`${vm.file.level * 16}px`);
- });
-
it('does not render commit message and datetime if mini', (done) => {
vm = createComponent({
file: file(),
diff --git a/spec/javascripts/vue_shared/components/file_icon_spec.js b/spec/javascripts/vue_shared/components/file_icon_spec.js
new file mode 100644
index 00000000000..d99b17bdc79
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/file_icon_spec.js
@@ -0,0 +1,83 @@
+import Vue from 'vue';
+import fileIcon from '~/vue_shared/components/file_icon.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('File Icon component', () => {
+ let vm;
+ let FileIcon;
+
+ beforeEach(() => {
+ FileIcon = Vue.extend(fileIcon);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should render a span element with an svg', () => {
+ vm = mountComponent(FileIcon, {
+ fileName: 'test.js',
+ });
+
+ expect(vm.$el.tagName).toEqual('SPAN');
+ expect(vm.$el.querySelector('span > svg')).toBeDefined();
+ });
+
+ it('should render a javascript icon based on file ending', () => {
+ vm = mountComponent(FileIcon, {
+ fileName: 'test.js',
+ });
+
+ expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_file_icons}#javascript`);
+ });
+
+ it('should render a image icon based on file ending', () => {
+ vm = mountComponent(FileIcon, {
+ fileName: 'test.png',
+ });
+
+ expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_file_icons}#image`);
+ });
+
+ it('should render a webpack icon based on file namer', () => {
+ vm = mountComponent(FileIcon, {
+ fileName: 'webpack.js',
+ });
+
+ expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_file_icons}#webpack`);
+ });
+
+ it('should render a standard folder icon', () => {
+ vm = mountComponent(FileIcon, {
+ fileName: 'js',
+ folder: true,
+ });
+
+ expect(vm.$el.querySelector('span > svg > use').getAttribute('xlink:href')).toBe(`${gon.sprite_file_icons}#folder`);
+ });
+
+ it('should render a loading icon', () => {
+ vm = mountComponent(FileIcon, {
+ fileName: 'test.js',
+ loading: true,
+ });
+
+ expect(
+ vm.$el.querySelector('i').getAttribute('class'),
+ ).toEqual('fa fa-spin fa-spinner fa-1x');
+ });
+
+ it('should add a special class and a size class', () => {
+ vm = mountComponent(FileIcon, {
+ fileName: 'test.js',
+ cssClasses: 'extraclasses',
+ size: 120,
+ });
+
+ const classList = vm.$el.firstChild.classList;
+ const containsSizeClass = classList.contains('s120');
+ const containsCustomClass = classList.contains('extraclasses');
+ expect(containsSizeClass).toBe(true);
+ expect(containsCustomClass).toBe(true);
+ });
+});
--
cgit v1.2.1
From 8cf0ea4469290815daa1d64c4f3e16cbba8c00c1 Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Fri, 22 Dec 2017 16:58:05 +0100
Subject: Handle Gitaly aborted merge due to branch update
---
lib/gitlab/gitaly_client/operation_service.rb | 1 +
spec/lib/gitlab/git/repository_spec.rb | 14 ++++++++++++++
2 files changed, 15 insertions(+)
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index c7732764880..ae1753ff0ae 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -101,6 +101,7 @@ module Gitlab
request_enum.push(Gitaly::UserMergeBranchRequest.new(apply: true))
branch_update = response_enum.next.branch_update
+ return if branch_update.nil?
raise Gitlab::Git::CommitError.new('failed to apply merge to branch') unless branch_update.commit_id.present?
Gitlab::Git::OperationService::BranchUpdate.from_gitaly(branch_update)
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 0e4292026df..c8ed0494f68 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1719,6 +1719,20 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(result.repo_created).to eq(false)
expect(result.branch_created).to eq(false)
end
+
+ it 'returns nil if there was a concurrent branch update' do
+ concurrent_update_id = '33f3729a45c02fc67d00adb1b8bca394b0e761d9'
+ result = repository.merge(user, source_sha, target_branch, 'Test merge') do
+ # This ref update should make the merge fail
+ repository.write_ref(Gitlab::Git::BRANCH_REF_PREFIX + target_branch, concurrent_update_id)
+ end
+
+ # This 'nil' signals that the merge was not applied
+ expect(result).to be_nil
+
+ # Our concurrent ref update should not have been reversed
+ expect(repository.find_branch(target_branch).target).to eq(concurrent_update_id)
+ end
end
context 'with gitaly' do
--
cgit v1.2.1
From 78d22fb20db14c90861318b9f316466fbf002114 Mon Sep 17 00:00:00 2001
From: Yorick Peterse
Date: Thu, 21 Dec 2017 16:44:07 +0100
Subject: Use a background migration for issues.closed_at
In a previous attempt (rolled back in
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/16021) we tried
to migrate `issues.closed_at` from timestamp to timestamptz using a
regular migration. This has a bad impact on GitLab.com and as such was
rolled back.
This commit re-implements the original migrations using generic
background migrations, allowing us to still migrate the data in a single
release but without a negative impact on availability.
To ensure the database schema is up to date the background migrations
are performed inline in development and test environments. We also make
sure to not migrate that that doesn't need migrating in the first place
or has already been migrated.
---
...hange-issues-closed-at-background-migration.yml | 5 +
...140220_schedule_issues_closed_at_type_change.rb | 45 ++++++++
db/schema.rb | 2 +-
doc/development/what_requires_downtime.md | 57 ++++++++++
.../cleanup_concurrent_type_change.rb | 54 +++++++++
lib/gitlab/background_migration/copy_column.rb | 39 +++++++
lib/gitlab/database/migration_helpers.rb | 121 +++++++++++++++++++--
spec/lib/gitlab/database/migration_helpers_spec.rb | 91 +++++++++++++++-
8 files changed, 402 insertions(+), 12 deletions(-)
create mode 100644 changelogs/unreleased/change-issues-closed-at-background-migration.yml
create mode 100644 db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb
create mode 100644 lib/gitlab/background_migration/cleanup_concurrent_type_change.rb
create mode 100644 lib/gitlab/background_migration/copy_column.rb
diff --git a/changelogs/unreleased/change-issues-closed-at-background-migration.yml b/changelogs/unreleased/change-issues-closed-at-background-migration.yml
new file mode 100644
index 00000000000..1c81c6a889e
--- /dev/null
+++ b/changelogs/unreleased/change-issues-closed-at-background-migration.yml
@@ -0,0 +1,5 @@
+---
+title: Use a background migration for issues.closed_at
+merge_request:
+author:
+type: other
diff --git a/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb
new file mode 100644
index 00000000000..be18c5866ae
--- /dev/null
+++ b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb
@@ -0,0 +1,45 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class ScheduleIssuesClosedAtTypeChange < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class Issue < ActiveRecord::Base
+ self.table_name = 'issues'
+ include EachBatch
+
+ def self.to_migrate
+ where('closed_at IS NOT NULL')
+ end
+ end
+
+ def up
+ return unless migrate_column_type?
+
+ change_column_type_using_background_migration(
+ Issue.to_migrate,
+ :closed_at,
+ :datetime_with_timezone
+ )
+ end
+
+ def down
+ return if migrate_column_type?
+
+ change_column_type_using_background_migration(
+ Issue.to_migrate,
+ :closed_at,
+ :datetime
+ )
+ end
+
+ def migrate_column_type?
+ # Some environments may have already executed the previous version of this
+ # migration, thus we don't need to migrate those environments again.
+ column_for('issues', 'closed_at').type == :datetime
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 42715d5e1e8..cd1f5d12fef 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20171220191323) do
+ActiveRecord::Schema.define(version: 20171221140220) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
diff --git a/doc/development/what_requires_downtime.md b/doc/development/what_requires_downtime.md
index 05e0a64af18..9d0c62ecc35 100644
--- a/doc/development/what_requires_downtime.md
+++ b/doc/development/what_requires_downtime.md
@@ -195,6 +195,63 @@ end
And that's it, we're done!
+## Changing Column Types For Large Tables
+
+While `change_column_type_concurrently` can be used for changing the type of a
+column without downtime it doesn't work very well for large tables. Because all
+of the work happens in sequence the migration can take a very long time to
+complete, preventing a deployment from proceeding.
+`change_column_type_concurrently` can also produce a lot of pressure on the
+database due to it rapidly updating many rows in sequence.
+
+To reduce database pressure you should instead use
+`change_column_type_using_background_migration` when migrating a column in a
+large table (e.g. `issues`). This method works similar to
+`change_column_type_concurrently` but uses background migration to spread the
+work / load over a longer time period, without slowing down deployments.
+
+Usage of this method is fairly simple:
+
+```ruby
+class ExampleMigration < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ class Issue < ActiveRecord::Base
+ self.table_name = 'issues'
+
+ include EachBatch
+
+ def self.to_migrate
+ where('closed_at IS NOT NULL')
+ end
+ end
+
+ def up
+ change_column_type_using_background_migration(
+ Issue.to_migrate,
+ :closed_at,
+ :datetime_with_timezone
+ )
+ end
+
+ def down
+ change_column_type_using_background_migration(
+ Issue.to_migrate,
+ :closed_at,
+ :datetime
+ )
+ end
+end
+```
+
+This would change the type of `issues.closed_at` to `timestamp with time zone`.
+
+Keep in mind that the relation passed to
+`change_column_type_using_background_migration` _must_ include `EachBatch`,
+otherwise it will raise a `TypeError`.
+
## Adding Indexes
Adding indexes is an expensive process that blocks INSERT and UPDATE queries for
diff --git a/lib/gitlab/background_migration/cleanup_concurrent_type_change.rb b/lib/gitlab/background_migration/cleanup_concurrent_type_change.rb
new file mode 100644
index 00000000000..de622f657b2
--- /dev/null
+++ b/lib/gitlab/background_migration/cleanup_concurrent_type_change.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Background migration for cleaning up a concurrent column rename.
+ class CleanupConcurrentTypeChange
+ include Database::MigrationHelpers
+
+ RESCHEDULE_DELAY = 10.minutes
+
+ # table - The name of the table the migration is performed for.
+ # old_column - The name of the old (to drop) column.
+ # new_column - The name of the new column.
+ def perform(table, old_column, new_column)
+ return unless column_exists?(:issues, new_column)
+
+ rows_to_migrate = define_model_for(table)
+ .where(new_column => nil)
+ .where
+ .not(old_column => nil)
+
+ if rows_to_migrate.any?
+ BackgroundMigrationWorker.perform_in(
+ RESCHEDULE_DELAY,
+ 'CleanupConcurrentTypeChange',
+ [table, old_column, new_column]
+ )
+ else
+ cleanup_concurrent_column_type_change(table, old_column)
+ end
+ end
+
+ # These methods are necessary so we can re-use the migration helpers in
+ # this class.
+ def connection
+ ActiveRecord::Base.connection
+ end
+
+ def method_missing(name, *args, &block)
+ connection.__send__(name, *args, &block) # rubocop: disable GitlabSecurity/PublicSend
+ end
+
+ def respond_to_missing?(*args)
+ connection.respond_to?(*args) || super
+ end
+
+ def define_model_for(table)
+ Class.new(ActiveRecord::Base) do
+ self.table_name = table
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/copy_column.rb b/lib/gitlab/background_migration/copy_column.rb
new file mode 100644
index 00000000000..a2cb215c230
--- /dev/null
+++ b/lib/gitlab/background_migration/copy_column.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # CopyColumn is a simple (reusable) background migration that can be used to
+ # update the value of a column based on the value of another column in the
+ # same table.
+ #
+ # For this background migration to work the table that is migrated _has_ to
+ # have an `id` column as the primary key.
+ class CopyColumn
+ # table - The name of the table that contains the columns.
+ # copy_from - The column containing the data to copy.
+ # copy_to - The column to copy the data to.
+ # start_id - The start ID of the range of rows to update.
+ # end_id - The end ID of the range of rows to update.
+ def perform(table, copy_from, copy_to, start_id, end_id)
+ return unless connection.column_exists?(table, copy_to)
+
+ quoted_table = connection.quote_table_name(table)
+ quoted_copy_from = connection.quote_column_name(copy_from)
+ quoted_copy_to = connection.quote_column_name(copy_to)
+
+ # We're using raw SQL here since this job may be frequently executed. As
+ # a result dynamically defining models would lead to many unnecessary
+ # schema information queries.
+ connection.execute <<-SQL.strip_heredoc
+ UPDATE #{quoted_table}
+ SET #{quoted_copy_to} = #{quoted_copy_from}
+ WHERE id BETWEEN #{start_id} AND #{end_id}
+ SQL
+ end
+
+ def connection
+ ActiveRecord::Base.connection
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 3f65bc912de..33171f83692 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -385,10 +385,27 @@ module Gitlab
# necessary since we copy over old values further down.
change_column_default(table, new, old_col.default) if old_col.default
- trigger_name = rename_trigger_name(table, old, new)
+ install_rename_triggers(table, old, new)
+
+ update_column_in_batches(table, new, Arel::Table.new(table)[old])
+
+ change_column_null(table, new, false) unless old_col.null
+
+ copy_indexes(table, old, new)
+ copy_foreign_keys(table, old, new)
+ end
+
+ # Installs triggers in a table that keep a new column in sync with an old
+ # one.
+ #
+ # table - The name of the table to install the trigger in.
+ # old_column - The name of the old column.
+ # new_column - The name of the new column.
+ def install_rename_triggers(table, old_column, new_column)
+ trigger_name = rename_trigger_name(table, old_column, new_column)
quoted_table = quote_table_name(table)
- quoted_old = quote_column_name(old)
- quoted_new = quote_column_name(new)
+ quoted_old = quote_column_name(old_column)
+ quoted_new = quote_column_name(new_column)
if Database.postgresql?
install_rename_triggers_for_postgresql(trigger_name, quoted_table,
@@ -397,13 +414,6 @@ module Gitlab
install_rename_triggers_for_mysql(trigger_name, quoted_table,
quoted_old, quoted_new)
end
-
- update_column_in_batches(table, new, Arel::Table.new(table)[old])
-
- change_column_null(table, new, false) unless old_col.null
-
- copy_indexes(table, old, new)
- copy_foreign_keys(table, old, new)
end
# Changes the type of a column concurrently.
@@ -455,6 +465,97 @@ module Gitlab
remove_column(table, old)
end
+ # Changes the column type of a table using a background migration.
+ #
+ # Because this method uses a background migration it's more suitable for
+ # large tables. For small tables it's better to use
+ # `change_column_type_concurrently` since it can complete its work in a
+ # much shorter amount of time and doesn't rely on Sidekiq.
+ #
+ # Example usage:
+ #
+ # class Issue < ActiveRecord::Base
+ # self.table_name = 'issues'
+ #
+ # include EachBatch
+ #
+ # def self.to_migrate
+ # where('closed_at IS NOT NULL')
+ # end
+ # end
+ #
+ # change_column_type_using_background_migration(
+ # Issue.to_migrate,
+ # :closed_at,
+ # :datetime_with_timezone
+ # )
+ #
+ # Reverting a migration like this is done exactly the same way, just with
+ # a different type to migrate to (e.g. `:datetime` in the above example).
+ #
+ # relation - An ActiveRecord relation to use for scheduling jobs and
+ # figuring out what table we're modifying. This relation _must_
+ # have the EachBatch module included.
+ #
+ # column - The name of the column for which the type will be changed.
+ #
+ # new_type - The new type of the column.
+ #
+ # batch_size - The number of rows to schedule in a single background
+ # migration.
+ #
+ # interval - The time interval between every background migration.
+ def change_column_type_using_background_migration(
+ relation,
+ column,
+ new_type,
+ batch_size: 10_000,
+ interval: 10.minutes
+ )
+ unless relation.model < EachBatch
+ raise TypeError, 'The relation must include the EachBatch module'
+ end
+
+ temp_column = "#{column}_for_type_change"
+ table = relation.table_name
+ max_index = 0
+
+ add_column(table, temp_column, new_type)
+ install_rename_triggers(table, column, temp_column)
+
+ # Schedule the jobs that will copy the data from the old column to the
+ # new one.
+ relation.each_batch(of: batch_size) do |batch, index|
+ start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
+ max_index = index
+
+ BackgroundMigrationWorker.perform_in(
+ index * interval,
+ 'CopyColumn',
+ [table, column, temp_column, start_id, end_id]
+ )
+ end
+
+ # Schedule the renaming of the column to happen (initially) 1 hour after
+ # the last batch finished.
+ BackgroundMigrationWorker.perform_in(
+ (max_index * interval) + 1.hour,
+ 'CleanupConcurrentTypeChange',
+ [table, column, temp_column]
+ )
+
+ if perform_background_migration_inline?
+ # To ensure the schema is up to date immediately we perform the
+ # migration inline in dev / test environments.
+ Gitlab::BackgroundMigration.steal('CopyColumn')
+ Gitlab::BackgroundMigration.steal('CleanupConcurrentTypeChange')
+ end
+ end
+
+ def perform_background_migration_inline?
+ Rails.env.test? || Rails.env.development?
+ end
+
# Performs a concurrent column rename when using PostgreSQL.
def install_rename_triggers_for_postgresql(trigger, table, old, new)
execute <<-EOF.strip_heredoc
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 664ba0f7234..7727a1d81b1 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -902,7 +902,7 @@ describe Gitlab::Database::MigrationHelpers do
describe '#check_trigger_permissions!' do
it 'does nothing when the user has the correct permissions' do
expect { model.check_trigger_permissions!('users') }
- .not_to raise_error(RuntimeError)
+ .not_to raise_error
end
it 'raises RuntimeError when the user does not have the correct permissions' do
@@ -1036,4 +1036,93 @@ describe Gitlab::Database::MigrationHelpers do
end
end
end
+
+ describe '#change_column_type_using_background_migration' do
+ let!(:issue) { create(:issue) }
+
+ let(:issue_model) do
+ Class.new(ActiveRecord::Base) do
+ self.table_name = 'issues'
+ include EachBatch
+ end
+ end
+
+ it 'changes the type of a column using a background migration' do
+ expect(model)
+ .to receive(:add_column)
+ .with('issues', 'closed_at_for_type_change', :datetime_with_timezone)
+
+ expect(model)
+ .to receive(:install_rename_triggers)
+ .with('issues', :closed_at, 'closed_at_for_type_change')
+
+ expect(BackgroundMigrationWorker)
+ .to receive(:perform_in)
+ .ordered
+ .with(
+ 10.minutes,
+ 'CopyColumn',
+ ['issues', :closed_at, 'closed_at_for_type_change', issue.id, issue.id]
+ )
+
+ expect(BackgroundMigrationWorker)
+ .to receive(:perform_in)
+ .ordered
+ .with(
+ 1.hour + 10.minutes,
+ 'CleanupConcurrentTypeChange',
+ ['issues', :closed_at, 'closed_at_for_type_change']
+ )
+
+ expect(Gitlab::BackgroundMigration)
+ .to receive(:steal)
+ .ordered
+ .with('CopyColumn')
+
+ expect(Gitlab::BackgroundMigration)
+ .to receive(:steal)
+ .ordered
+ .with('CleanupConcurrentTypeChange')
+
+ model.change_column_type_using_background_migration(
+ issue_model.all,
+ :closed_at,
+ :datetime_with_timezone
+ )
+ end
+ end
+
+ describe '#perform_background_migration_inline?' do
+ it 'returns true in a test environment' do
+ allow(Rails.env)
+ .to receive(:test?)
+ .and_return(true)
+
+ expect(model.perform_background_migration_inline?).to eq(true)
+ end
+
+ it 'returns true in a development environment' do
+ allow(Rails.env)
+ .to receive(:test?)
+ .and_return(false)
+
+ allow(Rails.env)
+ .to receive(:development?)
+ .and_return(true)
+
+ expect(model.perform_background_migration_inline?).to eq(true)
+ end
+
+ it 'returns false in a production environment' do
+ allow(Rails.env)
+ .to receive(:test?)
+ .and_return(false)
+
+ allow(Rails.env)
+ .to receive(:development?)
+ .and_return(false)
+
+ expect(model.perform_background_migration_inline?).to eq(false)
+ end
+ end
end
--
cgit v1.2.1
From 8d8550c78ba0b7d6ac4a26b77b9b2def203d4eec Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Wed, 3 Jan 2018 12:44:57 +0100
Subject: Fix method lookup
---
lib/gitlab/gitaly_client/conflicts_service.rb | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb
index 1e631e4bd3d..40f032cf873 100644
--- a/lib/gitlab/gitaly_client/conflicts_service.rb
+++ b/lib/gitlab/gitaly_client/conflicts_service.rb
@@ -1,6 +1,8 @@
module Gitlab
module GitalyClient
class ConflictsService
+ include Gitlab::EncodingHelper
+
MAX_MSG_SIZE = 128.kilobytes.freeze
def initialize(repository, our_commit_oid, their_commit_oid)
@@ -22,7 +24,7 @@ module Gitlab
end
def resolve_conflicts(target_repository, resolution, source_branch, target_branch)
- reader = GitalyClient.binary_stringio(resolution.files.to_json)
+ reader = binary_stringio(resolution.files.to_json)
req_enum = Enumerator.new do |y|
header = resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch)
--
cgit v1.2.1
From ce09dc31827e36fa0bd26c939a81bdb710e1fb93 Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Wed, 3 Jan 2018 12:44:57 +0100
Subject: Fix method lookup
---
lib/gitlab/gitaly_client/conflicts_service.rb | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb
index 1e631e4bd3d..40f032cf873 100644
--- a/lib/gitlab/gitaly_client/conflicts_service.rb
+++ b/lib/gitlab/gitaly_client/conflicts_service.rb
@@ -1,6 +1,8 @@
module Gitlab
module GitalyClient
class ConflictsService
+ include Gitlab::EncodingHelper
+
MAX_MSG_SIZE = 128.kilobytes.freeze
def initialize(repository, our_commit_oid, their_commit_oid)
@@ -22,7 +24,7 @@ module Gitlab
end
def resolve_conflicts(target_repository, resolution, source_branch, target_branch)
- reader = GitalyClient.binary_stringio(resolution.files.to_json)
+ reader = binary_stringio(resolution.files.to_json)
req_enum = Enumerator.new do |y|
header = resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch)
--
cgit v1.2.1
From 449b59ec69f7da2be9e75fdaf282592f048b9853 Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Wed, 3 Jan 2018 12:54:47 +0100
Subject: Better English
---
spec/lib/gitlab/git/repository_spec.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index c8ed0494f68..21379ae0f45 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1730,7 +1730,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
# This 'nil' signals that the merge was not applied
expect(result).to be_nil
- # Our concurrent ref update should not have been reversed
+ # Our concurrent ref update should not have been undone
expect(repository.find_branch(target_branch).target).to eq(concurrent_update_id)
end
end
--
cgit v1.2.1
From 6c8daa6827353564dac45f495b5953cb3b4b273b Mon Sep 17 00:00:00 2001
From: James Ramsay
Date: Wed, 3 Jan 2018 08:46:06 -0500
Subject: Remove superfluous i18n namespaces
---
app/views/projects/compare/_form.html.haml | 8 ++++----
app/views/projects/compare/index.html.haml | 4 ++--
app/views/projects/compare/show.html.haml | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index ebeeeff5e76..d0c8a699608 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -9,7 +9,7 @@
= s_("CompareBranches|Source")
= hidden_field_tag :to, params[:to]
= button_tag type: 'button', title: params[:to], class: "form-control compare-dropdown-toggle js-compare-dropdown has-tooltip git-revision-dropdown-toggle", required: true, data: { refs_url: refs_project_path(@project), toggle: "dropdown", target: ".js-compare-to-dropdown", selected: params[:to], field_name: :to } do
- .dropdown-toggle-text.str-truncated= params[:to] || s_("CompareBranches|Select branch/tag")
+ .dropdown-toggle-text.str-truncated= params[:to] || _("Select branch/tag")
= render 'shared/ref_dropdown'
.compare-ellipsis.inline ...
.form-group.dropdown.compare-form-group.from.js-compare-from-dropdown
@@ -18,11 +18,11 @@
= s_("CompareBranches|Target")
= hidden_field_tag :from, params[:from]
= button_tag type: 'button', title: params[:from], class: "form-control compare-dropdown-toggle js-compare-dropdown has-tooltip git-revision-dropdown-toggle", required: true, data: { refs_url: refs_project_path(@project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from], field_name: :from } do
- .dropdown-toggle-text.str-truncated= params[:from] || s_("CompareBranches|Select branch/tag")
+ .dropdown-toggle-text.str-truncated= params[:from] || _("Select branch/tag")
= render 'shared/ref_dropdown'
= button_tag s_("CompareBranches|Compare"), class: "btn btn-create commits-compare-btn"
- if @merge_request.present?
- = link_to s_("CompareBranches|View open merge request"), project_merge_request_path(@project, @merge_request), class: 'prepend-left-10 btn'
+ = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'prepend-left-10 btn'
- elsif create_mr_button?
- = link_to s_("CompareBranches|Create merge request"), create_mr_path, class: 'prepend-left-10 btn'
+ = link_to _("Create merge request"), create_mr_path, class: 'prepend-left-10 btn'
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index b3b9aa55b7c..9b0095f5f0f 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -10,9 +10,9 @@
%code.ref-name master
- example_sha = capture_haml do
%code.ref-name 4eedf23
- = (s_("CompareBranches|Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to what's changed or to create a merge request.") % { master: example_master, sha: example_sha }).html_safe
+ = (_("Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request.") % { master: example_master, sha: example_sha }).html_safe
%br
- = (s_("ComparBranches|Changes are shown as if the source revision was being merged into the target revision.")).html_safe
+ = (_("Changes are shown as if the source revision was being merged into the target revision.")).html_safe
.prepend-top-20
= render "form"
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index b892d4d8ba5..0939b2a3b07 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -22,4 +22,4 @@
%span.ref-name= params[:to]
= (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: sourceBranch, target_branch: targetBranch }).html_safe
- else
- = s_("CompareBranches|You'll need to use different branch names to get a valid comparison.")
+ = _("You'll need to use different branch names to get a valid comparison.")
--
cgit v1.2.1
From 5e0143a84bca7fd8b2dccd175e0f50c87dea4b98 Mon Sep 17 00:00:00 2001
From: Alessio Caiazza
Date: Sat, 27 May 2017 15:23:27 +0200
Subject: Add online attribute to runner api entity
---
.../unreleased/feature-api_runners_online.yml | 4 +++
doc/api/runners.md | 29 +++++++++++++++-------
lib/api/entities.rb | 1 +
3 files changed, 25 insertions(+), 9 deletions(-)
create mode 100644 changelogs/unreleased/feature-api_runners_online.yml
diff --git a/changelogs/unreleased/feature-api_runners_online.yml b/changelogs/unreleased/feature-api_runners_online.yml
new file mode 100644
index 00000000000..f5077507e5b
--- /dev/null
+++ b/changelogs/unreleased/feature-api_runners_online.yml
@@ -0,0 +1,4 @@
+---
+title: Add online attribute to runner api entity
+merge_request: 11750
+author: Alessio Caiazza
diff --git a/doc/api/runners.md b/doc/api/runners.md
index 015b09a745e..50981ed96bc 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -30,14 +30,16 @@ Example response:
"description": "test-1-20150125",
"id": 6,
"is_shared": false,
- "name": null
+ "name": null,
+ "online": true
},
{
"active": true,
"description": "test-2-20150125",
"id": 8,
"is_shared": false,
- "name": null
+ "name": null,
+ "online": false
}
]
```
@@ -69,28 +71,32 @@ Example response:
"description": "shared-runner-1",
"id": 1,
"is_shared": true,
- "name": null
+ "name": null,
+ "online": true
},
{
"active": true,
"description": "shared-runner-2",
"id": 3,
"is_shared": true,
- "name": null
+ "name": null,
+ "online": false
},
{
"active": true,
"description": "test-1-20150125",
"id": 6,
"is_shared": false,
- "name": null
+ "name": null,
+ "online": true
},
{
"active": true,
"description": "test-2-20150125",
"id": 8,
"is_shared": false,
- "name": null
+ "name": null,
+ "online": false
}
]
```
@@ -122,6 +128,7 @@ Example response:
"is_shared": false,
"contacted_at": "2016-01-25T16:39:48.066Z",
"name": null,
+ "online": true,
"platform": null,
"projects": [
{
@@ -176,6 +183,7 @@ Example response:
"is_shared": false,
"contacted_at": "2016-01-25T16:39:48.066Z",
"name": null,
+ "online": true,
"platform": null,
"projects": [
{
@@ -327,14 +335,16 @@ Example response:
"description": "test-2-20150125",
"id": 8,
"is_shared": false,
- "name": null
+ "name": null,
+ "online": false
},
{
"active": true,
"description": "development_runner",
"id": 5,
"is_shared": true,
- "name": null
+ "name": null,
+ "online": true
}
]
```
@@ -364,7 +374,8 @@ Example response:
"description": "test-2016-02-01",
"id": 9,
"is_shared": false,
- "name": null
+ "name": null,
+ "online": true
}
```
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 4ad4a1f7867..c612dde7f73 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -862,6 +862,7 @@ module API
expose :active
expose :is_shared
expose :name
+ expose :online?, as: :online
end
class RunnerDetails < Runner
--
cgit v1.2.1
From 87a437995e4bec0c9b84c1ae2833cf7186709911 Mon Sep 17 00:00:00 2001
From: Oswaldo Ferreira
Date: Wed, 3 Jan 2018 11:57:07 -0200
Subject: Simplify metrics fetching for closed/merged MRs
---
app/serializers/merge_request_widget_entity.rb | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 83ea36adcc1..e905e6876c2 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -187,12 +187,11 @@ class MergeRequestWidgetEntity < IssuableEntity
def build_metrics(merge_request)
# There's no need to query and serialize metrics data for merge requests that are not
# merged or closed.
- case merge_request.state
- when 'merged'
- merge_request.metrics&.merged_by_id ? merge_request.metrics : build_metrics_from_events(merge_request)
- when 'closed'
- merge_request.metrics&.latest_closed_by_id ? merge_request.metrics : build_metrics_from_events(merge_request)
- end
+ return unless merge_request.merged? || merge_request.closed?
+ return merge_request.metrics if merge_request.merged? && merge_request.metrics&.merged_by_id
+ return merge_request.metrics if merge_request.closed? && merge_request.metrics&.latest_closed_by_id
+
+ build_metrics_from_events(merge_request)
end
def build_metrics_from_events(merge_request)
--
cgit v1.2.1
From e24e0c90a30c37917555baa0bfa0849458ce93d5 Mon Sep 17 00:00:00 2001
From: Lin Jen-Shin
Date: Tue, 2 Jan 2018 22:40:07 +0800
Subject: Use heredoc for long strings so it's easier to read
---
qa/qa/runtime/user.rb | 14 +++++------
spec/factories/keys.rb | 63 ++++++++++++++++++++++++++++----------------------
2 files changed, 43 insertions(+), 34 deletions(-)
diff --git a/qa/qa/runtime/user.rb b/qa/qa/runtime/user.rb
index 7bd50023561..2832439d9e0 100644
--- a/qa/qa/runtime/user.rb
+++ b/qa/qa/runtime/user.rb
@@ -12,13 +12,13 @@ module QA
end
def ssh_key
- <<~KEY.tr("\n", '')
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O9
- 6x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5
- /jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7
- M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaC
- rzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy0
- 5qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz= dummy@gitlab.com
+ <<~KEY.delete("\n")
+ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O9
+ 6x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5
+ /jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7
+ M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaC
+ rzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy0
+ 5qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz= dummy@gitlab.com
KEY
end
end
diff --git a/spec/factories/keys.rb b/spec/factories/keys.rb
index e6eb76f71d3..552b4b7e06e 100644
--- a/spec/factories/keys.rb
+++ b/spec/factories/keys.rb
@@ -21,12 +21,14 @@ FactoryBot.define do
factory :rsa_key_2048 do
key do
- 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O9' \
- '6x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5' \
- '/jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7' \
- 'M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaC' \
- 'rzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy0' \
- '5qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz= dummy@gitlab.com'
+ <<~KEY.delete("\n")
+ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O9
+ 6x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5
+ /jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7
+ M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaC
+ rzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy0
+ 5qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz= dummy@gitlab.com
+ KEY
end
factory :rsa_deploy_key_2048, class: 'DeployKey'
@@ -34,37 +36,44 @@ FactoryBot.define do
factory :dsa_key_2048 do
key do
- 'ssh-dss AAAAB3NzaC1kc3MAAAEBAO/3/NPLA/zSFkMOCaTtGo+uos1flfQ5f038Uk+G' \
- 'Y9AeLGzX+Srhw59GdVXmOQLYBrOt5HdGwqYcmLnE2VurUGmhtfeO5H+3p5pGJbkS0Gxp' \
- 'YH1HRO9lWsncF3Hh1w4lYsDjkclDiSTdfTuN8F4Kb3DXNnVSCieeonp+B25F/CXagyTQ' \
- '/pvNmHFeYgGCVdnBtFdi+xfxaZ8NKdPrGggzokbKHElDZQ4Xo5EpdcyLajgM7nB2r2Rz' \
- 'OrmeaevKi5lV68ehRa9Yyrb7vxvwiwBwOgqR/mnN7Gnaq1jUdmJY+ct04Qwx37f5jvhv' \
- '5gA4U40SGMoiHM8RFIN7Ksz0jsyX73MAAAAVALRWOfjfzHpK7KLz4iqDvvTUAevJAAAB' \
- 'AEa9NZ+6y9iQ5erGsdfLTXFrhSefTG0NhghoO/5IFkSGfd8V7kzTvCHaFrcfpEA5kP8t' \
- 'poeOG0TASB6tgGOxm1Bq4Wncry5RORBPJlAVpDGRcvZ931ddH7IgltEInS6za2uH6F/1' \
- 'M1QfKePSLr6xJ1ZLYfP0Og5KTp1x6yMQvfwV0a+XdA+EPgaJWLWp/pWwKWa0oLUgjsIH' \
- 'MYzuOGh5c708uZrmkzqvgtW2NgXhcIroRgynT3IfI2lP2rqqb3uuuE/qH5UCUFO+Dc3H' \
- 'nAFNeQDT/M25AERdPYBAY5a+iPjIgO+jT7BfmfByT+AZTqZySrCyc7nNZL3YgGLK0l6A' \
- '1GgAAAEBAN9FpFOdIXE+YEZhKl1vPmbcn+b1y5zOl6N4x1B7Q8pD/pLMziWROIS8uLzb' \
- 'aZ0sMIWezHIkxuo1iROMeT+jtCubn7ragaN6AX7nMpxYUH9+mYZZs/fyElt6wCviVhTI' \
- 'zM+u7VdQsnZttOOlQfogHdL+SpeAft0DsfJjlcgQnsLlHQKv6aPqCPYUST2nE7RyW/Ex' \
- 'PrMxLtOWt0/j8RYHbwwqvyeZqBz3ESBgrS9c5tBdBfauwYUV/E7gPLOU3OZFw9ue7o+z' \
- 'wzoTZqW6Xouy5wtWvSLQSLT5XwOslmQz8QMBxD0AQyDfEFGsBCWzmbTgKv9uqrBjubsS' \
- 'Taja+Cf9kMo== dummy@gitlab.com'
+ <<~KEY.delete("\n")
+ ssh-dss AAAAB3NzaC1kc3MAAAEBAO/3/NPLA/zSFkMOCaTtGo+uos1flfQ5f038Uk+G
+ Y9AeLGzX+Srhw59GdVXmOQLYBrOt5HdGwqYcmLnE2VurUGmhtfeO5H+3p5pGJbkS0Gxp
+ YH1HRO9lWsncF3Hh1w4lYsDjkclDiSTdfTuN8F4Kb3DXNnVSCieeonp+B25F/CXagyTQ
+ /pvNmHFeYgGCVdnBtFdi+xfxaZ8NKdPrGggzokbKHElDZQ4Xo5EpdcyLajgM7nB2r2Rz
+ OrmeaevKi5lV68ehRa9Yyrb7vxvwiwBwOgqR/mnN7Gnaq1jUdmJY+ct04Qwx37f5jvhv
+ 5gA4U40SGMoiHM8RFIN7Ksz0jsyX73MAAAAVALRWOfjfzHpK7KLz4iqDvvTUAevJAAAB
+ AEa9NZ+6y9iQ5erGsdfLTXFrhSefTG0NhghoO/5IFkSGfd8V7kzTvCHaFrcfpEA5kP8t
+ poeOG0TASB6tgGOxm1Bq4Wncry5RORBPJlAVpDGRcvZ931ddH7IgltEInS6za2uH6F/1
+ M1QfKePSLr6xJ1ZLYfP0Og5KTp1x6yMQvfwV0a+XdA+EPgaJWLWp/pWwKWa0oLUgjsIH
+ MYzuOGh5c708uZrmkzqvgtW2NgXhcIroRgynT3IfI2lP2rqqb3uuuE/qH5UCUFO+Dc3H
+ nAFNeQDT/M25AERdPYBAY5a+iPjIgO+jT7BfmfByT+AZTqZySrCyc7nNZL3YgGLK0l6A
+ 1GgAAAEBAN9FpFOdIXE+YEZhKl1vPmbcn+b1y5zOl6N4x1B7Q8pD/pLMziWROIS8uLzb
+ aZ0sMIWezHIkxuo1iROMeT+jtCubn7ragaN6AX7nMpxYUH9+mYZZs/fyElt6wCviVhTI
+ zM+u7VdQsnZttOOlQfogHdL+SpeAft0DsfJjlcgQnsLlHQKv6aPqCPYUST2nE7RyW/Ex
+ PrMxLtOWt0/j8RYHbwwqvyeZqBz3ESBgrS9c5tBdBfauwYUV/E7gPLOU3OZFw9ue7o+z
+ wzoTZqW6Xouy5wtWvSLQSLT5XwOslmQz8QMBxD0AQyDfEFGsBCWzmbTgKv9uqrBjubsS
+ Taja+Cf9kMo== dummy@gitlab.com
+ KEY
end
end
factory :ecdsa_key_256 do
key do
- 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYA' \
- 'AABBBJZmkzTgY0fiCQ+DVReyH/fFwTFz0XoR3RUO0u+199H19KFw7mNPxRSMOVS7tEtO' \
- 'Nj3Q7FcZXfqthHvgAzDiHsc= dummy@gitlab.com'
+ <<~KEY.delete("\n")
+ ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYA
+ AABBBJZmkzTgY0fiCQ+DVReyH/fFwTFz0XoR3RUO0u+199H19KFw7mNPxRSMOVS7tEtO
+ Nj3Q7FcZXfqthHvgAzDiHsc= dummy@gitlab.com
+ KEY
end
end
factory :ed25519_key_256 do
key do
- 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIETnVTgzqC1gatgSlC4zH6aYt2CAQzgJOhDRvf59ohL6 dummy@gitlab.com'
+ <<~KEY.delete("\n")
+ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIETnVTgzqC1gatgSlC4zH6aYt2CAQzgJ
+ OhDRvf59ohL6 dummy@gitlab.com
+ KEY
end
end
end
--
cgit v1.2.1
From 86257cf7138a6d28c055071219142722787b6546 Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Wed, 3 Jan 2018 16:17:16 +0100
Subject: refactor project create service
---
app/models/project.rb | 2 +-
app/services/projects/create_service.rb | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/models/project.rb b/app/models/project.rb
index e37eae9f176..6ebb083aeb4 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -639,7 +639,7 @@ class Project < ActiveRecord::Base
end
def import?
- external_import? || forked? || gitlab_project_import?
+ external_import? || forked? || gitlab_project_import? || bare_repository_import?
end
def no_import?
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 52b90cdf135..dc7b1f1f5cc 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -120,7 +120,7 @@ module Projects
Project.transaction do
@project.create_or_update_import_data(data: import_data[:data], credentials: import_data[:credentials]) if import_data
- if @project.save && !@project.import? && !@project.bare_repository_import?
+ if @project.save && !@project.import?
raise 'Failed to create repository' unless @project.create_repository
end
end
@@ -165,7 +165,7 @@ module Projects
def import_schedule
if @project.errors.empty?
- @project.import_schedule if @project.import?
+ @project.import_schedule if @project.import? && !@project.bare_repository_import?
else
fail(error: @project.errors.full_messages.join(', '))
end
--
cgit v1.2.1
From 274bde5d8bbf17f1cbc71ff6a38d45d6fe606245 Mon Sep 17 00:00:00 2001
From: James Ramsay
Date: Wed, 3 Jan 2018 10:32:03 -0500
Subject: Fix incorrect case of ruby vars
---
app/views/projects/compare/show.html.haml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 0939b2a3b07..0d59d800d1e 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -16,10 +16,10 @@
= s_("CompareBranches|There isn't anything to compare.")
%p.slead
- if params[:to] == params[:from]
- - sourceBranch = capture_haml do
+ - source_branch = capture_haml do
%span.ref-name= params[:from]
- - targetBranch = capture_haml do
+ - target_branch = capture_haml do
%span.ref-name= params[:to]
- = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: sourceBranch, target_branch: targetBranch }).html_safe
+ = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: source_branch, target_branch: target_branch }).html_safe
- else
= _("You'll need to use different branch names to get a valid comparison.")
--
cgit v1.2.1
From 592e81503abee7087dca0c4994a9dbeff5bf6945 Mon Sep 17 00:00:00 2001
From: James Ramsay
Date: Wed, 3 Jan 2018 10:32:46 -0500
Subject: Add changelog entry
---
changelogs/unreleased/jramsay-4012-i18n-compare.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 changelogs/unreleased/jramsay-4012-i18n-compare.yml
diff --git a/changelogs/unreleased/jramsay-4012-i18n-compare.yml b/changelogs/unreleased/jramsay-4012-i18n-compare.yml
new file mode 100644
index 00000000000..ff15724be39
--- /dev/null
+++ b/changelogs/unreleased/jramsay-4012-i18n-compare.yml
@@ -0,0 +1,5 @@
+---
+title: Add i18n helpers to branch comparison view
+merge_request: 16031
+author: James Ramsay
+type: added
--
cgit v1.2.1
From 0d6b9e30cb5c3b76ee97cd14dea1dae12a74e8d6 Mon Sep 17 00:00:00 2001
From: Jose Ivan Vargas
Date: Fri, 22 Dec 2017 12:25:24 -0600
Subject: Fix import project url not updating project name
---
app/assets/javascripts/projects/project_new.js | 7 +++--
.../unreleased/jivl-fix-import-project-url-bug.yml | 5 ++++
spec/javascripts/projects/project_new_spec.js | 32 ++++++++++++----------
3 files changed, 27 insertions(+), 17 deletions(-)
create mode 100644 changelogs/unreleased/jivl-fix-import-project-url-bug.yml
diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js
index 3ecc0c2a6e5..4710e70d619 100644
--- a/app/assets/javascripts/projects/project_new.js
+++ b/app/assets/javascripts/projects/project_new.js
@@ -1,6 +1,7 @@
let hasUserDefinedProjectPath = false;
-const deriveProjectPathFromUrl = ($projectImportUrl, $projectPath) => {
+const deriveProjectPathFromUrl = ($projectImportUrl) => {
+ const $currentProjectPath = $projectImportUrl.parents('.toggle-import-form').find('#project_path');
if (hasUserDefinedProjectPath) {
return;
}
@@ -21,7 +22,7 @@ const deriveProjectPathFromUrl = ($projectImportUrl, $projectPath) => {
// extract everything after the last slash
const pathMatch = /\/([^/]+)$/.exec(importUrl);
if (pathMatch) {
- $projectPath.val(pathMatch[1]);
+ $currentProjectPath.val(pathMatch[1]);
}
};
@@ -96,7 +97,7 @@ const bindEvents = () => {
hasUserDefinedProjectPath = $projectPath.val().trim().length > 0;
});
- $projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl, $projectPath));
+ $projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl));
};
document.addEventListener('DOMContentLoaded', bindEvents);
diff --git a/changelogs/unreleased/jivl-fix-import-project-url-bug.yml b/changelogs/unreleased/jivl-fix-import-project-url-bug.yml
new file mode 100644
index 00000000000..0d97b9c9a53
--- /dev/null
+++ b/changelogs/unreleased/jivl-fix-import-project-url-bug.yml
@@ -0,0 +1,5 @@
+---
+title: Fix import project url not updating project name
+merge_request: 16120
+author:
+type: fixed
diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js
index 850768f0e4f..c314ca8ab72 100644
--- a/spec/javascripts/projects/project_new_spec.js
+++ b/spec/javascripts/projects/project_new_spec.js
@@ -6,8 +6,12 @@ describe('New Project', () => {
beforeEach(() => {
setFixtures(`
-
-
+
+
+
+
+
+
`);
$projectImportUrl = $('#project_import_url');
@@ -25,7 +29,7 @@ describe('New Project', () => {
it('does not change project path for disabled $projectImportUrl', () => {
$projectImportUrl.attr('disabled', true);
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual(dummyImportUrl);
});
@@ -38,7 +42,7 @@ describe('New Project', () => {
it('does not change project path if it is set by user', () => {
$projectPath.keyup();
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual(dummyImportUrl);
});
@@ -46,7 +50,7 @@ describe('New Project', () => {
it('does not change project path for empty $projectImportUrl', () => {
$projectImportUrl.val('');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual(dummyImportUrl);
});
@@ -54,7 +58,7 @@ describe('New Project', () => {
it('does not change project path for whitespace $projectImportUrl', () => {
$projectImportUrl.val(' ');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual(dummyImportUrl);
});
@@ -62,7 +66,7 @@ describe('New Project', () => {
it('does not change project path for $projectImportUrl without slashes', () => {
$projectImportUrl.val('has-no-slash');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual(dummyImportUrl);
});
@@ -70,7 +74,7 @@ describe('New Project', () => {
it('changes project path to last $projectImportUrl component', () => {
$projectImportUrl.val('/this/is/last');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual('last');
});
@@ -78,7 +82,7 @@ describe('New Project', () => {
it('ignores trailing slashes in $projectImportUrl', () => {
$projectImportUrl.val('/has/trailing/slash/');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual('slash');
});
@@ -86,7 +90,7 @@ describe('New Project', () => {
it('ignores fragment identifier in $projectImportUrl', () => {
$projectImportUrl.val('/this/has/a#fragment-identifier/');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual('a');
});
@@ -94,7 +98,7 @@ describe('New Project', () => {
it('ignores query string in $projectImportUrl', () => {
$projectImportUrl.val('/url/with?query=string');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual('with');
});
@@ -102,7 +106,7 @@ describe('New Project', () => {
it('ignores trailing .git in $projectImportUrl', () => {
$projectImportUrl.val('/repository.git');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual('repository');
});
@@ -110,7 +114,7 @@ describe('New Project', () => {
it('changes project path for HTTPS URL in $projectImportUrl', () => {
$projectImportUrl.val('https://username:password@gitlab.company.com/group/project.git');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual('project');
});
@@ -118,7 +122,7 @@ describe('New Project', () => {
it('changes project path for SSH URL in $projectImportUrl', () => {
$projectImportUrl.val('git@gitlab.com:gitlab-org/gitlab-ce.git');
- projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath);
+ projectNew.deriveProjectPathFromUrl($projectImportUrl);
expect($projectPath.val()).toEqual('gitlab-ce');
});
--
cgit v1.2.1
From 7c721e7bba4359b60f20090d850c672d06023072 Mon Sep 17 00:00:00 2001
From: James Ramsay
Date: Wed, 3 Jan 2018 11:43:01 -0500
Subject: Replace use of capture_haml with capture
---
app/views/projects/compare/index.html.haml | 4 ++--
app/views/projects/compare/show.html.haml | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index 9b0095f5f0f..14c64b3534a 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -6,9 +6,9 @@
%h3.page-title
= _("Compare Git revisions")
.sub-header-block
- - example_master = capture_haml do
+ - example_master = capture do
%code.ref-name master
- - example_sha = capture_haml do
+ - example_sha = capture do
%code.ref-name 4eedf23
= (_("Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request.") % { master: example_master, sha: example_sha }).html_safe
%br
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 0d59d800d1e..8da55664878 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -16,9 +16,9 @@
= s_("CompareBranches|There isn't anything to compare.")
%p.slead
- if params[:to] == params[:from]
- - source_branch = capture_haml do
+ - source_branch = capture do
%span.ref-name= params[:from]
- - target_branch = capture_haml do
+ - target_branch = capture do
%span.ref-name= params[:to]
= (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: source_branch, target_branch: target_branch }).html_safe
- else
--
cgit v1.2.1
From 9504a529b758b0352b9c60d67fda8b4ee2a5fec0 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Tue, 19 Dec 2017 14:36:33 -0200
Subject: Write project full path to .git/config when creating projects
We'd need to keep track of project full path otherwise directory tree created with hashed storage enabled cannot be usefully imported using the import rake task.
---
app/models/project.rb | 5 +++++
app/services/projects/create_service.rb | 5 +++++
spec/services/projects/create_service_spec.rb | 6 ++++++
3 files changed, 16 insertions(+)
diff --git a/app/models/project.rb b/app/models/project.rb
index 6ebb083aeb4..eac78de1ac9 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1432,6 +1432,11 @@ class Project < ActiveRecord::Base
Gitlab::PagesTransfer.new.rename_project(path_before_change, self.path, namespace.full_path)
end
+ def write_repository_config(key, value, prefix: :gitlab)
+ key = [prefix, key].compact.join('.')
+ repo.config[key] = value
+ end
+
def rename_repo_notify!
send_move_instructions(full_path_was)
expires_full_path_cache
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index dc7b1f1f5cc..4c7e5370bbe 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -87,6 +87,11 @@ module Projects
def after_create_actions
log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
+ # We'd need to keep track of project full path otherwise directory tree
+ # created with hashed storage enabled cannot be usefully imported using
+ # the import rake task.
+ @project.write_repository_config(:fullpath, @project.full_path)
+
unless @project.gitlab_project_import?
@project.create_wiki unless skip_wiki?
create_services_from_active_templates(@project)
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index dc89fdebce7..1833078f37c 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -252,6 +252,12 @@ describe Projects::CreateService, '#execute' do
end
end
+ it 'writes project full path to .git/config' do
+ project = create_project(user, opts)
+
+ expect(project.repo.config['gitlab.fullpath']).to eq project.full_path
+ end
+
def create_project(user, opts)
Projects::CreateService.new(user, opts).execute
end
--
cgit v1.2.1
From 64fe954dcebaadd6f686f30eb4ff0be5ebcf172d Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Tue, 19 Dec 2017 14:53:59 -0200
Subject: Update project full path in .git/config when renaming a repository
---
app/models/project.rb | 5 +++++
spec/models/project_spec.rb | 14 ++++++++++++++
spec/services/projects/update_service_spec.rb | 2 +-
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/app/models/project.rb b/app/models/project.rb
index eac78de1ac9..1182dbda0c0 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1420,6 +1420,11 @@ class Project < ActiveRecord::Base
end
def after_rename_repo
+ # We'd need to keep track of project full path otherwise directory tree
+ # created with hashed storage enabled cannot be usefully imported using
+ # the import rake task.
+ write_repository_config(:fullpath, full_path)
+
path_before_change = previous_changes['path'].first
# We need to check if project had been rolled out to move resource to hashed storage or not and decide
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 7338e341359..10634d22b39 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2626,6 +2626,14 @@ describe Project do
project.rename_repo
end
end
+
+ it 'updates project full path in .git/config' do
+ allow(project_storage).to receive(:rename_repo).and_return(true)
+
+ expect(project).to receive(:write_repository_config).with(:fullpath, project.full_path)
+
+ project.rename_repo
+ end
end
describe '#pages_path' do
@@ -2781,6 +2789,12 @@ describe Project do
end
end
end
+
+ it 'updates project full path in .git/config' do
+ expect(project).to receive(:write_repository_config).with(:fullpath, project.full_path)
+
+ project.rename_repo
+ end
end
describe '#pages_path' do
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index d887f70efae..fc6aa713d6f 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -61,7 +61,7 @@ describe Projects::UpdateService do
end
end
- context 'When project visibility is higher than parent group' do
+ context 'when project visibility is higher than parent group' do
let(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::INTERNAL) }
before do
--
cgit v1.2.1
From bd90330740e0ea5c0ce0672fd605a463fcdfc898 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Tue, 19 Dec 2017 17:18:26 -0200
Subject: Update project full path in .git/config when transfering a project
---
app/services/projects/transfer_service.rb | 10 ++++++++++
spec/services/projects/transfer_service_spec.rb | 12 ++++++++++++
2 files changed, 22 insertions(+)
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index e5cd6fcdfe3..e742df5f696 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -75,6 +75,8 @@ module Projects
project.old_path_with_namespace = @old_path
project.expires_full_path_cache
+ write_repository_config(@new_path)
+
execute_system_hooks
end
rescue Exception # rubocop:disable Lint/RescueException
@@ -98,6 +100,13 @@ module Projects
project.save!
end
+ def write_repository_config(full_path)
+ # We'd need to keep track of project full path otherwise directory tree
+ # created with hashed storage enabled cannot be usefully imported using
+ # the import rake task.
+ project.write_repository_config(:fullpath, full_path)
+ end
+
def refresh_permissions
# This ensures we only schedule 1 job for every user that has access to
# the namespaces.
@@ -110,6 +119,7 @@ module Projects
def rollback_side_effects
rollback_folder_move
update_namespace_and_visibility(@old_namespace)
+ write_repository_config(@old_path)
end
def rollback_folder_move
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 2b1337bee7e..7377c748698 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -54,6 +54,12 @@ describe Projects::TransferService do
expect(project.disk_path).not_to eq(old_path)
expect(project.disk_path).to start_with(group.path)
end
+
+ it 'updates project full path in .git/config' do
+ transfer_project(project, user, group)
+
+ expect(project.repo.config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}"
+ end
end
context 'when transfer fails' do
@@ -86,6 +92,12 @@ describe Projects::TransferService do
expect(original_path).to eq current_path
end
+ it 'rolls back project full path in .git/config' do
+ attempt_project_transfer
+
+ expect(project.repo.config['gitlab.fullpath']).to eq project.full_path
+ end
+
it "doesn't send move notifications" do
expect_any_instance_of(NotificationService).not_to receive(:project_was_moved)
--
cgit v1.2.1
From ca089f59687fb8616bcbd3d5501fbc6006893e8f Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Tue, 19 Dec 2017 17:42:51 -0200
Subject: Update project full path in .git/config when renaming namespace
---
app/models/concerns/storage/legacy_namespace.rb | 2 ++
app/models/namespace.rb | 7 +++++++
spec/models/namespace_spec.rb | 14 ++++++++++++++
3 files changed, 23 insertions(+)
diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb
index b3020484738..22b9ef4e338 100644
--- a/app/models/concerns/storage/legacy_namespace.rb
+++ b/app/models/concerns/storage/legacy_namespace.rb
@@ -34,6 +34,8 @@ module Storage
# So we basically we mute exceptions in next actions
begin
send_update_instructions
+ write_projects_full_path_config
+
true
rescue
# Returning false does not rollback after_* transaction but gives
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 0ff169d4531..d983b2f106b 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -268,4 +268,11 @@ class Namespace < ActiveRecord::Base
def namespace_previously_created_with_same_path?
RedirectRoute.permanent.exists?(path: path)
end
+
+ def write_projects_full_path_config
+ all_projects.each do |project|
+ project.expires_full_path_cache # we need to clear cache to validate renames correctly
+ project.write_repository_config(:fullpath, project.full_path)
+ end
+ end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index b7c6286fd83..0a99485ec8e 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -240,6 +240,20 @@ describe Namespace do
end
end
end
+
+ it 'updates project full path in .git/config for each project inside namespace' do
+ parent = create(:group, name: 'mygroup', path: 'mygroup')
+ subgroup = create(:group, name: 'mysubgroup', path: 'mysubgroup', parent: parent)
+ project_in_parent_group = create(:project, :repository, namespace: parent, name: 'foo1')
+ hashed_project_in_subgroup = create(:project, :repository, :hashed, namespace: subgroup, name: 'foo2')
+ legacy_project_in_subgroup = create(:project, :repository, namespace: subgroup, name: 'foo3')
+
+ parent.update(path: 'mygroup_new')
+
+ expect(project_in_parent_group.repo.config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}"
+ expect(hashed_project_in_subgroup.repo.config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}"
+ expect(legacy_project_in_subgroup.repo.config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}"
+ end
end
describe '#rm_dir', 'callback' do
--
cgit v1.2.1
From 2f2233774c3d6416f5571a2e83b367d34bad3f5f Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Tue, 19 Dec 2017 18:04:48 -0200
Subject: Write project full path to .git/config when migrating legacy storage
---
.../projects/hashed_storage/migrate_repository_service.rb | 7 +++++++
.../projects/hashed_storage/migrate_repository_service_spec.rb | 8 +++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/app/services/projects/hashed_storage/migrate_repository_service.rb b/app/services/projects/hashed_storage/migrate_repository_service.rb
index 7212e7524ab..c076ce06278 100644
--- a/app/services/projects/hashed_storage/migrate_repository_service.rb
+++ b/app/services/projects/hashed_storage/migrate_repository_service.rb
@@ -39,6 +39,13 @@ module Projects
yield
end
+ # We'd need to keep track of project full path otherwise directory tree
+ # created with hashed storage enabled cannot be usefully imported using
+ # the import rake task.
+ if result
+ project.write_repository_config(:fullpath, project.full_path)
+ end
+
result
end
diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
index 3a3e47fd9c0..ded864beb1d 100644
--- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Projects::HashedStorage::MigrateRepositoryService do
let(:gitlab_shell) { Gitlab::Shell.new }
- let(:project) { create(:project, :empty_repo, :wiki_repo) }
+ let(:project) { create(:project, :repository, :wiki_repo) }
let(:service) { described_class.new(project) }
let(:legacy_storage) { Storage::LegacyProject.new(project) }
let(:hashed_storage) { Storage::HashedProject.new(project) }
@@ -33,6 +33,12 @@ describe Projects::HashedStorage::MigrateRepositoryService do
service.execute
end
+
+ it 'writes project full path to .git/config' do
+ service.execute
+
+ expect(project.repo.config['gitlab.fullpath']).to eq project.full_path
+ end
end
context 'when one move fails' do
--
cgit v1.2.1
From d3d617354e0f0da7c8930dd9c089f437603dea20 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Tue, 19 Dec 2017 19:54:04 -0200
Subject: Does not write to .git/config when importing bare repositories
---
app/services/projects/create_service.rb | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 4c7e5370bbe..24ae50f8dc4 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -87,12 +87,12 @@ module Projects
def after_create_actions
log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
- # We'd need to keep track of project full path otherwise directory tree
- # created with hashed storage enabled cannot be usefully imported using
- # the import rake task.
- @project.write_repository_config(:fullpath, @project.full_path)
-
unless @project.gitlab_project_import?
+ # We'd need to keep track of project full path otherwise directory tree
+ # created with hashed storage enabled cannot be usefully imported using
+ # the import rake task.
+ @project.write_repository_config(:fullpath, @project.full_path)
+
@project.create_wiki unless skip_wiki?
create_services_from_active_templates(@project)
--
cgit v1.2.1
From 582678b5f5e1399603610b20149acf1d305309d3 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Tue, 19 Dec 2017 23:58:54 -0200
Subject: Import directory tree created with hashed storage using import rake
task
---
lib/gitlab/bare_repository_import/importer.rb | 9 +-
lib/gitlab/bare_repository_import/repository.rb | 36 +++++--
.../gitlab/bare_repository_import/importer_spec.rb | 14 ++-
.../bare_repository_import/repository_spec.rb | 119 +++++++++++++++------
4 files changed, 129 insertions(+), 49 deletions(-)
diff --git a/lib/gitlab/bare_repository_import/importer.rb b/lib/gitlab/bare_repository_import/importer.rb
index 64e41d42709..1f0fdc6685e 100644
--- a/lib/gitlab/bare_repository_import/importer.rb
+++ b/lib/gitlab/bare_repository_import/importer.rb
@@ -14,13 +14,13 @@ module Gitlab
repos_to_import.each do |repo_path|
bare_repo = Gitlab::BareRepositoryImport::Repository.new(import_path, repo_path)
- if bare_repo.hashed? || bare_repo.wiki?
+ unless bare_repo.processable?
log " * Skipping repo #{bare_repo.repo_path}".color(:yellow)
next
end
- log "Processing #{repo_path}".color(:yellow)
+ log "Processing #{repo_path} -> #{bare_repo.project_full_path}".color(:yellow)
new(user, bare_repo).create_project_if_needed
end
@@ -62,6 +62,11 @@ module Gitlab
if project.persisted? && mv_repo(project)
log " * Created #{project.name} (#{project_full_path})".color(:green)
+ # We'd need to keep track of project full path otherwise directory tree
+ # created with hashed storage enabled cannot be usefully imported using
+ # the import rake task.
+ project.write_repository_config(:fullpath, project.full_path)
+
ProjectCacheWorker.perform_async(project.id)
else
log " * Failed trying to create #{project.name} (#{project_full_path})".color(:red)
diff --git a/lib/gitlab/bare_repository_import/repository.rb b/lib/gitlab/bare_repository_import/repository.rb
index fa7891c8dcc..b5907875460 100644
--- a/lib/gitlab/bare_repository_import/repository.rb
+++ b/lib/gitlab/bare_repository_import/repository.rb
@@ -6,39 +6,55 @@ module Gitlab
def initialize(root_path, repo_path)
@root_path = root_path
@repo_path = repo_path
-
@root_path << '/' unless root_path.ends_with?('/')
+ full_path =
+ if hashed? && !wiki?
+ repository.config.get('gitlab.fullpath')
+ else
+ repo_relative_path
+ end
+
# Split path into 'all/the/namespaces' and 'project_name'
- @group_path, _, @project_name = repo_relative_path.rpartition('/')
+ @group_path, _, @project_name = full_path.to_s.rpartition('/')
end
def wiki_exists?
File.exist?(wiki_path)
end
- def wiki?
- @wiki ||= repo_path.end_with?('.wiki.git')
- end
-
def wiki_path
@wiki_path ||= repo_path.sub(/\.git$/, '.wiki.git')
end
- def hashed?
- @hashed ||= group_path.start_with?('@hashed')
- end
-
def project_full_path
@project_full_path ||= "#{group_path}/#{project_name}"
end
+ def processable?
+ return false if wiki?
+
+ group_path.present? && project_name.present?
+ end
+
private
+ def wiki?
+ @wiki ||= repo_path.end_with?('.wiki.git')
+ end
+
+ def hashed?
+ @hashed ||= repo_relative_path.include?('@hashed')
+ end
+
def repo_relative_path
# Remove root path and `.git` at the end
repo_path[@root_path.size...-4]
end
+
+ def repository
+ @repository ||= Rugged::Repository.new(repo_path)
+ end
end
end
end
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index 82ac3c424d4..99cc9c4bd41 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -1,6 +1,7 @@
require 'spec_helper'
describe Gitlab::BareRepositoryImport::Importer, repository: true do
+ let(:gitlab_shell) { Gitlab::Shell.new }
let!(:admin) { create(:admin) }
let!(:base_dir) { Dir.mktmpdir + '/' }
let(:bare_repository) { Gitlab::BareRepositoryImport::Repository.new(base_dir, File.join(base_dir, "#{project_path}.git")) }
@@ -75,7 +76,7 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
end
it 'creates the Git repo in disk' do
- FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git"))
+ create_bare_repository("#{project_path}.git")
importer.create_project_if_needed
@@ -130,7 +131,7 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
end
it 'creates the Git repo in disk' do
- FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git"))
+ create_bare_repository("#{project_path}.git")
importer.create_project_if_needed
@@ -165,8 +166,8 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
it_behaves_like 'importing a repository'
it 'creates the Wiki git repo in disk' do
- FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git"))
- FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.wiki.git"))
+ create_bare_repository("#{project_path}.git")
+ create_bare_repository("#{project_path}.wiki.git")
expect(Projects::CreateService).to receive(:new).with(admin, hash_including(skip_wiki: true,
import_type: 'bare_repository')).and_call_original
@@ -192,4 +193,9 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
end
end
end
+
+ def create_bare_repository(project_path)
+ repo_path = File.join(base_dir, project_path)
+ Gitlab::Git::Repository.create(repo_path, bare: true)
+ end
end
diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
index 61b73abcba4..770e26bbf6a 100644
--- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
@@ -1,58 +1,111 @@
require 'spec_helper'
describe ::Gitlab::BareRepositoryImport::Repository do
- let(:project_repo_path) { described_class.new('/full/path/', '/full/path/to/repo.git') }
+ context 'legacy storage' do
+ subject { described_class.new('/full/path/', '/full/path/to/repo.git') }
- it 'stores the repo path' do
- expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git')
- end
+ it 'stores the repo path' do
+ expect(subject.repo_path).to eq('/full/path/to/repo.git')
+ end
- it 'stores the group path' do
- expect(project_repo_path.group_path).to eq('to')
- end
+ it 'stores the group path' do
+ expect(subject.group_path).to eq('to')
+ end
- it 'stores the project name' do
- expect(project_repo_path.project_name).to eq('repo')
- end
+ it 'stores the project name' do
+ expect(subject.project_name).to eq('repo')
+ end
- it 'stores the wiki path' do
- expect(project_repo_path.wiki_path).to eq('/full/path/to/repo.wiki.git')
- end
+ it 'stores the wiki path' do
+ expect(subject.wiki_path).to eq('/full/path/to/repo.wiki.git')
+ end
+
+ describe '#processable?' do
+ it 'returns false if it is a wiki' do
+ subject = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git')
- describe '#wiki?' do
- it 'returns true if it is a wiki' do
- wiki_path = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git')
+ expect(subject.processable?).to eq(false)
+ end
- expect(wiki_path.wiki?).to eq(true)
+ it 'returns true when group and project name are present' do
+ expect(subject.processable?).to eq(true)
+ end
end
- it 'returns false if it is not a wiki' do
- expect(project_repo_path.wiki?).to eq(false)
+ describe '#project_full_path' do
+ it 'returns the project full path' do
+ expect(subject.repo_path).to eq('/full/path/to/repo.git')
+ expect(subject.project_full_path).to eq('to/repo')
+ end
+
+ it 'with no trailing slash in the root path' do
+ repo_path = described_class.new('/full/path', '/full/path/to/repo.git')
+
+ expect(repo_path.project_full_path).to eq('to/repo')
+ end
end
end
- describe '#hashed?' do
- it 'returns true if it is a hashed folder' do
- path = described_class.new('/full/path/', '/full/path/@hashed/my.repo.git')
+ context 'hashed storage' do
+ let(:gitlab_shell) { Gitlab::Shell.new }
+ let(:repository_storage) { 'default' }
+ let(:root_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
+ let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
+ let(:hashed_path) { "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" }
+ let(:repo_path) { File.join(root_path, "#{hashed_path}.git") }
+ let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") }
- expect(path.hashed?).to eq(true)
+ before do
+ gitlab_shell.add_repository(repository_storage, hashed_path)
+ repository = Rugged::Repository.new(repo_path)
+ repository.config['gitlab.fullpath'] = 'to/repo'
end
- it 'returns false if it is not a hashed folder' do
- expect(project_repo_path.hashed?).to eq(false)
+ after do
+ gitlab_shell.remove_repository(root_path, hashed_path)
end
- end
- describe '#project_full_path' do
- it 'returns the project full path' do
- expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git')
- expect(project_repo_path.project_full_path).to eq('to/repo')
+ subject { described_class.new(root_path, repo_path) }
+
+ it 'stores the repo path' do
+ expect(subject.repo_path).to eq(repo_path)
+ end
+
+ it 'stores the wiki path' do
+ expect(subject.wiki_path).to eq(wiki_path)
+ end
+
+ it 'reads the group path from .git/config' do
+ expect(subject.group_path).to eq('to')
+ end
+
+ it 'reads the project name from .git/config' do
+ expect(subject.project_name).to eq('repo')
end
- it 'with no trailing slash in the root path' do
- repo_path = described_class.new('/full/path', '/full/path/to/repo.git')
+ describe '#processable?' do
+ it 'returns false if it is a wiki' do
+ subject = described_class.new(root_path, wiki_path)
+
+ expect(subject.processable?).to eq(false)
+ end
+
+ it 'returns false when group and project name are missing' do
+ repository = Rugged::Repository.new(repo_path)
+ repository.config.delete('gitlab.fullpath')
+
+ expect(subject.processable?).to eq(false)
+ end
+
+ it 'returns true when group and project name are present' do
+ expect(subject.processable?).to eq(true)
+ end
+ end
- expect(repo_path.project_full_path).to eq('to/repo')
+ describe '#project_full_path' do
+ it 'returns the project full path' do
+ expect(subject.project_full_path).to eq('to/repo')
+ end
end
end
end
--
cgit v1.2.1
From c328a7db75b601bed449ad04100e12779f5bdb36 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Wed, 20 Dec 2017 14:22:13 -0200
Subject: Handle exceptions when writing to .git/config
---
app/models/project.rb | 3 +++
1 file changed, 3 insertions(+)
diff --git a/app/models/project.rb b/app/models/project.rb
index 1182dbda0c0..47ca62aa5bb 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1440,6 +1440,9 @@ class Project < ActiveRecord::Base
def write_repository_config(key, value, prefix: :gitlab)
key = [prefix, key].compact.join('.')
repo.config[key] = value
+ rescue Gitlab::Git::Repository::NoRepository => e
+ Rails.logger.error("Error writing key #{key} to .git/config for project #{full_path} (#{id}): #{e.message}.")
+ nil
end
def rename_repo_notify!
--
cgit v1.2.1
From 603fcb6b9ca0aec1a5f8d75fa16d626dd8058269 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Wed, 20 Dec 2017 15:40:59 -0200
Subject: Add CHANGELOG
---
.../da-handle-hashed-storage-repos-using-repo-import-task.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 changelogs/unreleased/da-handle-hashed-storage-repos-using-repo-import-task.yml
diff --git a/changelogs/unreleased/da-handle-hashed-storage-repos-using-repo-import-task.yml b/changelogs/unreleased/da-handle-hashed-storage-repos-using-repo-import-task.yml
new file mode 100644
index 00000000000..74a00d49ab3
--- /dev/null
+++ b/changelogs/unreleased/da-handle-hashed-storage-repos-using-repo-import-task.yml
@@ -0,0 +1,5 @@
+---
+title: Handle GitLab hashed storage repositories using the repo import task
+merge_request:
+author:
+type: added
--
cgit v1.2.1
From 9d575acc5b46be7e0b76ccc763997412cd278ef0 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Tue, 19 Dec 2017 17:06:38 -0200
Subject: Fix TestEnv.copy_repo to use disk_path instead of full_path
---
spec/models/namespace_spec.rb | 2 +-
spec/models/project_spec.rb | 2 +-
spec/support/test_env.rb | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 0a99485ec8e..0678cae9b93 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -203,7 +203,7 @@ describe Namespace do
context 'with subgroups' do
let(:parent) { create(:group, name: 'parent', path: 'parent') }
let(:child) { create(:group, name: 'child', path: 'child', parent: parent) }
- let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child) }
+ let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child, skip_disk_validation: true) }
let(:uploads_dir) { File.join(CarrierWave.root, FileUploader.base_dir) }
let(:pages_dir) { File.join(TestEnv.pages_path) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 10634d22b39..62029f385a2 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2676,7 +2676,7 @@ describe Project do
end
context 'hashed storage' do
- let(:project) { create(:project, :repository) }
+ let(:project) { create(:project, :repository, skip_disk_validation: true) }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index ffc051a3fff..1d99746b09f 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -215,7 +215,7 @@ module TestEnv
end
def copy_repo(project, bare_repo:, refs:)
- target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.full_path}.git")
+ target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.disk_path}.git")
FileUtils.mkdir_p(target_repo_path)
FileUtils.cp_r("#{File.expand_path(bare_repo)}/.", target_repo_path)
FileUtils.chmod_R 0755, target_repo_path
--
cgit v1.2.1
From 93eba91df9af083ea80b3b8ab01986efdeec43a0 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Thu, 21 Dec 2017 13:58:36 -0200
Subject: Refactoring Project#write_repository_config
---
app/models/namespace.rb | 2 +-
app/models/project.rb | 15 +++++++--------
app/services/projects/create_service.rb | 6 +-----
.../hashed_storage/migrate_repository_service.rb | 9 ++-------
app/services/projects/transfer_service.rb | 5 +----
lib/gitlab/bare_repository_import/importer.rb | 7 ++-----
spec/models/project_spec.rb | 22 +++++++++++-----------
7 files changed, 25 insertions(+), 41 deletions(-)
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index d983b2f106b..efbfc607040 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -272,7 +272,7 @@ class Namespace < ActiveRecord::Base
def write_projects_full_path_config
all_projects.each do |project|
project.expires_full_path_cache # we need to clear cache to validate renames correctly
- project.write_repository_config(:fullpath, project.full_path)
+ project.write_repository_config
end
end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 47ca62aa5bb..9c0bbf697e2 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1420,10 +1420,7 @@ class Project < ActiveRecord::Base
end
def after_rename_repo
- # We'd need to keep track of project full path otherwise directory tree
- # created with hashed storage enabled cannot be usefully imported using
- # the import rake task.
- write_repository_config(:fullpath, full_path)
+ write_repository_config
path_before_change = previous_changes['path'].first
@@ -1437,11 +1434,13 @@ class Project < ActiveRecord::Base
Gitlab::PagesTransfer.new.rename_project(path_before_change, self.path, namespace.full_path)
end
- def write_repository_config(key, value, prefix: :gitlab)
- key = [prefix, key].compact.join('.')
- repo.config[key] = value
+ def write_repository_config(gl_full_path: full_path)
+ # We'd need to keep track of project full path otherwise directory tree
+ # created with hashed storage enabled cannot be usefully imported using
+ # the import rake task.
+ repo.config['gitlab.fullpath'] = gl_full_path
rescue Gitlab::Git::Repository::NoRepository => e
- Rails.logger.error("Error writing key #{key} to .git/config for project #{full_path} (#{id}): #{e.message}.")
+ Rails.logger.error("Error writing to .git/config for project #{full_path} (#{id}): #{e.message}.")
nil
end
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 24ae50f8dc4..01838ec6b5d 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -88,11 +88,7 @@ module Projects
log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
unless @project.gitlab_project_import?
- # We'd need to keep track of project full path otherwise directory tree
- # created with hashed storage enabled cannot be usefully imported using
- # the import rake task.
- @project.write_repository_config(:fullpath, @project.full_path)
-
+ @project.write_repository_config
@project.create_wiki unless skip_wiki?
create_services_from_active_templates(@project)
diff --git a/app/services/projects/hashed_storage/migrate_repository_service.rb b/app/services/projects/hashed_storage/migrate_repository_service.rb
index c076ce06278..b6763c9436f 100644
--- a/app/services/projects/hashed_storage/migrate_repository_service.rb
+++ b/app/services/projects/hashed_storage/migrate_repository_service.rb
@@ -30,6 +30,8 @@ module Projects
unless result
rollback_folder_move
project.storage_version = nil
+ else
+ project.write_repository_config
end
project.repository_read_only = false
@@ -39,13 +41,6 @@ module Projects
yield
end
- # We'd need to keep track of project full path otherwise directory tree
- # created with hashed storage enabled cannot be usefully imported using
- # the import rake task.
- if result
- project.write_repository_config(:fullpath, project.full_path)
- end
-
result
end
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index e742df5f696..14cf9f82bdb 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -101,10 +101,7 @@ module Projects
end
def write_repository_config(full_path)
- # We'd need to keep track of project full path otherwise directory tree
- # created with hashed storage enabled cannot be usefully imported using
- # the import rake task.
- project.write_repository_config(:fullpath, full_path)
+ project.write_repository_config(:gl_fullpath, full_path)
end
def refresh_permissions
diff --git a/lib/gitlab/bare_repository_import/importer.rb b/lib/gitlab/bare_repository_import/importer.rb
index 1f0fdc6685e..709a901aa77 100644
--- a/lib/gitlab/bare_repository_import/importer.rb
+++ b/lib/gitlab/bare_repository_import/importer.rb
@@ -20,7 +20,7 @@ module Gitlab
next
end
- log "Processing #{repo_path} -> #{bare_repo.project_full_path}".color(:yellow)
+ log "Processing #{repo_path}".color(:yellow)
new(user, bare_repo).create_project_if_needed
end
@@ -62,10 +62,7 @@ module Gitlab
if project.persisted? && mv_repo(project)
log " * Created #{project.name} (#{project_full_path})".color(:green)
- # We'd need to keep track of project full path otherwise directory tree
- # created with hashed storage enabled cannot be usefully imported using
- # the import rake task.
- project.write_repository_config(:fullpath, project.full_path)
+ project.write_repository_config
ProjectCacheWorker.perform_async(project.id)
else
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 62029f385a2..1d4b68bdf8d 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2630,9 +2630,9 @@ describe Project do
it 'updates project full path in .git/config' do
allow(project_storage).to receive(:rename_repo).and_return(true)
- expect(project).to receive(:write_repository_config).with(:fullpath, project.full_path)
-
project.rename_repo
+
+ expect(project.repo.config['gitlab.fullpath']).to eq(project.full_path)
end
end
@@ -2678,12 +2678,10 @@ describe Project do
context 'hashed storage' do
let(:project) { create(:project, :repository, skip_disk_validation: true) }
let(:gitlab_shell) { Gitlab::Shell.new }
- let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
+ let(:hash) { Digest::SHA2.hexdigest(project.id.to_s) }
before do
stub_application_setting(hashed_storage_enabled: true)
- allow(Digest::SHA2).to receive(:hexdigest) { hash }
- allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
end
describe '#legacy_storage?' do
@@ -2706,13 +2704,13 @@ describe Project do
describe '#base_dir' do
it 'returns base_dir based on hash of project id' do
- expect(project.base_dir).to eq('@hashed/6b/86')
+ expect(project.base_dir).to eq("@hashed/#{hash[0..1]}/#{hash[2..3]}")
end
end
describe '#disk_path' do
it 'returns disk_path based on hash of project id' do
- hashed_path = '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b'
+ hashed_path = "@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}"
expect(project.disk_path).to eq(hashed_path)
end
@@ -2720,7 +2718,9 @@ describe Project do
describe '#ensure_storage_path_exists' do
it 'delegates to gitlab_shell to ensure namespace is created' do
- expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, '@hashed/6b/86')
+ allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
+
+ expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, "@hashed/#{hash[0..1]}/#{hash[2..3]}")
project.ensure_storage_path_exists
end
@@ -2780,7 +2780,7 @@ describe Project do
end
context 'when not rolled out' do
- let(:project) { create(:project, :repository, storage_version: 1) }
+ let(:project) { create(:project, :repository, storage_version: 1, skip_disk_validation: true) }
it 'moves pages folder to new location' do
expect_any_instance_of(Gitlab::UploadsTransfer).to receive(:rename_project)
@@ -2791,9 +2791,9 @@ describe Project do
end
it 'updates project full path in .git/config' do
- expect(project).to receive(:write_repository_config).with(:fullpath, project.full_path)
-
project.rename_repo
+
+ expect(project.repo.config['gitlab.fullpath']).to eq(project.full_path)
end
end
--
cgit v1.2.1
From fcb967ac672e224737f6e170693e45331eb4d636 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Thu, 21 Dec 2017 15:32:08 -0200
Subject: Write projects config to all projects inside namespace in batches
---
app/models/concerns/storage/legacy_namespace.rb | 2 +-
app/models/namespace.rb | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb
index 22b9ef4e338..99dbd4fbacf 100644
--- a/app/models/concerns/storage/legacy_namespace.rb
+++ b/app/models/concerns/storage/legacy_namespace.rb
@@ -34,7 +34,7 @@ module Storage
# So we basically we mute exceptions in next actions
begin
send_update_instructions
- write_projects_full_path_config
+ write_projects_repository_config
true
rescue
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index efbfc607040..bdcc9159d26 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -269,8 +269,8 @@ class Namespace < ActiveRecord::Base
RedirectRoute.permanent.exists?(path: path)
end
- def write_projects_full_path_config
- all_projects.each do |project|
+ def write_projects_repository_config
+ all_projects.find_each do |project|
project.expires_full_path_cache # we need to clear cache to validate renames correctly
project.write_repository_config
end
--
cgit v1.2.1
From 2af3400c4eeb0227ca6f38117323a18e9fbd7d9b Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Thu, 21 Dec 2017 16:04:58 -0200
Subject: Add spec for Project#write_repository_config
---
spec/models/project_spec.rb | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 1d4b68bdf8d..cea22bbd184 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -3155,4 +3155,26 @@ describe Project do
it { is_expected.to eq(platform_kubernetes) }
end
end
+
+ describe '#write_repository_config' do
+ set(:project) { create(:project, :repository) }
+
+ it 'writes full path in .git/config when key is missing' do
+ project.write_repository_config
+
+ expect(project.repo.config['gitlab.fullpath']).to eq project.full_path
+ end
+
+ it 'updates full path in .git/config when key is present' do
+ project.write_repository_config(gl_full_path: 'old/path')
+
+ expect { project.write_repository_config }.to change { project.repo.config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
+ end
+
+ it 'does not raise an error with an empty repository' do
+ project = create(:project_empty_repo)
+
+ expect { project.write_repository_config }.not_to raise_error
+ end
+ end
end
--
cgit v1.2.1
From 58c2f3b5796cd8349dbd90404ed6ad0ca3ee6caf Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Thu, 21 Dec 2017 16:49:32 -0200
Subject: Fix Repository#processable? to allow .git repos in the root folder
---
lib/gitlab/bare_repository_import/repository.rb | 3 ++-
spec/lib/gitlab/bare_repository_import/repository_spec.rb | 10 ++++++++--
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/lib/gitlab/bare_repository_import/repository.rb b/lib/gitlab/bare_repository_import/repository.rb
index b5907875460..85b79362196 100644
--- a/lib/gitlab/bare_repository_import/repository.rb
+++ b/lib/gitlab/bare_repository_import/repository.rb
@@ -33,8 +33,9 @@ module Gitlab
def processable?
return false if wiki?
+ return false if hashed? && (group_path.blank? || project_name.blank?)
- group_path.present? && project_name.present?
+ true
end
private
diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
index 770e26bbf6a..e0b7d16ebb7 100644
--- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
@@ -27,7 +27,13 @@ describe ::Gitlab::BareRepositoryImport::Repository do
expect(subject.processable?).to eq(false)
end
- it 'returns true when group and project name are present' do
+ it 'returns true if group path is missing' do
+ subject = described_class.new('/full/path/', '/full/path/repo.git')
+
+ expect(subject.processable?).to eq(true)
+ end
+
+ it 'returns true when group path and project name are present' do
expect(subject.processable?).to eq(true)
end
end
@@ -97,7 +103,7 @@ describe ::Gitlab::BareRepositoryImport::Repository do
expect(subject.processable?).to eq(false)
end
- it 'returns true when group and project name are present' do
+ it 'returns true when group path and project name are present' do
expect(subject.processable?).to eq(true)
end
end
--
cgit v1.2.1
From 6c95c771fb9a3c71d176aa996b82096a8e0a3f7a Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Thu, 21 Dec 2017 17:08:00 -0200
Subject: Fix Projects::TransferService#write_repository_config method
---
app/services/projects/transfer_service.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 14cf9f82bdb..26765e5c3f3 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -101,7 +101,7 @@ module Projects
end
def write_repository_config(full_path)
- project.write_repository_config(:gl_fullpath, full_path)
+ project.write_repository_config(gl_full_path: full_path)
end
def refresh_permissions
--
cgit v1.2.1
From 62ee2ccfcc1d765cf2b80ba8f7a226855f2f8a2f Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Fri, 22 Dec 2017 11:28:46 -0200
Subject: Refactoring spec for Gitlab::BareRepositoryImport::Repository
---
.../gitlab/bare_repository_import/repository_spec.rb | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
index e0b7d16ebb7..39f2cfe6175 100644
--- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
@@ -39,15 +39,14 @@ describe ::Gitlab::BareRepositoryImport::Repository do
end
describe '#project_full_path' do
- it 'returns the project full path' do
- expect(subject.repo_path).to eq('/full/path/to/repo.git')
+ it 'returns the project full path with trailing slash in the root path' do
expect(subject.project_full_path).to eq('to/repo')
end
- it 'with no trailing slash in the root path' do
- repo_path = described_class.new('/full/path', '/full/path/to/repo.git')
+ it 'returns the project full path with no trailing slash in the root path' do
+ subject = described_class.new('/full/path', '/full/path/to/repo.git')
- expect(repo_path.project_full_path).to eq('to/repo')
+ expect(subject.project_full_path).to eq('to/repo')
end
end
end
@@ -109,7 +108,13 @@ describe ::Gitlab::BareRepositoryImport::Repository do
end
describe '#project_full_path' do
- it 'returns the project full path' do
+ it 'returns the project full path with trailing slash in the root path' do
+ expect(subject.project_full_path).to eq('to/repo')
+ end
+
+ it 'returns the project full path with no trailing slash in the root path' do
+ subject = described_class.new(root_path[0...-1], repo_path)
+
expect(subject.project_full_path).to eq('to/repo')
end
end
--
cgit v1.2.1
From 3f5403ab74b2f60c1a306a2f617d1cd323854c7a Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Wed, 3 Jan 2018 16:17:11 -0200
Subject: Remove unused variable from bare repository importer spec
---
spec/lib/gitlab/bare_repository_import/importer_spec.rb | 1 -
1 file changed, 1 deletion(-)
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index 99cc9c4bd41..b5d86df09d2 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
describe Gitlab::BareRepositoryImport::Importer, repository: true do
- let(:gitlab_shell) { Gitlab::Shell.new }
let!(:admin) { create(:admin) }
let!(:base_dir) { Dir.mktmpdir + '/' }
let(:bare_repository) { Gitlab::BareRepositoryImport::Repository.new(base_dir, File.join(base_dir, "#{project_path}.git")) }
--
cgit v1.2.1
From 08de4746dc03e7f090546063711153e99de344ae Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Wed, 3 Jan 2018 16:22:00 -0200
Subject: Refactoring Gitlab::BareRepositoryImport::Repository
---
spec/lib/gitlab/bare_repository_import/repository_spec.rb | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
index 39f2cfe6175..9f42cf1dfca 100644
--- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
@@ -24,17 +24,17 @@ describe ::Gitlab::BareRepositoryImport::Repository do
it 'returns false if it is a wiki' do
subject = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git')
- expect(subject.processable?).to eq(false)
+ expect(subject).not_to be_processable
end
it 'returns true if group path is missing' do
subject = described_class.new('/full/path/', '/full/path/repo.git')
- expect(subject.processable?).to eq(true)
+ expect(subject).to be_processable
end
it 'returns true when group path and project name are present' do
- expect(subject.processable?).to eq(true)
+ expect(subject).to be_processable
end
end
@@ -92,18 +92,18 @@ describe ::Gitlab::BareRepositoryImport::Repository do
it 'returns false if it is a wiki' do
subject = described_class.new(root_path, wiki_path)
- expect(subject.processable?).to eq(false)
+ expect(subject).not_to be_processable
end
it 'returns false when group and project name are missing' do
repository = Rugged::Repository.new(repo_path)
repository.config.delete('gitlab.fullpath')
- expect(subject.processable?).to eq(false)
+ expect(subject).not_to be_processable
end
it 'returns true when group path and project name are present' do
- expect(subject.processable?).to eq(true)
+ expect(subject).to be_processable
end
end
--
cgit v1.2.1
From 540a2b67098782842cfdd98b4177a29ac3c81ebf Mon Sep 17 00:00:00 2001
From: George Tsiolis
Date: Tue, 2 Jan 2018 15:07:13 +0200
Subject: Move 2FA disable button
- Removed disable button from /profile/account
- Added disable button to /profile/two_factor_auth
- Changed 2FA breadcrumb from 'User Settings > Account > Account' to 'User Settings > Account > Two-Factor Authentication'
---
app/views/profiles/accounts/show.html.haml | 4 ----
app/views/profiles/two_factor_auths/show.html.haml | 9 +++++++--
changelogs/unreleased/fix-move-2fa-disable-button.yml | 5 +++++
spec/features/u2f_spec.rb | 2 +-
4 files changed, 13 insertions(+), 7 deletions(-)
create mode 100644 changelogs/unreleased/fix-move-2fa-disable-button.yml
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index ced58dffcdc..f1313b79589 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -17,10 +17,6 @@
Status: #{current_user.two_factor_enabled? ? 'Enabled' : 'Disabled'}
- if current_user.two_factor_enabled?
= link_to 'Manage two-factor authentication', profile_two_factor_auth_path, class: 'btn btn-info'
- = link_to 'Disable', profile_two_factor_auth_path,
- method: :delete,
- data: { confirm: "Are you sure? This will invalidate your registered applications and U2F devices." },
- class: 'btn btn-danger'
- else
.append-bottom-10
= link_to 'Enable two-factor authentication', profile_two_factor_auth_path, class: 'btn btn-success'
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index 0b03276efcc..5207dac3ac2 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -1,5 +1,5 @@
- page_title 'Two-Factor Authentication', 'Account'
-- add_to_breadcrumbs("Account", profile_account_path)
+- add_to_breadcrumbs("Two-Factor Authentication", profile_account_path)
- @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head'
@@ -18,7 +18,12 @@
Use an app on your mobile device to enable two-factor authentication (2FA).
.col-lg-8
- if current_user.two_factor_otp_enabled?
- = icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page."
+ %p
+ You've already enabled two-factor authentication using mobile authenticator applications. In order to register a different device, you must first disable two-factor authentication.
+ = link_to 'Disable two-factor authentication', profile_two_factor_auth_path,
+ method: :delete,
+ data: { confirm: "Are you sure? This will invalidate your registered applications and U2F devices." },
+ class: 'btn btn-danger'
- else
%p
Download the Google Authenticator application from App Store or Google Play Store and scan this code.
diff --git a/changelogs/unreleased/fix-move-2fa-disable-button.yml b/changelogs/unreleased/fix-move-2fa-disable-button.yml
new file mode 100644
index 00000000000..bac98ad5148
--- /dev/null
+++ b/changelogs/unreleased/fix-move-2fa-disable-button.yml
@@ -0,0 +1,5 @@
+---
+title: Move 2FA disable button
+merge_request: 16177
+author: George Tsiolis
+type: fixed
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
index c9afef2a8de..50ee1656e10 100644
--- a/spec/features/u2f_spec.rb
+++ b/spec/features/u2f_spec.rb
@@ -264,7 +264,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
end
it "deletes u2f registrations" do
- visit profile_account_path
+ visit profile_two_factor_auth_path
expect do
accept_confirm { click_on "Disable" }
end.to change { U2fRegistration.count }.by(-1)
--
cgit v1.2.1
From 14336c0bda493a870ffeed86379b274c522fe804 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Wed, 3 Jan 2018 16:26:59 -0200
Subject: Use if instead of unless on
Projects::HashedStorage::MigrateRepositoryService
---
app/services/projects/hashed_storage/migrate_repository_service.rb | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/services/projects/hashed_storage/migrate_repository_service.rb b/app/services/projects/hashed_storage/migrate_repository_service.rb
index b6763c9436f..67178de75de 100644
--- a/app/services/projects/hashed_storage/migrate_repository_service.rb
+++ b/app/services/projects/hashed_storage/migrate_repository_service.rb
@@ -27,11 +27,11 @@ module Projects
result &&= move_repository("#{@old_wiki_disk_path}", "#{@new_disk_path}.wiki")
end
- unless result
+ if result
+ project.write_repository_config
+ else
rollback_folder_move
project.storage_version = nil
- else
- project.write_repository_config
end
project.repository_read_only = false
--
cgit v1.2.1
From fd8e284dde6a263e7f0364b36c642c92f3ad31a4 Mon Sep 17 00:00:00 2001
From: Annabel Dunstone Gray
Date: Wed, 3 Jan 2018 11:36:18 -0700
Subject: Add left margin to definition elements
---
app/assets/stylesheets/framework/typography.scss | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 11c1aeea871..d0999e60e65 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -178,6 +178,10 @@
font-weight: inherit;
}
+ dd {
+ margin-left: $gl-padding;
+ }
+
ul,
ol {
padding: 0;
--
cgit v1.2.1
From 78cdac8401375cc85be54ae68e5d94d02a90233c Mon Sep 17 00:00:00 2001
From: Luc Didry
Date: Wed, 3 Jan 2018 17:32:34 +0100
Subject: Expose project_id on /api/v4/pages/domains
---
changelogs/unreleased/api-domains-expose-project_id.yml | 5 +++++
doc/api/pages_domains.md | 1 +
lib/api/entities.rb | 1 +
spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json | 3 ++-
spec/requests/api/pages_domains_spec.rb | 1 +
5 files changed, 10 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/api-domains-expose-project_id.yml
diff --git a/changelogs/unreleased/api-domains-expose-project_id.yml b/changelogs/unreleased/api-domains-expose-project_id.yml
new file mode 100644
index 00000000000..22617ffe9b5
--- /dev/null
+++ b/changelogs/unreleased/api-domains-expose-project_id.yml
@@ -0,0 +1,5 @@
+---
+title: Expose project_id on /api/v4/pages/domains
+merge_request: 16200
+author: Luc Didry
+type: changed
diff --git a/doc/api/pages_domains.md b/doc/api/pages_domains.md
index 50685f335f7..20275b902c6 100644
--- a/doc/api/pages_domains.md
+++ b/doc/api/pages_domains.md
@@ -21,6 +21,7 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/a
{
"domain": "ssl.domain.example",
"url": "https://ssl.domain.example",
+ "project_id": 1337,
"certificate": {
"expired": false,
"expiration": "2020-04-12T14:32:00.000Z"
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 4ad4a1f7867..270b456597d 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1133,6 +1133,7 @@ module API
class PagesDomainBasic < Grape::Entity
expose :domain
expose :url
+ expose :project_id
expose :certificate,
as: :certificate_expiration,
if: ->(pages_domain, _) { pages_domain.certificate? },
diff --git a/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json b/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json
index 4ba6422406c..e8c17298b43 100644
--- a/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json
+++ b/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json
@@ -3,6 +3,7 @@
"properties": {
"domain": { "type": "string" },
"url": { "type": "uri" },
+ "project_id": { "type": "integer" },
"certificate_expiration": {
"type": "object",
"properties": {
@@ -13,6 +14,6 @@
"additionalProperties": false
}
},
- "required": ["domain", "url"],
+ "required": ["domain", "url", "project_id"],
"additionalProperties": false
}
diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb
index d412b045e9f..5d01dc37f0e 100644
--- a/spec/requests/api/pages_domains_spec.rb
+++ b/spec/requests/api/pages_domains_spec.rb
@@ -46,6 +46,7 @@ describe API::PagesDomains do
expect(json_response).to be_an Array
expect(json_response.size).to eq(3)
expect(json_response.last).to have_key('domain')
+ expect(json_response.last).to have_key('project_id')
expect(json_response.last).to have_key('certificate_expiration')
expect(json_response.last['certificate_expiration']['expired']).to be true
expect(json_response.first).not_to have_key('certificate_expiration')
--
cgit v1.2.1
From f635277228c4ac90bd7215db741392df1998ddfc Mon Sep 17 00:00:00 2001
From: Michael Kozono
Date: Wed, 3 Jan 2018 12:03:52 -0800
Subject: Make DeleteConflictingRedirectRoutes no-op
Both the post-deploy and background migration.
---
.../mk-no-op-delete-conflicting-redirects.yml | 6 ++++
...907170235_delete_conflicting_redirect_routes.rb | 28 ++---------------
.../delete_conflicting_redirect_routes_range.rb | 36 ++--------------------
...elete_conflicting_redirect_routes_range_spec.rb | 13 +++-----
.../delete_conflicting_redirect_routes_spec.rb | 22 ++-----------
5 files changed, 17 insertions(+), 88 deletions(-)
create mode 100644 changelogs/unreleased/mk-no-op-delete-conflicting-redirects.yml
diff --git a/changelogs/unreleased/mk-no-op-delete-conflicting-redirects.yml b/changelogs/unreleased/mk-no-op-delete-conflicting-redirects.yml
new file mode 100644
index 00000000000..37fdb1df6df
--- /dev/null
+++ b/changelogs/unreleased/mk-no-op-delete-conflicting-redirects.yml
@@ -0,0 +1,6 @@
+---
+title: Prevent excessive DB load due to faulty DeleteConflictingRedirectRoutes background
+ migration
+merge_request: 16205
+author:
+type: fixed
diff --git a/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb b/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb
index 3e84b295be4..033019c398e 100644
--- a/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb
+++ b/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb
@@ -2,36 +2,12 @@
# for more information on how to write migrations for GitLab.
class DeleteConflictingRedirectRoutes < ActiveRecord::Migration
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- MIGRATION = 'DeleteConflictingRedirectRoutesRange'.freeze
- BATCH_SIZE = 200 # At 200, I expect under 20s per batch, which is under our query timeout of 60s.
- DELAY_INTERVAL = 12.seconds
-
- disable_ddl_transaction!
-
- class Route < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'routes'
- end
-
def up
- say opening_message
-
- queue_background_migration_jobs_by_range_at_intervals(Route, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
+ # No-op.
+ # See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
end
def down
# nothing
end
-
- def opening_message
- <<~MSG
- Clean up redirect routes that conflict with regular routes.
- See initial bug fix:
- https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13357
- MSG
- end
end
diff --git a/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb b/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb
index a1af045a71f..21b626dde56 100644
--- a/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb
+++ b/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb
@@ -1,44 +1,12 @@
# frozen_string_literal: true
-# rubocop:disable Metrics/LineLength
# rubocop:disable Style/Documentation
module Gitlab
module BackgroundMigration
class DeleteConflictingRedirectRoutesRange
- class Route < ActiveRecord::Base
- self.table_name = 'routes'
- end
-
- class RedirectRoute < ActiveRecord::Base
- self.table_name = 'redirect_routes'
- end
-
- # start_id - The start ID of the range of events to process
- # end_id - The end ID of the range to process.
def perform(start_id, end_id)
- return unless migrate?
-
- conflicts = RedirectRoute.where(routes_match_redirects_clause(start_id, end_id))
- num_rows = conflicts.delete_all
-
- Rails.logger.info("Gitlab::BackgroundMigration::DeleteConflictingRedirectRoutesRange [#{start_id}, #{end_id}] - Deleted #{num_rows} redirect routes that were conflicting with routes.")
- end
-
- def migrate?
- Route.table_exists? && RedirectRoute.table_exists?
- end
-
- def routes_match_redirects_clause(start_id, end_id)
- <<~ROUTES_MATCH_REDIRECTS
- EXISTS (
- SELECT 1 FROM routes
- WHERE (
- LOWER(redirect_routes.path) = LOWER(routes.path)
- OR LOWER(redirect_routes.path) LIKE LOWER(CONCAT(routes.path, '/%'))
- )
- AND routes.id BETWEEN #{start_id} AND #{end_id}
- )
- ROUTES_MATCH_REDIRECTS
+ # No-op.
+ # See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
end
end
end
diff --git a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb
index 5c471cbdeda..9bae7e53b71 100644
--- a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb
+++ b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb
@@ -24,17 +24,12 @@ describe Gitlab::BackgroundMigration::DeleteConflictingRedirectRoutesRange, :mig
redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo5')
end
- it 'deletes the conflicting redirect_routes in the range' do
+ # No-op. See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
+ it 'NO-OP: does not delete any redirect_routes' do
expect(redirect_routes.count).to eq(8)
- expect do
- described_class.new.perform(1, 3)
- end.to change { redirect_routes.where("path like 'foo%'").count }.from(5).to(2)
+ described_class.new.perform(1, 5)
- expect do
- described_class.new.perform(4, 5)
- end.to change { redirect_routes.where("path like 'foo%'").count }.from(2).to(0)
-
- expect(redirect_routes.count).to eq(3)
+ expect(redirect_routes.count).to eq(8)
end
end
diff --git a/spec/migrations/delete_conflicting_redirect_routes_spec.rb b/spec/migrations/delete_conflicting_redirect_routes_spec.rb
index 1df2477da51..8a191bd7139 100644
--- a/spec/migrations/delete_conflicting_redirect_routes_spec.rb
+++ b/spec/migrations/delete_conflicting_redirect_routes_spec.rb
@@ -10,9 +10,6 @@ describe DeleteConflictingRedirectRoutes, :migration, :sidekiq do
end
before do
- stub_const("DeleteConflictingRedirectRoutes::BATCH_SIZE", 2)
- stub_const("Gitlab::Database::MigrationHelpers::BACKGROUND_MIGRATION_JOB_BUFFER_SIZE", 2)
-
routes.create!(id: 1, source_id: 1, source_type: 'Namespace', path: 'foo1')
routes.create!(id: 2, source_id: 2, source_type: 'Namespace', path: 'foo2')
routes.create!(id: 3, source_id: 3, source_type: 'Namespace', path: 'foo3')
@@ -32,27 +29,14 @@ describe DeleteConflictingRedirectRoutes, :migration, :sidekiq do
redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo5')
end
- it 'correctly schedules background migrations' do
+ # No-op. See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
+ it 'NO-OP: does not schedule any background migrations' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
- expect(BackgroundMigrationWorker.jobs[0]['args']).to eq([described_class::MIGRATION, [1, 2]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(12.seconds.from_now.to_f)
- expect(BackgroundMigrationWorker.jobs[1]['args']).to eq([described_class::MIGRATION, [3, 4]])
- expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(24.seconds.from_now.to_f)
- expect(BackgroundMigrationWorker.jobs[2]['args']).to eq([described_class::MIGRATION, [5, 5]])
- expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(36.seconds.from_now.to_f)
- expect(BackgroundMigrationWorker.jobs.size).to eq 3
+ expect(BackgroundMigrationWorker.jobs.size).to eq 0
end
end
end
-
- it 'schedules background migrations' do
- Sidekiq::Testing.inline! do
- expect do
- migrate!
- end.to change { redirect_routes.count }.from(8).to(3)
- end
- end
end
--
cgit v1.2.1
From 57a490ec192d91ec2fd9dc9e0511af1709001fe6 Mon Sep 17 00:00:00 2001
From: Danny
Date: Wed, 3 Jan 2018 20:57:41 +0000
Subject: fix issue #37843
---
...-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml | 5 +++++
lib/gitlab/ci/ansi2html.rb | 2 +-
spec/lib/gitlab/ci/ansi2html_spec.rb | 4 ++++
3 files changed, 10 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/37843-ci-trace-ansi-colours-256-bold-have-no-css-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml
diff --git a/changelogs/unreleased/37843-ci-trace-ansi-colours-256-bold-have-no-css-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml b/changelogs/unreleased/37843-ci-trace-ansi-colours-256-bold-have-no-css-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml
new file mode 100644
index 00000000000..abf98cd2af4
--- /dev/null
+++ b/changelogs/unreleased/37843-ci-trace-ansi-colours-256-bold-have-no-css-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml
@@ -0,0 +1,5 @@
+---
+title: Fix ANSI 256 bold colors in pipelines job output
+merge_request:
+author:
+type: fixed
diff --git a/lib/gitlab/ci/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb
index 72b75791bbb..e25916528f4 100644
--- a/lib/gitlab/ci/ansi2html.rb
+++ b/lib/gitlab/ci/ansi2html.rb
@@ -234,7 +234,7 @@ module Gitlab
# Most terminals show bold colored text in the light color variant
# Let's mimic that here
if @style_mask & STYLE_SWITCHES[:bold] != 0
- fg_color.sub!(/fg-(\w{2,}+)/, 'fg-l-\1')
+ fg_color.sub!(/fg-([a-z]{2,}+)/, 'fg-l-\1')
end
css_classes << fg_color
end
diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb
index 33540eab5d6..05e2d94cbd6 100644
--- a/spec/lib/gitlab/ci/ansi2html_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2html_spec.rb
@@ -120,6 +120,10 @@ describe Gitlab::Ci::Ansi2html do
expect(convert_html("\e[48;5;240mHello")).to eq('Hello')
end
+ it "can print 256 xterm fg bold colors" do
+ expect(convert_html("\e[38;5;16;1mHello")).to eq('Hello')
+ end
+
it "can print 256 xterm bg colors on normal magenta foreground" do
expect(convert_html("\e[48;5;16;35mHello")).to eq('Hello')
end
--
cgit v1.2.1
From f6e339141d527fe50f61d9204ccf16b8ccc6d861 Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Wed, 3 Jan 2018 21:03:39 +0000
Subject: Backport of methods and components added in EBackport of methods and
components added in EEE
---
app/assets/javascripts/lib/utils/text_utility.js | 9 +++++
.../vue_shared/components/expand_button.vue | 46 ++++++++++++++++++++++
spec/javascripts/lib/utils/text_utility_spec.js | 10 +++++
.../vue_shared/components/expand_button_spec.js | 32 +++++++++++++++
4 files changed, 97 insertions(+)
create mode 100644 app/assets/javascripts/vue_shared/components/expand_button.vue
create mode 100644 spec/javascripts/vue_shared/components/expand_button_spec.js
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index 9280b7f150c..cb6e06ea584 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -64,3 +64,12 @@ export const truncate = (string, maxLength) => `${string.substr(0, (maxLength -
export function capitalizeFirstCharacter(text) {
return `${text[0].toUpperCase()}${text.slice(1)}`;
}
+
+/**
+ * Replaces all html tags from a string with the given replacement.
+ *
+ * @param {String} string
+ * @param {*} replace
+ * @returns {String}
+ */
+export const stripeHtml = (string, replace = '') => string.replace(/<[^>]*>/g, replace);
diff --git a/app/assets/javascripts/vue_shared/components/expand_button.vue b/app/assets/javascripts/vue_shared/components/expand_button.vue
new file mode 100644
index 00000000000..96991c4e268
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/expand_button.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js
index 1f46c225071..6f8dad6b835 100644
--- a/spec/javascripts/lib/utils/text_utility_spec.js
+++ b/spec/javascripts/lib/utils/text_utility_spec.js
@@ -62,4 +62,14 @@ describe('text_utility', () => {
expect(textUtils.slugify('João')).toEqual('joão');
});
});
+
+ describe('stripeHtml', () => {
+ it('replaces html tag with the default replacement', () => {
+ expect(textUtils.stripeHtml('This is a text with
html
.')).toEqual('This is a text with html.');
+ });
+
+ it('replaces html tags with the provided replacement', () => {
+ expect(textUtils.stripeHtml('This is a text with
html
.', ' ')).toEqual('This is a text with html .');
+ });
+ });
});
diff --git a/spec/javascripts/vue_shared/components/expand_button_spec.js b/spec/javascripts/vue_shared/components/expand_button_spec.js
new file mode 100644
index 00000000000..a33ab689dd1
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/expand_button_spec.js
@@ -0,0 +1,32 @@
+import Vue from 'vue';
+import expandButton from '~/vue_shared/components/expand_button.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('expand button', () => {
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(expandButton);
+ vm = mountComponent(Component, {
+ slots: {
+ expanded: '
Expanded!
',
+ },
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders a collpased button', () => {
+ expect(vm.$el.textContent.trim()).toEqual('...');
+ });
+
+ it('hides expander on click', (done) => {
+ vm.$el.querySelector('button').click();
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('button').getAttribute('style')).toEqual('display: none;');
+ done();
+ });
+ });
+});
--
cgit v1.2.1
From 127cedd0203a7ad16808391b6b768a52e8cb89f8 Mon Sep 17 00:00:00 2001
From: Mayra Cabrera
Date: Wed, 3 Jan 2018 17:59:23 -0600
Subject: Update Kubernetes service documentation
States this service was deprecated on 10.3 and his behavior depends on
the kubernetes service status. Also includes a link for the release post
for more information.
---
doc/api/services.md | 3 +++
doc/user/project/integrations/kubernetes.md | 2 +-
doc/user/project/integrations/project_services.md | 2 +-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/doc/api/services.md b/doc/api/services.md
index 7e2afc71f9a..2928ab6cc75 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -562,6 +562,9 @@ DELETE /projects/:id/services/jira
Kubernetes / Openshift integration
+CAUTION: **Warning:**
+Kubernetes service integration has been deprecated in GitLab 10.3. API service endpoints will continue to work as long as the Kubernetes service is active, however if the service is inactive API endpoints will automatically return a `400 Bad Request`. Read [GitLab 10.3 release post](https://about.gitlab.com/2017/12/22/gitlab-10-3-released/#kubernetes-integration-service) for more information.
+
### Create/Edit Kubernetes service
Set Kubernetes service for a project.
diff --git a/doc/user/project/integrations/kubernetes.md b/doc/user/project/integrations/kubernetes.md
index 079a840a56a..710cf78e84f 100644
--- a/doc/user/project/integrations/kubernetes.md
+++ b/doc/user/project/integrations/kubernetes.md
@@ -3,7 +3,7 @@ last_updated: 2017-12-28
---
CAUTION: **Warning:**
-Kubernetes service integration has been deprecated on GitLab 10.4. Fields on Kubernetes integration page are now uneditable, you can configure your clusters using the new [Clusters](../clusters/index.md) page.
+Kubernetes service integration has been deprecated in GitLab 10.3. If the service is active the cluster information still be editable, however we advised to disable and reconfigure the clusters using the new [Clusters](../clusters/index.md) page. If the service is inactive the fields will be uneditable. Read [GitLab 10.3 release post](https://about.gitlab.com/2017/12/22/gitlab-10-3-released/#kubernetes-integration-service) for more information.
# GitLab Kubernetes / OpenShift integration
diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md
index 6bda07f103e..9496d6f2ce0 100644
--- a/doc/user/project/integrations/project_services.md
+++ b/doc/user/project/integrations/project_services.md
@@ -39,7 +39,7 @@ Click on the service links to see further configuration instructions and details
| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway |
| [JIRA](jira.md) | JIRA issue tracker |
| JetBrains TeamCity CI | A continuous integration and build server |
-| [Kubernetes](kubernetes.md) _(Has been deprecated in GitLab 10.4)_ | A containerized deployment service |
+| [Kubernetes](kubernetes.md) _(Has been deprecated in GitLab 10.3)_ | A containerized deployment service |
| [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands |
| [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost |
| [Microsoft teams](microsoft_teams.md) | Receive notifications for actions that happen on GitLab into a room on Microsoft Teams using Office 365 Connectors |
--
cgit v1.2.1
From 5d3ade5cebfaefa38f888d2b2c3ae85c131ada7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Thu, 4 Jan 2018 01:55:18 +0100
Subject: Update Advanced cluster settings subtitle
---
app/views/projects/clusters/show.html.haml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml
index c15785806b9..1f5426dcfa5 100644
--- a/app/views/projects/clusters/show.html.haml
+++ b/app/views/projects/clusters/show.html.haml
@@ -40,6 +40,6 @@
%h4= _('Advanced settings')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
- %p= s_('ClusterIntegration|Manage cluster integration on your GitLab project')
+ %p= s_("ClusterIntegration|Advanced options on this cluster's integration")
.settings-content
= render 'advanced_settings'
--
cgit v1.2.1
From e712d1d121d7e5d02987710e460be9ecb9593978 Mon Sep 17 00:00:00 2001
From: George Tsiolis
Date: Thu, 4 Jan 2018 02:58:10 +0200
Subject: Remove unnecessary dashboard scroll
---
app/assets/stylesheets/framework/layout.scss | 4 ----
1 file changed, 4 deletions(-)
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 3f0268541a4..fab3270b9f5 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -106,10 +106,6 @@ body {
}
}
-.layout-page > .content-wrapper {
- min-height: calc(100vh - #{$header-height});
-}
-
.with-performance-bar .layout-page {
margin-top: $header-height + $performance-bar-height;
}
--
cgit v1.2.1
From ab7382f90a8a59d1dcd4445eadb0a3adb0eda7c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Thu, 4 Jan 2018 01:58:28 +0100
Subject: Update Remove cluster subtitle and alert
---
app/views/projects/clusters/_advanced_settings.html.haml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/views/projects/clusters/_advanced_settings.html.haml b/app/views/projects/clusters/_advanced_settings.html.haml
index 7032b892029..8a13713ae02 100644
--- a/app/views/projects/clusters/_advanced_settings.html.haml
+++ b/app/views/projects/clusters/_advanced_settings.html.haml
@@ -11,5 +11,5 @@
%label.text-danger
= s_('ClusterIntegration|Remove cluster integration')
%p
- = s_('ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine.')
- = link_to(s_('ClusterIntegration|Remove integration'), namespace_project_cluster_path(@project.namespace, @project, @cluster.id), method: :delete, class: 'btn btn-danger', data: { confirm: "Are you sure you want to remove cluster integration from this project? This will not delete your cluster on Google Kubernetes Engine"})
+ = s_("ClusterIntegration|Remove this cluster's configuration from this project. This will not delete your actual cluster.")
+ = link_to(s_('ClusterIntegration|Remove integration'), namespace_project_cluster_path(@project.namespace, @project, @cluster.id), method: :delete, class: 'btn btn-danger', data: { confirm: s_("ClusterIntegration|Are you sure you want to remove this cluster's integration? This will not delete your actual cluster.")})
--
cgit v1.2.1
From 43308bd826a88f92bbc92320e0591faf92acd66f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?=
Date: Mon, 18 Dec 2017 23:27:21 -0300
Subject: Move push_remote_branches from Gitlab::Shell to
Gitlab::Git::Repository
---
lib/gitlab/git/repository.rb | 19 +++++++++++++++-
lib/gitlab/shell.rb | 21 ------------------
spec/lib/gitlab/git/repository_spec.rb | 40 ++++++++++++++++++++++++++++++++--
spec/lib/gitlab/shell_spec.rb | 28 ------------------------
4 files changed, 56 insertions(+), 52 deletions(-)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 37d67b6052c..e159a795960 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -21,6 +21,7 @@ module Gitlab
REBASE_WORKTREE_PREFIX = 'rebase'.freeze
SQUASH_WORKTREE_PREFIX = 'squash'.freeze
GITALY_INTERNAL_URL = 'ssh://gitaly/internal.git'.freeze
+ GITLAB_PROJECTS_TIMEOUT = Gitlab.config.gitlab_shell.git_timeout
NoRepository = Class.new(StandardError)
InvalidBlobName = Class.new(StandardError)
@@ -83,7 +84,7 @@ module Gitlab
# Rugged repo object
attr_reader :rugged
- attr_reader :storage, :gl_repository, :relative_path
+ attr_reader :gitlab_projects, :storage, :gl_repository, :relative_path
# This initializer method is only used on the client side (gitlab-ce).
# Gitaly-ruby uses a different initializer.
@@ -93,6 +94,12 @@ module Gitlab
@gl_repository = gl_repository
storage_path = Gitlab.config.repositories.storages[@storage]['path']
+ @gitlab_projects = Gitlab::Git::GitlabProjects.new(
+ storage_path,
+ relative_path,
+ global_hooks_path: Gitlab.config.gitlab_shell.hooks_path,
+ logger: Rails.logger
+ )
@path = File.join(storage_path, @relative_path)
@name = @relative_path.split("/").last
@attributes = Gitlab::Git::Attributes.new(path)
@@ -1266,6 +1273,12 @@ module Gitlab
fresh_worktree?(worktree_path(SQUASH_WORKTREE_PREFIX, squash_id))
end
+ def push_remote_branches(remote_name, branch_names, forced: true)
+ success = @gitlab_projects.push_branches(remote_name, GITLAB_PROJECTS_TIMEOUT, forced, branch_names)
+
+ success || gitlab_projects_error
+ end
+
def gitaly_repository
Gitlab::GitalyClient::Util.repository(@storage, @relative_path, @gl_repository)
end
@@ -1943,6 +1956,10 @@ module Gitlab
def fetch_remote(remote_name = 'origin', env: nil)
run_git(['fetch', remote_name], env: env).last.zero?
end
+
+ def gitlab_projects_error
+ raise CommandError, @gitlab_projects.output
+ end
end
end
end
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 9cdd3d22f18..8dbe8ba5df0 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -306,27 +306,6 @@ module Gitlab
end
end
- # Push branch to remote repository
- #
- # storage - project's storage path
- # project_name - project's disk path
- # remote_name - remote name
- # branch_names - remote branch names to push
- # forced - should we use --force flag
- #
- # Ex.
- # push_remote_branches('/path/to/storage', 'gitlab-org/gitlab-test' 'upstream', ['feature'])
- #
- def push_remote_branches(storage, project_name, remote_name, branch_names, forced: true)
- cmd = gitlab_projects(storage, "#{project_name}.git")
-
- success = cmd.push_branches(remote_name, git_timeout, forced, branch_names)
-
- raise Error, cmd.output unless success
-
- success
- end
-
# Delete branch from remote repository
#
# storage - project's storage path
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 0e4292026df..12ec7b1fdc4 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -18,9 +18,10 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
+ let(:storage_path) { TestEnv.repos_path }
describe '.create_hooks' do
- let(:repo_path) { File.join(TestEnv.repos_path, 'hook-test.git') }
+ let(:repo_path) { File.join(storage_path, 'hook-test.git') }
let(:hooks_dir) { File.join(repo_path, 'hooks') }
let(:target_hooks_dir) { Gitlab.config.gitlab_shell.hooks_path }
let(:existing_target) { File.join(repo_path, 'foobar') }
@@ -645,7 +646,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
after do
- Gitlab::Shell.new.remove_repository(TestEnv.repos_path, 'my_project')
+ Gitlab::Shell.new.remove_repository(storage_path, 'my_project')
end
it 'fetches a repository as a mirror remote' do
@@ -1884,6 +1885,41 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe '#gitlab_projects' do
+ subject { repository.gitlab_projects }
+
+ it { expect(subject.shard_path).to eq(storage_path) }
+ it { expect(subject.repository_relative_path).to eq(repository.relative_path) }
+ end
+
+ context 'gitlab_projects commands' do
+ let(:gitlab_projects) { repository.gitlab_projects }
+ let(:timeout) { Gitlab.config.gitlab_shell.git_timeout }
+
+ describe '#push_remote_branches' do
+ subject do
+ repository.push_remote_branches('downstream-remote', ['master'])
+ end
+
+ it 'executes the command' do
+ expect(gitlab_projects).to receive(:push_branches)
+ .with('downstream-remote', timeout, true, ['master'])
+ .and_return(true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'raises an error if the command fails' do
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:push_branches)
+ .with('downstream-remote', timeout, true, ['master'])
+ .and_return(false)
+
+ expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
+ end
+ end
+ end
+
def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
source_branch = repository.branches.find { |branch| branch.name == source_branch_name }
rugged = repository.rugged
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index dd779b04741..7c2c02505b3 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -348,34 +348,6 @@ describe Gitlab::Shell do
end
end
- describe '#push_remote_branches' do
- subject(:result) do
- gitlab_shell.push_remote_branches(
- project.repository_storage_path,
- project.disk_path,
- 'downstream-remote',
- ['master']
- )
- end
-
- it 'executes the command' do
- expect(gitlab_projects).to receive(:push_branches)
- .with('downstream-remote', timeout, true, ['master'])
- .and_return(true)
-
- is_expected.to be_truthy
- end
-
- it 'fails to execute the command' do
- allow(gitlab_projects).to receive(:output) { 'error' }
- expect(gitlab_projects).to receive(:push_branches)
- .with('downstream-remote', timeout, true, ['master'])
- .and_return(false)
-
- expect { result }.to raise_error(Gitlab::Shell::Error, 'error')
- end
- end
-
describe '#delete_remote_branches' do
subject(:result) do
gitlab_shell.delete_remote_branches(
--
cgit v1.2.1
From 1c458d17d723161d871659f888dd24b995b8491d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?=
Date: Tue, 19 Dec 2017 01:41:02 -0300
Subject: Move delete_remote_branches from Gitlab::Shell to
Gitlab::Git::Repository
---
lib/gitlab/git/repository.rb | 12 ++++++
lib/gitlab/shell.rb | 20 ----------
spec/lib/gitlab/git/repository_spec.rb | 69 ++++++++++++++++++++++++++++++++++
spec/lib/gitlab/shell_spec.rb | 28 --------------
4 files changed, 81 insertions(+), 48 deletions(-)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index e159a795960..59c5484e587 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -1279,6 +1279,18 @@ module Gitlab
success || gitlab_projects_error
end
+ def delete_remote_branches(remote_name, branch_names)
+ success = @gitlab_projects.delete_remote_branches(remote_name, branch_names)
+
+ success || gitlab_projects_error
+ end
+
+ def delete_remote_branches(remote_name, branch_names)
+ success = @gitlab_projects.delete_remote_branches(remote_name, branch_names)
+
+ success || gitlab_projects_error
+ end
+
def gitaly_repository
Gitlab::GitalyClient::Util.repository(@storage, @relative_path, @gl_repository)
end
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 8dbe8ba5df0..40650fc5ee7 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -306,26 +306,6 @@ module Gitlab
end
end
- # Delete branch from remote repository
- #
- # storage - project's storage path
- # project_name - project's disk path
- # remote_name - remote name
- # branch_names - remote branch names
- #
- # Ex.
- # delete_remote_branches('/path/to/storage', 'gitlab-org/gitlab-test', 'upstream', ['feature'])
- #
- def delete_remote_branches(storage, project_name, remote_name, branch_names)
- cmd = gitlab_projects(storage, "#{project_name}.git")
-
- success = cmd.delete_remote_branches(remote_name, branch_names)
-
- raise Error, cmd.output unless success
-
- success
- end
-
protected
def gitlab_shell_path
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 12ec7b1fdc4..7c2c3584788 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1918,6 +1918,75 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
end
end
+
+ describe '#delete_remote_branches' do
+ subject do
+ repository.delete_remote_branches('downstream-remote', ['master'])
+ end
+
+ it 'executes the command' do
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'raises an error if the command fails' do
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(false)
+
+ expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
+ end
+ end
+
+ describe '#delete_remote_branches' do
+ subject do
+ repository.delete_remote_branches('downstream-remote', ['master'])
+ end
+
+ it 'executes the command' do
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'raises an error if the command fails' do
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(false)
+
+ expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
+ end
+ end
+
+ describe '#delete_remote_branches' do
+ subject do
+ repository.delete_remote_branches('downstream-remote', ['master'])
+ end
+
+ it 'executes the command' do
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'raises an error if the command fails' do
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(false)
+
+ expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
+ end
+ end
end
def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 7c2c02505b3..81d9e6a8f82 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -347,34 +347,6 @@ describe Gitlab::Shell do
end.to raise_error(Gitlab::Shell::Error, "error")
end
end
-
- describe '#delete_remote_branches' do
- subject(:result) do
- gitlab_shell.delete_remote_branches(
- project.repository_storage_path,
- project.disk_path,
- 'downstream-remote',
- ['master']
- )
- end
-
- it 'executes the command' do
- expect(gitlab_projects).to receive(:delete_remote_branches)
- .with('downstream-remote', ['master'])
- .and_return(true)
-
- is_expected.to be_truthy
- end
-
- it 'fails to execute the command' do
- allow(gitlab_projects).to receive(:output) { 'error' }
- expect(gitlab_projects).to receive(:delete_remote_branches)
- .with('downstream-remote', ['master'])
- .and_return(false)
-
- expect { result }.to raise_error(Gitlab::Shell::Error, 'error')
- end
- end
end
describe 'namespace actions' do
--
cgit v1.2.1
From 996becdcbb3cd40f9620b704dea3fd9229081f00 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?=
Date: Mon, 18 Dec 2017 20:58:20 -0300
Subject: Move git operations for UpdateRemoteMirrorService into Gitlab::Git
---
lib/gitlab/git/remote_mirror.rb | 75 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
create mode 100644 lib/gitlab/git/remote_mirror.rb
diff --git a/lib/gitlab/git/remote_mirror.rb b/lib/gitlab/git/remote_mirror.rb
new file mode 100644
index 00000000000..38e9d2a8554
--- /dev/null
+++ b/lib/gitlab/git/remote_mirror.rb
@@ -0,0 +1,75 @@
+module Gitlab
+ module Git
+ class RemoteMirror
+ def initialize(repository, ref_name)
+ @repository = repository
+ @ref_name = ref_name
+ end
+
+ def update(only_branches_matching: [], only_tags_matching: [])
+ local_branches = refs_obj(@repository.local_branches, only_refs_matching: only_branches_matching)
+ remote_branches = refs_obj(@repository.remote_branches(@ref_name), only_refs_matching: only_branches_matching)
+
+ updated_branches = changed_refs(local_branches, remote_branches)
+ push_branches(updated_branches.keys) if updated_branches.present?
+
+ delete_refs(local_branches, remote_branches)
+
+ local_tags = refs_obj(@repository.tags, only_refs_matching: only_tags_matching)
+ remote_tags = refs_obj(@repository.remote_tags(@ref_name), only_refs_matching: only_tags_matching)
+
+ updated_tags = changed_refs(local_tags, remote_tags)
+ @repository.push_remote_branches(@ref_name, updated_tags.keys) if updated_tags.present?
+
+ delete_refs(local_tags, remote_tags)
+ end
+
+ private
+
+ def refs_obj(refs, only_refs_matching: [])
+ refs.each_with_object({}) do |ref, refs|
+ next if only_refs_matching.present? && !only_refs_matching.include?(ref.name)
+
+ refs[ref.name] = ref
+ end
+ end
+
+ def changed_refs(local_refs, remote_refs)
+ local_refs.select do |ref_name, ref|
+ remote_ref = remote_refs[ref_name]
+
+ remote_ref.nil? || ref.dereferenced_target != remote_ref.dereferenced_target
+ end
+ end
+
+ def push_branches(branches)
+ default_branch, branches = branches.partition do |branch|
+ @repository.root_ref == branch
+ end
+
+ # Push the default branch first so it works fine when remote mirror is empty.
+ branches.unshift(*default_branch)
+
+ @repository.push_remote_branches(@ref_name, branches)
+ end
+
+ def delete_refs(local_refs, remote_refs)
+ refs = refs_to_delete(local_refs, remote_refs)
+
+ @repository.delete_remote_branches(@ref_name, refs.keys) if refs.present?
+ end
+
+ def refs_to_delete(local_refs, remote_refs)
+ default_branch_id = @repository.commit.id
+
+ remote_refs.select do |remote_ref_name, remote_ref|
+ next false if local_refs[remote_ref_name] # skip if branch or tag exist in local repo
+
+ remote_ref_id = remote_ref.dereferenced_target.try(:id)
+
+ remote_ref_id && @repository.rugged_is_ancestor?(remote_ref_id, default_branch_id)
+ end
+ end
+ end
+ end
+end
--
cgit v1.2.1
From 57dc5a521bbdd94cc2eab34f22e2b6fac9e8bd55 Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Sun, 17 Dec 2017 15:17:55 -0800
Subject: Avoid leaving a push event empty if payload cannot be created
If the payload cannot be created for some reason, we could be left with a nil
push event payload, which causes Error 500s when viewing the dashboard. Guard
against this error and log when it happens.
Avoids problems seen in #38823
---
.../unreleased/sh-validate-path-project-import.yml | 5 +++++
.../migrate_events_to_push_event_payloads.rb | 16 ++++++++--------
.../migrate_events_to_push_event_payloads_spec.rb | 14 ++++++++++++--
3 files changed, 25 insertions(+), 10 deletions(-)
create mode 100644 changelogs/unreleased/sh-validate-path-project-import.yml
diff --git a/changelogs/unreleased/sh-validate-path-project-import.yml b/changelogs/unreleased/sh-validate-path-project-import.yml
new file mode 100644
index 00000000000..acad66c0ab2
--- /dev/null
+++ b/changelogs/unreleased/sh-validate-path-project-import.yml
@@ -0,0 +1,5 @@
+---
+title: Avoid leaving a push event empty if payload cannot be created
+merge_request:
+author:
+type: fixed
diff --git a/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb b/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb
index 84ac00f1a5c..7088aa0860a 100644
--- a/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb
+++ b/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb
@@ -128,8 +128,14 @@ module Gitlab
end
def process_event(event)
- replicate_event(event)
- create_push_event_payload(event) if event.push_event?
+ ActiveRecord::Base.transaction do
+ replicate_event(event)
+ create_push_event_payload(event) if event.push_event?
+ end
+ rescue ActiveRecord::InvalidForeignKey => e
+ # A foreign key error means the associated event was removed. In this
+ # case we'll just skip migrating the event.
+ Rails.logger.error("Unable to migrate event #{event.id}: #{e}")
end
def replicate_event(event)
@@ -137,9 +143,6 @@ module Gitlab
.with_indifferent_access.except(:title, :data)
EventForMigration.create!(new_attributes)
- rescue ActiveRecord::InvalidForeignKey
- # A foreign key error means the associated event was removed. In this
- # case we'll just skip migrating the event.
end
def create_push_event_payload(event)
@@ -156,9 +159,6 @@ module Gitlab
ref: event.trimmed_ref_name,
commit_title: event.commit_title
)
- rescue ActiveRecord::InvalidForeignKey
- # A foreign key error means the associated event was removed. In this
- # case we'll just skip migrating the event.
end
def find_events(start_id, end_id)
diff --git a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
index 7351d45336a..5432d270555 100644
--- a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
@@ -281,6 +281,17 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati
migration.process_event(event)
end
+
+ it 'handles an error gracefully' do
+ event1 = create_push_event(project, author, { commits: [] })
+
+ expect(migration).to receive(:replicate_event).and_call_original
+ expect(migration).to receive(:create_push_event_payload).and_raise(ActiveRecord::InvalidForeignKey, 'invalid foreign key')
+
+ migration.process_event(event1)
+
+ expect(described_class::EventForMigration.all.count).to eq(0)
+ end
end
describe '#replicate_event' do
@@ -335,9 +346,8 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati
it 'does not create push event payloads for removed events' do
allow(event).to receive(:id).and_return(-1)
- payload = migration.create_push_event_payload(event)
+ expect { migration.create_push_event_payload(event) }.to raise_error(ActiveRecord::InvalidForeignKey)
- expect(payload).to be_nil
expect(PushEventPayload.count).to eq(0)
end
--
cgit v1.2.1
From 9222900b5f528ad38299a7dac2b3fa92bdb858e4 Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Wed, 3 Jan 2018 12:12:18 +0530
Subject: Fix groups list icon, timestamp alignment and row height
---
app/assets/stylesheets/framework/lists.scss | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index 17915a55b45..f453fc2b547 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -450,6 +450,7 @@ ul.indent-list {
}
.stats {
+ position: relative;
line-height: 46px;
> span {
@@ -459,20 +460,40 @@ ul.indent-list {
min-width: 30px;
}
+ > span:last-child {
+ margin-right: 0;
+ }
+
.stat-value {
margin: 2px 0 0 5px;
}
}
+
+ .controls {
+ margin-left: 5px;
+
+ > .btn {
+ margin-right: $btn-xs-side-margin;
+ }
+ }
}
.project-row-contents .stats {
line-height: inherit;
- span:first-child {
+ > span:first-child {
margin-left: 25px;
}
+ .item-visibility {
+ margin-right: 0;
+ }
+
.last-updated {
+ position: absolute;
+ right: 12px;
+ min-width: 250px;
+ text-align: right;
color: $gl-text-color-secondary;
}
}
@@ -486,11 +507,11 @@ ul.indent-list {
ul.group-list-tree {
li.group-row {
- .title {
+ > .group-row-contents .title {
line-height: $list-text-height;
}
- &.has-description .title {
+ &.has-description > .group-row-contents .title {
line-height: inherit;
}
}
--
cgit v1.2.1
From 703aa9d23229c69c0d5d90869f979d318b17d028 Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Thu, 4 Jan 2018 12:32:47 +0530
Subject: Make tooltip placement bottom by default as per design guidelines
---
app/assets/javascripts/groups/components/group_item.vue | 2 +-
app/assets/javascripts/groups/components/item_actions.vue | 2 ++
app/assets/javascripts/groups/components/item_stats_value.vue | 2 +-
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index 583f14e6885..02129d39846 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -125,7 +125,7 @@ export default {
:href="group.relativePath"
:title="group.fullName"
class="no-expand"
- data-placement="top"
+ data-placement="bottom"
>{{
// ending bracket must be by closing tag to prevent
// link hover text-decoration from over-extending
diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue
index d3817cae6dc..a685960d862 100644
--- a/app/assets/javascripts/groups/components/item_actions.vue
+++ b/app/assets/javascripts/groups/components/item_actions.vue
@@ -64,6 +64,7 @@ export default {
:title="editBtnTitle"
:aria-label="editBtnTitle"
data-container="body"
+ data-placement="bottom"
class="edit-group btn no-expand">
@@ -75,6 +76,7 @@ export default {
:title="leaveBtnTitle"
:aria-label="leaveBtnTitle"
data-container="body"
+ data-placement="bottom"
class="leave-group btn no-expand">
diff --git a/app/assets/javascripts/groups/components/item_stats_value.vue b/app/assets/javascripts/groups/components/item_stats_value.vue
index 46402b304c5..f441cabf6d2 100644
--- a/app/assets/javascripts/groups/components/item_stats_value.vue
+++ b/app/assets/javascripts/groups/components/item_stats_value.vue
@@ -21,7 +21,7 @@ export default {
tooltipPlacement: {
type: String,
required: false,
- default: 'top',
+ default: 'bottom',
},
/**
* value could either be number or string
--
cgit v1.2.1
From 7fbb5addaf7c15c971f584ebeecb2c93773093c0 Mon Sep 17 00:00:00 2001
From: Tim Zallmann
Date: Thu, 4 Jan 2018 09:31:06 +0000
Subject: Resolve "Resizable file list and commit panel"
---
.../javascripts/ide/components/ide_context_bar.vue | 33 ++++++++
.../javascripts/ide/components/ide_side_bar.vue | 33 ++++++++
.../javascripts/ide/components/repo_editor.vue | 6 ++
app/assets/javascripts/ide/stores/actions.js | 4 +
.../javascripts/ide/stores/mutation_types.js | 1 +
app/assets/javascripts/ide/stores/mutations.js | 5 ++
app/assets/javascripts/ide/stores/state.js | 1 +
.../vue_shared/components/panel_resizer.vue | 91 ++++++++++++++++++++++
app/assets/stylesheets/pages/repo.scss | 34 ++++++--
.../vue_shared/components/panel_resizer_spec.js | 59 ++++++++++++++
10 files changed, 262 insertions(+), 5 deletions(-)
create mode 100644 app/assets/javascripts/vue_shared/components/panel_resizer.vue
create mode 100644 spec/javascripts/vue_shared/components/panel_resizer_spec.js
diff --git a/app/assets/javascripts/ide/components/ide_context_bar.vue b/app/assets/javascripts/ide/components/ide_context_bar.vue
index 5a08718e386..78c01272af6 100644
--- a/app/assets/javascripts/ide/components/ide_context_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_context_bar.vue
@@ -2,11 +2,18 @@
import { mapGetters, mapState, mapActions } from 'vuex';
import repoCommitSection from './repo_commit_section.vue';
import icon from '../../vue_shared/components/icon.vue';
+import panelResizer from '../../vue_shared/components/panel_resizer.vue';
export default {
+ data() {
+ return {
+ width: 290,
+ };
+ },
components: {
repoCommitSection,
icon,
+ panelResizer,
},
computed: {
...mapState([
@@ -18,10 +25,20 @@ export default {
currentIcon() {
return this.rightPanelCollapsed ? 'angle-double-left' : 'angle-double-right';
},
+ maxSize() {
+ return window.innerWidth / 2;
+ },
+ panelStyle() {
+ if (!this.rightPanelCollapsed) {
+ return { width: `${this.width}px` };
+ }
+ return {};
+ },
},
methods: {
...mapActions([
'setPanelCollapsedStatus',
+ 'setResizingStatus',
]),
toggleCollapsed() {
this.setPanelCollapsedStatus({
@@ -29,6 +46,12 @@ export default {
collapsed: !this.rightPanelCollapsed,
});
},
+ resizingStarted() {
+ this.setResizingStatus(true);
+ },
+ resizingEnded() {
+ this.setResizingStatus(false);
+ },
},
};
@@ -39,6 +62,7 @@ export default {
:class="{
'is-collapsed': rightPanelCollapsed,
}"
+ :style="panelStyle"
>
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index 221be4b9074..343fd0a5300 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -90,6 +90,11 @@ export default {
rightPanelCollapsed() {
this.editor.updateDimensions();
},
+ panelResizing(isResizing) {
+ if (isResizing === false) {
+ this.editor.updateDimensions();
+ }
+ },
},
computed: {
...mapGetters([
@@ -99,6 +104,7 @@ export default {
...mapState([
'leftPanelCollapsed',
'rightPanelCollapsed',
+ 'panelResizing',
]),
shouldHideEditor() {
return this.activeFile.binary && !this.activeFile.raw;
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index c01046c8c76..335882bb6d7 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -63,6 +63,10 @@ export const setPanelCollapsedStatus = ({ commit }, { side, collapsed }) => {
}
};
+export const setResizingStatus = ({ commit }, resizing) => {
+ commit(types.SET_RESIZING_STATUS, resizing);
+};
+
export const checkCommitStatus = ({ state }) =>
service
.getBranchData(state.currentProjectId, state.currentBranchId)
diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js
index 4e3c10972ba..69b218a5e7d 100644
--- a/app/assets/javascripts/ide/stores/mutation_types.js
+++ b/app/assets/javascripts/ide/stores/mutation_types.js
@@ -5,6 +5,7 @@ export const SET_ROOT = 'SET_ROOT';
export const SET_LAST_COMMIT_DATA = 'SET_LAST_COMMIT_DATA';
export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED';
export const SET_RIGHT_PANEL_COLLAPSED = 'SET_RIGHT_PANEL_COLLAPSED';
+export const SET_RESIZING_STATUS = 'SET_RESIZING_STATUS';
// Project Mutation Types
export const SET_PROJECT = 'SET_PROJECT';
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 2fed9019cb6..03d81be10a1 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -49,6 +49,11 @@ export default {
rightPanelCollapsed: collapsed,
});
},
+ [types.SET_RESIZING_STATUS](state, resizing) {
+ Object.assign(state, {
+ panelResizing: resizing,
+ });
+ },
[types.SET_LAST_COMMIT_DATA](state, { entry, lastCommit }) {
Object.assign(entry.lastCommit, {
id: lastCommit.commit.id,
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 539e382830f..61d12096946 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -19,4 +19,5 @@ export default () => ({
projects: {},
leftPanelCollapsed: false,
rightPanelCollapsed: true,
+ panelResizing: false,
});
diff --git a/app/assets/javascripts/vue_shared/components/panel_resizer.vue b/app/assets/javascripts/vue_shared/components/panel_resizer.vue
new file mode 100644
index 00000000000..4371534d345
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/panel_resizer.vue
@@ -0,0 +1,91 @@
+
+
+
+
+
diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss
index 51cc1729d9a..d01cbadebcc 100644
--- a/app/assets/stylesheets/pages/repo.scss
+++ b/app/assets/stylesheets/pages/repo.scss
@@ -36,10 +36,6 @@
}
}
-.with-performance-bar .ide-view {
- height: calc(100vh - #{$header-height});
-}
-
.ide-file-list {
flex: 1;
@@ -242,12 +238,13 @@ table.table tr td.multi-file-table-name {
.multi-file-commit-panel {
display: flex;
+ position: relative;
flex-direction: column;
height: 100%;
width: 290px;
padding: 0;
background-color: $gray-light;
- border-left: 1px solid $white-dark;
+ padding-right: 3px;
.projects-sidebar {
display: flex;
@@ -496,3 +493,30 @@ table.table tr td.multi-file-table-name {
margin-top: $header-height;
margin-bottom: 0;
}
+
+.with-performance-bar {
+ .ide-flash-container.flash-container {
+ margin-top: $header-height + $performance-bar-height;
+ }
+
+ .ide-view {
+ height: calc(100vh - #{$header-height + $performance-bar-height});
+ }
+}
+
+
+.dragHandle {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ width: 3px;
+ background-color: $white-dark;
+
+ &.dragright {
+ right: 0;
+ }
+
+ &.dragleft {
+ left: 0;
+ }
+}
diff --git a/spec/javascripts/vue_shared/components/panel_resizer_spec.js b/spec/javascripts/vue_shared/components/panel_resizer_spec.js
new file mode 100644
index 00000000000..70ce3dffaba
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/panel_resizer_spec.js
@@ -0,0 +1,59 @@
+import Vue from 'vue';
+import panelResizer from '~/vue_shared/components/panel_resizer.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('Panel Resizer component', () => {
+ let vm;
+ let PanelResizer;
+
+ const triggerEvent = (eventName, el = vm.$el, clientX = 0) => {
+ const event = document.createEvent('MouseEvents');
+ event.initMouseEvent(eventName, true, true, window, 1, clientX, 0, clientX, 0, false, false,
+ false, false, 0, null);
+
+ el.dispatchEvent(event);
+ };
+
+ beforeEach(() => {
+ PanelResizer = Vue.extend(panelResizer);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should render a div element with the correct classes and styles', () => {
+ vm = mountComponent(PanelResizer, {
+ startSize: 100,
+ side: 'left',
+ });
+
+ expect(vm.$el.tagName).toEqual('DIV');
+ expect(vm.$el.getAttribute('class')).toBe('dragHandle dragleft');
+ expect(vm.$el.getAttribute('style')).toBe('cursor: ew-resize;');
+ });
+
+ it('should render a div element with the correct classes for a right side panel', () => {
+ vm = mountComponent(PanelResizer, {
+ startSize: 100,
+ side: 'right',
+ });
+
+ expect(vm.$el.tagName).toEqual('DIV');
+ expect(vm.$el.getAttribute('class')).toBe('dragHandle dragright');
+ });
+
+ it('drag the resizer', () => {
+ vm = mountComponent(PanelResizer, {
+ startSize: 100,
+ side: 'left',
+ });
+
+ spyOn(vm, '$emit');
+ triggerEvent('mousedown', vm.$el);
+ triggerEvent('mousemove', document);
+ triggerEvent('mouseup', document);
+ expect(vm.$emit.calls.allArgs()).toEqual([['resize-start', 100], ['update:size', 100], ['resize-end', 100]]);
+ expect(vm.size).toBe(100);
+ });
+});
--
cgit v1.2.1
From e028d795c484dcd1030b4f6bba8f53d4e677f0b3 Mon Sep 17 00:00:00 2001
From: Mayra Cabrera
Date: Thu, 4 Jan 2018 09:33:51 +0000
Subject: 41054-Disallow creation of new Kubernetes integrations
---
app/assets/stylesheets/pages/settings.scss | 4 +
app/helpers/services_helper.rb | 11 +++
app/models/project_services/kubernetes_service.rb | 28 ++++++
app/models/service.rb | 8 ++
.../services/_deprecated_message.html.haml | 3 +
app/views/projects/services/_form.html.haml | 5 +-
app/views/projects/services/edit.html.haml | 2 +
app/views/shared/_field.html.haml | 11 ++-
app/views/shared/_service_settings.html.haml | 2 +-
...ble-creation-of-new-kubernetes-integrations.yml | 6 ++
.../projects/services_controller_spec.rb | 36 ++++++++
spec/factories/services.rb | 1 +
.../projects/clusters/interchangeability_spec.rb | 2 +-
.../project_services/kubernetes_service_spec.rb | 101 +++++++++++++++++++++
spec/models/service_spec.rb | 18 ++++
spec/requests/api/services_spec.rb | 8 +-
spec/requests/api/v3/services_spec.rb | 4 +
spec/support/services_shared_context.rb | 8 ++
18 files changed, 244 insertions(+), 14 deletions(-)
create mode 100644 app/views/projects/services/_deprecated_message.html.haml
create mode 100644 changelogs/unreleased/41054-disable-creation-of-new-kubernetes-integrations.yml
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 5d630c7d61e..6353482ede7 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -268,3 +268,7 @@
margin: 0 0 5px 17px;
}
}
+
+.deprecated-service {
+ cursor: default;
+}
diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb
index 3707bb5ba36..240783bc7fd 100644
--- a/app/helpers/services_helper.rb
+++ b/app/helpers/services_helper.rb
@@ -27,5 +27,16 @@ module ServicesHelper
"#{event}_events"
end
+ def service_save_button(service)
+ button_tag(class: 'btn btn-save', type: 'submit', disabled: service.deprecated?) do
+ icon('spinner spin', class: 'hidden js-btn-spinner') +
+ content_tag(:span, 'Save changes', class: 'js-btn-label')
+ end
+ end
+
+ def disable_fields_service?(service)
+ !current_controller?("admin/services") && service.deprecated?
+ end
+
extend self
end
diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb
index b82567ce2b3..c72b01b64af 100644
--- a/app/models/project_services/kubernetes_service.rb
+++ b/app/models/project_services/kubernetes_service.rb
@@ -31,6 +31,7 @@ class KubernetesService < DeploymentService
before_validation :enforce_namespace_to_lower_case
+ validate :deprecation_validation, unless: :template?
validates :namespace,
allow_blank: true,
length: 1..63,
@@ -145,6 +146,17 @@ class KubernetesService < DeploymentService
@kubeclient ||= build_kubeclient!
end
+ def deprecated?
+ !active
+ end
+
+ def deprecation_message
+ content = <<-MESSAGE.strip_heredoc
+ Kubernetes service integration has been deprecated. #{deprecated_message_content} your clusters using the new Clusters page
+ MESSAGE
+ content.html_safe
+ end
+
TEMPLATE_PLACEHOLDER = 'Kubernetes namespace'.freeze
private
@@ -226,4 +238,20 @@ class KubernetesService < DeploymentService
def enforce_namespace_to_lower_case
self.namespace = self.namespace&.downcase
end
+
+ def deprecation_validation
+ return if active_changed?(from: true, to: false)
+
+ if deprecated?
+ errors[:base] << deprecation_message
+ end
+ end
+
+ def deprecated_message_content
+ if active?
+ "Your cluster information on this page is still editable, but you are advised to disable and reconfigure"
+ else
+ "Fields on this page are now uneditable, you can configure"
+ end
+ end
end
diff --git a/app/models/service.rb b/app/models/service.rb
index 3c4f1885dd0..176b472e724 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -263,6 +263,14 @@ class Service < ActiveRecord::Base
service
end
+ def deprecated?
+ false
+ end
+
+ def deprecation_message
+ nil
+ end
+
private
def cache_project_has_external_issue_tracker
diff --git a/app/views/projects/services/_deprecated_message.html.haml b/app/views/projects/services/_deprecated_message.html.haml
new file mode 100644
index 00000000000..fea9506a4bb
--- /dev/null
+++ b/app/views/projects/services/_deprecated_message.html.haml
@@ -0,0 +1,3 @@
+.flash-container.flash-container-page
+ .flash-alert.deprecated-service
+ %span= @service.deprecation_message
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index c0b1c62e8ef..21acd857ce7 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -13,10 +13,7 @@
= render 'shared/service_settings', form: form, subject: @service
- if @service.editable?
.footer-block.row-content-block
- %button.btn.btn-save{ type: 'submit' }
- = icon('spinner spin', class: 'hidden js-btn-spinner')
- %span.js-btn-label
- Save changes
+ = service_save_button(@service)
- if @service.valid? && @service.activated?
- unless @service.can_test?
diff --git a/app/views/projects/services/edit.html.haml b/app/views/projects/services/edit.html.haml
index 25770df1c90..df1fd583670 100644
--- a/app/views/projects/services/edit.html.haml
+++ b/app/views/projects/services/edit.html.haml
@@ -2,4 +2,6 @@
- page_title @service.title, "Services"
- add_to_breadcrumbs("Settings", edit_project_path(@project))
+= render 'deprecated_message' if @service.deprecation_message
+
= render 'form'
diff --git a/app/views/shared/_field.html.haml b/app/views/shared/_field.html.haml
index 795447a9ca6..aea0a8fd8e0 100644
--- a/app/views/shared/_field.html.haml
+++ b/app/views/shared/_field.html.haml
@@ -7,6 +7,7 @@
- choices = field[:choices]
- default_choice = field[:default_choice]
- help = field[:help]
+- disabled = disable_fields_service?(@service)
.form-group
- if type == "password" && value.present?
@@ -15,14 +16,14 @@
= form.label name, title, class: "control-label"
.col-sm-10
- if type == 'text'
- = form.text_field name, class: "form-control", placeholder: placeholder, required: required
+ = form.text_field name, class: "form-control", placeholder: placeholder, required: required, disabled: disabled
- elsif type == 'textarea'
- = form.text_area name, rows: 5, class: "form-control", placeholder: placeholder, required: required
+ = form.text_area name, rows: 5, class: "form-control", placeholder: placeholder, required: required, disabled: disabled
- elsif type == 'checkbox'
- = form.check_box name
+ = form.check_box name, disabled: disabled
- elsif type == 'select'
- = form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
+ = form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control", disabled: disabled}
- elsif type == 'password'
- = form.password_field name, autocomplete: "new-password", class: "form-control", required: value.blank? && :required
+ = form.password_field name, autocomplete: "new-password", class: "form-control", required: value.blank? && required, disabled: disabled
- if help
%span.help-block= help
diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml
index 7ca14ac93cc..61b39afb5d4 100644
--- a/app/views/shared/_service_settings.html.haml
+++ b/app/views/shared/_service_settings.html.haml
@@ -11,7 +11,7 @@
.form-group
= form.label :active, "Active", class: "control-label"
.col-sm-10
- = form.check_box :active
+ = form.check_box :active, disabled: disable_fields_service?(@service)
- if @service.supported_events.present?
.form-group
diff --git a/changelogs/unreleased/41054-disable-creation-of-new-kubernetes-integrations.yml b/changelogs/unreleased/41054-disable-creation-of-new-kubernetes-integrations.yml
new file mode 100644
index 00000000000..b960b14624c
--- /dev/null
+++ b/changelogs/unreleased/41054-disable-creation-of-new-kubernetes-integrations.yml
@@ -0,0 +1,6 @@
+---
+title: Disable creation of new Kubernetes Integrations unless they're active or created
+ from template
+merge_request: 41054
+author:
+type: added
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 2c6ad00515e..847ac6f2be0 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -114,5 +114,41 @@ describe Projects::ServicesController do
expect(flash[:notice]).to eq 'HipChat settings saved, but not activated.'
end
end
+
+ context 'with a deprecated service' do
+ let(:service) { create(:kubernetes_service, project: project) }
+
+ before do
+ put :update,
+ namespace_id: project.namespace, project_id: project, id: service.to_param, service: { namespace: 'updated_namespace' }
+ end
+
+ it 'should not update the service' do
+ service.reload
+ expect(service.namespace).not_to eq('updated_namespace')
+ end
+ end
+ end
+
+ describe "GET #edit" do
+ before do
+ get :edit, namespace_id: project.namespace, project_id: project, id: service_id
+ end
+
+ context 'with approved services' do
+ let(:service_id) { 'jira' }
+
+ it 'should render edit page' do
+ expect(response).to be_success
+ end
+ end
+
+ context 'with a deprecated service' do
+ let(:service_id) { 'kubernetes' }
+
+ it 'should render edit page' do
+ expect(response).to be_success
+ end
+ end
end
end
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index 4b0377967c7..110ef33c6f7 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -18,6 +18,7 @@ FactoryBot.define do
factory :kubernetes_service do
project
+ type 'KubernetesService'
active true
properties({
api_url: 'https://kubernetes.example.com',
diff --git a/spec/features/projects/clusters/interchangeability_spec.rb b/spec/features/projects/clusters/interchangeability_spec.rb
index 01f9526608f..3ddb35c755c 100644
--- a/spec/features/projects/clusters/interchangeability_spec.rb
+++ b/spec/features/projects/clusters/interchangeability_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
feature 'Interchangeability between KubernetesService and Platform::Kubernetes' do
- EXCEPT_METHODS = %i[test title description help fields initialize_properties namespace namespace= api_url api_url=].freeze
+ EXCEPT_METHODS = %i[test title description help fields initialize_properties namespace namespace= api_url api_url= deprecated? deprecation_message].freeze
EXCEPT_METHODS_GREP_V = %w[_touched? _changed? _was].freeze
it 'Clusters::Platform::Kubernetes covers core interfaces in KubernetesService' do
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index f037ee77a94..6980ba335b8 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -52,12 +52,75 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'when service is inactive' do
before do
+ subject.project = project
subject.active = false
end
it { is_expected.not_to validate_presence_of(:api_url) }
it { is_expected.not_to validate_presence_of(:token) }
end
+
+ context 'with a deprecated service' do
+ let(:kubernetes_service) { create(:kubernetes_service) }
+
+ before do
+ kubernetes_service.update_attribute(:active, false)
+ kubernetes_service.properties[:namespace] = "foo"
+ end
+
+ it 'should not update attributes' do
+ expect(kubernetes_service.save).to be_falsy
+ end
+
+ it 'should include an error with a deprecation message' do
+ kubernetes_service.valid?
+ expect(kubernetes_service.errors[:base].first).to match(/Kubernetes service integration has been deprecated/)
+ end
+ end
+
+ context 'with a non-deprecated service' do
+ let(:kubernetes_service) { create(:kubernetes_service) }
+
+ it 'should update attributes' do
+ kubernetes_service.properties[:namespace] = 'foo'
+ expect(kubernetes_service.save).to be_truthy
+ end
+ end
+
+ context 'with an active and deprecated service' do
+ let(:kubernetes_service) { create(:kubernetes_service) }
+
+ before do
+ kubernetes_service.active = false
+ kubernetes_service.properties[:namespace] = 'foo'
+ kubernetes_service.save
+ end
+
+ it 'should deactive the service' do
+ expect(kubernetes_service.active?).to be_falsy
+ end
+
+ it 'should not include a deprecation message as error' do
+ expect(kubernetes_service.errors.messages.count).to eq(0)
+ end
+
+ it 'should update attributes' do
+ expect(kubernetes_service.properties[:namespace]).to eq("foo")
+ end
+ end
+
+ context 'with a template service' do
+ let(:kubernetes_service) { create(:kubernetes_service, template: true, active: false) }
+
+ before do
+ kubernetes_service.properties[:namespace] = 'foo'
+ end
+
+ it 'should update attributes' do
+ expect(kubernetes_service.save).to be_truthy
+ expect(kubernetes_service.properties[:namespace]).to eq('foo')
+ end
+ end
end
describe '#initialize_properties' do
@@ -318,4 +381,42 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
it { is_expected.to eq(pods: []) }
end
end
+
+ describe "#deprecated?" do
+ let(:kubernetes_service) { create(:kubernetes_service) }
+
+ context 'with an active kubernetes service' do
+ it 'should return false' do
+ expect(kubernetes_service.deprecated?).to be_falsy
+ end
+ end
+
+ context 'with a inactive kubernetes service' do
+ it 'should return true' do
+ kubernetes_service.update_attribute(:active, false)
+ expect(kubernetes_service.deprecated?).to be_truthy
+ end
+ end
+ end
+
+ describe "#deprecation_message" do
+ let(:kubernetes_service) { create(:kubernetes_service) }
+
+ it 'should indicate the service is deprecated' do
+ expect(kubernetes_service.deprecation_message).to match(/Kubernetes service integration has been deprecated/)
+ end
+
+ context 'if the services is active' do
+ it 'should return a message' do
+ expect(kubernetes_service.deprecation_message).to match(/Your cluster information on this page is still editable/)
+ end
+ end
+
+ context 'if the service is not active' do
+ it 'should return a message' do
+ kubernetes_service.update_attribute(:active, false)
+ expect(kubernetes_service.deprecation_message).to match(/Fields on this page are now uneditable/)
+ end
+ end
+ end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 0f2f906c667..540615de117 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -254,4 +254,22 @@ describe Service do
end
end
end
+
+ describe "#deprecated?" do
+ let(:project) { create(:project, :repository) }
+
+ it 'should return false by default' do
+ service = create(:service, project: project)
+ expect(service.deprecated?).to be_falsy
+ end
+ end
+
+ describe "#deprecation_message" do
+ let(:project) { create(:project, :repository) }
+
+ it 'should be empty by default' do
+ service = create(:service, project: project)
+ expect(service.deprecation_message).to be_nil
+ end
+ end
end
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index ceafa0e2058..26d56c04862 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -53,6 +53,10 @@ describe API::Services do
describe "DELETE /projects/:id/services/#{service.dasherize}" do
include_context service
+ before do
+ initialize_service(service)
+ end
+
it "deletes #{service}" do
delete api("/projects/#{project.id}/services/#{dashed_service}", user)
@@ -67,9 +71,7 @@ describe API::Services do
# inject some properties into the service
before do
- service_object = project.find_or_initialize_service(service)
- service_object.properties = service_attrs
- service_object.save
+ initialize_service(service)
end
it 'returns authentication error when unauthenticated' do
diff --git a/spec/requests/api/v3/services_spec.rb b/spec/requests/api/v3/services_spec.rb
index 8f212ab6be6..c69a7d58ca6 100644
--- a/spec/requests/api/v3/services_spec.rb
+++ b/spec/requests/api/v3/services_spec.rb
@@ -10,6 +10,10 @@ describe API::V3::Services do
describe "DELETE /projects/:id/services/#{service.dasherize}" do
include_context service
+ before do
+ initialize_service(service)
+ end
+
it "deletes #{service}" do
delete v3_api("/projects/#{project.id}/services/#{dashed_service}", user)
diff --git a/spec/support/services_shared_context.rb b/spec/support/services_shared_context.rb
index 7457484a932..3f1fd169b72 100644
--- a/spec/support/services_shared_context.rb
+++ b/spec/support/services_shared_context.rb
@@ -29,5 +29,13 @@ Service.available_services_names.each do |service|
end
end
end
+
+ def initialize_service(service)
+ service_item = project.find_or_initialize_service(service)
+ service_item.properties = service_attrs
+ service_item.active = true if service == "kubernetes"
+ service_item.save
+ service_item
+ end
end
end
--
cgit v1.2.1
From 20f79920e584f70218c78ce7a2c9c42328020031 Mon Sep 17 00:00:00 2001
From: Alessio Caiazza
Date: Thu, 4 Jan 2018 10:29:16 +0100
Subject: Backport gitlab-org/gitlab-ci-yml!128 - Fix kubectl version to 1.8.6
This commit extracts `kubectl`, `helm` and `codeclimate` versions as CI
variables.
`kubectl` changes from latest stable version to `1.8.6`, the other two are just
extracted in order to be easily updated; now we can also test tool upgrades
overriding CI secret variables.
---
changelogs/unreleased/ac-autodevopfix-kubectl-version.yml | 5 +++++
vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 12 ++++++++----
2 files changed, 13 insertions(+), 4 deletions(-)
create mode 100644 changelogs/unreleased/ac-autodevopfix-kubectl-version.yml
diff --git a/changelogs/unreleased/ac-autodevopfix-kubectl-version.yml b/changelogs/unreleased/ac-autodevopfix-kubectl-version.yml
new file mode 100644
index 00000000000..0ceeb7ccee1
--- /dev/null
+++ b/changelogs/unreleased/ac-autodevopfix-kubectl-version.yml
@@ -0,0 +1,5 @@
+---
+title: Force Auto DevOps kubectl version to 1.8.6
+merge_request: 16218
+author:
+type: fixed
diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
index 18910a46d11..06473fba8e1 100644
--- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
+++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
@@ -34,6 +34,10 @@ variables:
POSTGRES_ENABLED: "true"
POSTGRES_DB: $CI_ENVIRONMENT_SLUG
+ KUBERNETES_VERSION: 1.8.6
+ HELM_VERSION: 2.6.1
+ CODECLIMATE_VERSION: 0.69.0
+
stages:
- build
- test
@@ -250,8 +254,8 @@ production:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume /tmp/cc:/tmp/cc"
- docker run ${cc_opts} codeclimate/codeclimate:0.69.0 init
- docker run ${cc_opts} codeclimate/codeclimate:0.69.0 analyze -f json > codeclimate.json
+ docker run ${cc_opts} "codeclimate/codeclimate:${CODECLIMATE_VERSION}" init
+ docker run ${cc_opts} "codeclimate/codeclimate:${CODECLIMATE_VERSION}" analyze -f json > codeclimate.json
}
function sast() {
@@ -323,11 +327,11 @@ production:
apk add glibc-2.23-r3.apk
rm glibc-2.23-r3.apk
- curl https://kubernetes-helm.storage.googleapis.com/helm-v2.6.1-linux-amd64.tar.gz | tar zx
+ curl "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx
mv linux-amd64/helm /usr/bin/
helm version --client
- curl -L -o /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
+ curl -L -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl"
chmod +x /usr/bin/kubectl
kubectl version --client
}
--
cgit v1.2.1
From 260935868acfb7c0cb720088d4f8c4c1c1088ddb Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Thu, 14 Dec 2017 11:49:35 +0100
Subject: add new git fsck rake task and spec
---
lib/tasks/gitlab/git.rake | 10 ++++++++++
spec/tasks/gitlab/git_rake_spec.rb | 27 +++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
create mode 100644 spec/tasks/gitlab/git_rake_spec.rb
diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake
index cf82134d97e..f3ffff43726 100644
--- a/lib/tasks/gitlab/git.rake
+++ b/lib/tasks/gitlab/git.rake
@@ -30,6 +30,16 @@ namespace :gitlab do
end
end
+ desc 'GitLab | Git | Check all repos integrity'
+ task fsck: :environment do
+ failures = perform_git_cmd(%W(#{Gitlab.config.git.bin_path} fsck --name-objects --no-progress), "Checking integrity")
+ if failures.empty?
+ puts "Done".color(:green)
+ else
+ output_failures(failures)
+ end
+ end
+
def perform_git_cmd(cmd, message)
puts "Starting #{message} on all repositories"
diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb
new file mode 100644
index 00000000000..63a7f7efe73
--- /dev/null
+++ b/spec/tasks/gitlab/git_rake_spec.rb
@@ -0,0 +1,27 @@
+require 'rake_helper'
+
+describe 'gitlab:git rake tasks' do
+ before do
+ Rake.application.rake_require 'tasks/gitlab/git'
+
+ stub_warn_user_is_not_gitlab
+
+ FileUtils.mkdir(Settings.absolute('tmp/tests/default_storage'))
+ end
+
+ after do
+ FileUtils.rm_rf(Settings.absolute('tmp/tests/default_storage'))
+ end
+
+ describe 'fsck' do
+ let(:storages) do
+ { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } }
+ end
+
+ it 'outputs the right git command' do
+ expect(Kernel).to receive(:system).with('').and_return(true)
+
+ run_rake_task('gitlab:git:fsck')
+ end
+ end
+end
--
cgit v1.2.1
From 7721e8dfca9d272376f58dcb03ff277aef0a9c31 Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Thu, 14 Dec 2017 14:53:34 +0100
Subject: fix spec
---
spec/tasks/gitlab/git_rake_spec.rb | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb
index 63a7f7efe73..60b51186ceb 100644
--- a/spec/tasks/gitlab/git_rake_spec.rb
+++ b/spec/tasks/gitlab/git_rake_spec.rb
@@ -4,9 +4,11 @@ describe 'gitlab:git rake tasks' do
before do
Rake.application.rake_require 'tasks/gitlab/git'
- stub_warn_user_is_not_gitlab
+ storages = { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } }
- FileUtils.mkdir(Settings.absolute('tmp/tests/default_storage'))
+ FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/repo/test.git'))
+ allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
+ stub_warn_user_is_not_gitlab
end
after do
@@ -14,14 +16,8 @@ describe 'gitlab:git rake tasks' do
end
describe 'fsck' do
- let(:storages) do
- { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } }
- end
-
it 'outputs the right git command' do
- expect(Kernel).to receive(:system).with('').and_return(true)
-
- run_rake_task('gitlab:git:fsck')
+ expect { run_rake_task('gitlab:git:fsck') }.to output(/Performed Checking integrity/).to_stdout
end
end
end
--
cgit v1.2.1
From bc46c822fc94cfa54a190cfb0e89afeae799f57a Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Thu, 21 Dec 2017 15:42:25 +0100
Subject: remove max-depth flag so it works with subgroups
---
lib/tasks/gitlab/task_helpers.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/tasks/gitlab/task_helpers.rb b/lib/tasks/gitlab/task_helpers.rb
index 6723662703c..c1182af1014 100644
--- a/lib/tasks/gitlab/task_helpers.rb
+++ b/lib/tasks/gitlab/task_helpers.rb
@@ -130,7 +130,7 @@ module Gitlab
def all_repos
Gitlab.config.repositories.storages.each_value do |repository_storage|
- IO.popen(%W(find #{repository_storage['path']} -mindepth 2 -maxdepth 2 -type d -name *.git)) do |find|
+ IO.popen(%W(find #{repository_storage['path']} -mindepth 2 -type d -name *.git)) do |find|
find.each_line do |path|
yield path.chomp
end
--
cgit v1.2.1
From f8e1b44dc5d2a78676672dfc7d44c17e6defeda6 Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Wed, 3 Jan 2018 14:51:04 +0100
Subject: add locks chek
---
lib/tasks/gitlab/git.rake | 26 +++++++++++++++++++++++++-
spec/tasks/gitlab/git_rake_spec.rb | 4 +++-
2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake
index f3ffff43726..5c1b19860f0 100644
--- a/lib/tasks/gitlab/git.rake
+++ b/lib/tasks/gitlab/git.rake
@@ -32,7 +32,10 @@ namespace :gitlab do
desc 'GitLab | Git | Check all repos integrity'
task fsck: :environment do
- failures = perform_git_cmd(%W(#{Gitlab.config.git.bin_path} fsck --name-objects --no-progress), "Checking integrity")
+ failures = perform_git_cmd(%W(#{Gitlab.config.git.bin_path} fsck --name-objects --no-progress), "Checking integrity") do |repo|
+ check_config_lock(repo)
+ check_ref_locks(repo)
+ end
if failures.empty?
puts "Done".color(:green)
else
@@ -50,6 +53,8 @@ namespace :gitlab do
else
failures << repo
end
+
+ yield(repo) if block_given?
end
failures
@@ -59,5 +64,24 @@ namespace :gitlab do
puts "The following repositories reported errors:".color(:red)
failures.each { |f| puts "- #{f}" }
end
+
+ def check_config_lock(repo_dir)
+ config_exists = File.exist?(File.join(repo_dir, 'config.lock'))
+ config_output = config_exists ? 'yes'.color(:red) : 'no'.color(:green)
+
+ puts "'config.lock' file exists?".color(:yellow) + " ... #{config_output}"
+ end
+
+ def check_ref_locks(repo_dir)
+ lock_files = Dir.glob(File.join(repo_dir, 'refs/heads/*.lock'))
+
+ if lock_files.present?
+ puts "Ref lock files exist:".color(:red)
+
+ lock_files.each { |lock_file| puts " #{lock_file}" }
+ else
+ puts "No ref lock files exist".color(:green)
+ end
+ end
end
end
diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb
index 60b51186ceb..19d298fb36d 100644
--- a/spec/tasks/gitlab/git_rake_spec.rb
+++ b/spec/tasks/gitlab/git_rake_spec.rb
@@ -1,3 +1,5 @@
+
+
require 'rake_helper'
describe 'gitlab:git rake tasks' do
@@ -6,7 +8,7 @@ describe 'gitlab:git rake tasks' do
storages = { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } }
- FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/repo/test.git'))
+ FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git'))
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
stub_warn_user_is_not_gitlab
end
--
cgit v1.2.1
From 5b9e7773766eebbe73bb400025de002962532a7c Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Wed, 3 Jan 2018 15:32:16 +0100
Subject: add lock specs
---
spec/tasks/gitlab/git_rake_spec.rb | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb
index 19d298fb36d..44a2607bea2 100644
--- a/spec/tasks/gitlab/git_rake_spec.rb
+++ b/spec/tasks/gitlab/git_rake_spec.rb
@@ -21,5 +21,18 @@ describe 'gitlab:git rake tasks' do
it 'outputs the right git command' do
expect { run_rake_task('gitlab:git:fsck') }.to output(/Performed Checking integrity/).to_stdout
end
+
+ it 'errors out about config.lock issues' do
+ FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/config.lock'))
+
+ expect { run_rake_task('gitlab:git:fsck') }.to output(/file exists\? ... yes/).to_stdout
+ end
+
+ it 'errors out about ref lock issues' do
+ FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/refs/heads'))
+ FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/refs/heads/blah.lock'))
+
+ expect { run_rake_task('gitlab:git:fsck') }.to output(/Ref lock files exist:/).to_stdout
+ end
end
end
--
cgit v1.2.1
From 6ee122c04ee8263dc1cb9dfddd010c5c0b587e8e Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Wed, 3 Jan 2018 16:11:17 +0100
Subject: deprecate check integrity task
---
lib/tasks/gitlab/check.rake | 41 ++---------------------------------------
1 file changed, 2 insertions(+), 39 deletions(-)
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index dfade1f3885..903e84359cd 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -387,14 +387,8 @@ namespace :gitlab do
namespace :repo do
desc "GitLab | Check the integrity of the repositories managed by GitLab"
task check: :environment do
- Gitlab.config.repositories.storages.each do |name, repository_storage|
- namespace_dirs = Dir.glob(File.join(repository_storage['path'], '*'))
-
- namespace_dirs.each do |namespace_dir|
- repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
- repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
- end
- end
+ puts "This task is deprecated. Please use gitlab:git:fsck instead".color(:red)
+ Rake::Task["gitlab:git:fsck"].execute
end
end
@@ -461,35 +455,4 @@ namespace :gitlab do
puts "FAIL. Please update gitlab-shell to #{required_version} from #{current_version}".color(:red)
end
end
-
- def check_repo_integrity(repo_dir)
- puts "\nChecking repo at #{repo_dir.color(:yellow)}"
-
- git_fsck(repo_dir)
- check_config_lock(repo_dir)
- check_ref_locks(repo_dir)
- end
-
- def git_fsck(repo_dir)
- puts "Running `git fsck`".color(:yellow)
- system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: repo_dir)
- end
-
- def check_config_lock(repo_dir)
- config_exists = File.exist?(File.join(repo_dir, 'config.lock'))
- config_output = config_exists ? 'yes'.color(:red) : 'no'.color(:green)
- puts "'config.lock' file exists?".color(:yellow) + " ... #{config_output}"
- end
-
- def check_ref_locks(repo_dir)
- lock_files = Dir.glob(File.join(repo_dir, 'refs/heads/*.lock'))
- if lock_files.present?
- puts "Ref lock files exist:".color(:red)
- lock_files.each do |lock_file|
- puts " #{lock_file}"
- end
- else
- puts "No ref lock files exist".color(:green)
- end
- end
end
--
cgit v1.2.1
From de36a8e27961d4c2af43d0ac2d700a391c245353 Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Thu, 4 Jan 2018 11:02:43 +0100
Subject: refactor spec, add docs
---
doc/administration/raketasks/check.md | 4 ++--
lib/tasks/gitlab/git.rake | 1 +
spec/tasks/gitlab/git_rake_spec.rb | 16 ++++++++--------
3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index c8b5434c068..7dabc014bad 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -34,13 +34,13 @@ This task loops through all repositories on the GitLab server and runs the
**Omnibus Installation**
```
-sudo gitlab-rake gitlab:repo:check
+sudo gitlab-rake gitlab:git:fsck
```
**Source Installation**
```bash
-sudo -u git -H bundle exec rake gitlab:repo:check RAILS_ENV=production
+sudo -u git -H bundle exec rake gitlab:git:fsck RAILS_ENV=production
```
### Check repositories for a specific user
diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake
index 5c1b19860f0..3f5dd2ae3b3 100644
--- a/lib/tasks/gitlab/git.rake
+++ b/lib/tasks/gitlab/git.rake
@@ -36,6 +36,7 @@ namespace :gitlab do
check_config_lock(repo)
check_ref_locks(repo)
end
+
if failures.empty?
puts "Done".color(:green)
else
diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb
index 44a2607bea2..dacc5dc5ae7 100644
--- a/spec/tasks/gitlab/git_rake_spec.rb
+++ b/spec/tasks/gitlab/git_rake_spec.rb
@@ -1,5 +1,3 @@
-
-
require 'rake_helper'
describe 'gitlab:git rake tasks' do
@@ -8,8 +6,10 @@ describe 'gitlab:git rake tasks' do
storages = { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } }
- FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git'))
+ FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@hashed/1/2/test.git'))
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
+ allow_any_instance_of(String).to receive(:color) { |string, _color| string }
+
stub_warn_user_is_not_gitlab
end
@@ -18,19 +18,19 @@ describe 'gitlab:git rake tasks' do
end
describe 'fsck' do
- it 'outputs the right git command' do
- expect { run_rake_task('gitlab:git:fsck') }.to output(/Performed Checking integrity/).to_stdout
+ it 'outputs the integrity check for a repo' do
+ expect { run_rake_task('gitlab:git:fsck') }.to output(/Performed Checking integrity at .*@hashed\/1\/2\/test.git/).to_stdout
end
it 'errors out about config.lock issues' do
- FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/config.lock'))
+ FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@hashed/1/2/test.git/config.lock'))
expect { run_rake_task('gitlab:git:fsck') }.to output(/file exists\? ... yes/).to_stdout
end
it 'errors out about ref lock issues' do
- FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/refs/heads'))
- FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/refs/heads/blah.lock'))
+ FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@hashed/1/2/test.git/refs/heads'))
+ FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@hashed/1/2/test.git/refs/heads/blah.lock'))
expect { run_rake_task('gitlab:git:fsck') }.to output(/Ref lock files exist:/).to_stdout
end
--
cgit v1.2.1
From 21d0a3a6c4ee78724e084f355da9e40c4243b036 Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Thu, 4 Jan 2018 11:19:11 +0100
Subject: add missing changelog
---
changelogs/unreleased/40228-verify-integrity-of-repositories.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 changelogs/unreleased/40228-verify-integrity-of-repositories.yml
diff --git a/changelogs/unreleased/40228-verify-integrity-of-repositories.yml b/changelogs/unreleased/40228-verify-integrity-of-repositories.yml
new file mode 100644
index 00000000000..261d48652db
--- /dev/null
+++ b/changelogs/unreleased/40228-verify-integrity-of-repositories.yml
@@ -0,0 +1,5 @@
+---
+title: Fix gitlab-rake gitlab:import:repos import schedule
+merge_request: 15931
+author:
+type: fixed
--
cgit v1.2.1
From 3b8cee95a7d62bce3b3890ff8618073958dc2fb0 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 4 Jan 2018 11:28:18 +0100
Subject: Fix cycle analytics specs
---
spec/lib/gitlab/cycle_analytics/events_spec.rb | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb
index 28ea7d4c303..38a47a159e1 100644
--- a/spec/lib/gitlab/cycle_analytics/events_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb
@@ -122,17 +122,18 @@ describe 'cycle analytics events' do
let(:stage) { :test }
let(:merge_request) { MergeRequest.first }
+
let!(:pipeline) do
create(:ci_pipeline,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha,
- project: context.project,
+ project: project,
head_pipeline_of: merge_request)
end
before do
- create(:ci_build, pipeline: pipeline, status: :success, author: user)
- create(:ci_build, pipeline: pipeline, status: :success, author: user)
+ create(:ci_build, :success, pipeline: pipeline, author: user)
+ create(:ci_build, :success, pipeline: pipeline, author: user)
pipeline.run!
pipeline.succeed!
@@ -219,17 +220,18 @@ describe 'cycle analytics events' do
describe '#staging_events' do
let(:stage) { :staging }
let(:merge_request) { MergeRequest.first }
+
let!(:pipeline) do
create(:ci_pipeline,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha,
- project: context.project,
+ project: project,
head_pipeline_of: merge_request)
end
before do
- create(:ci_build, pipeline: pipeline, status: :success, author: user)
- create(:ci_build, pipeline: pipeline, status: :success, author: user)
+ create(:ci_build, :success, pipeline: pipeline, author: user)
+ create(:ci_build, :success, pipeline: pipeline, author: user)
pipeline.run!
pipeline.succeed!
--
cgit v1.2.1
From 55137e200d9f9f8cdbdadc96cf098a088873e3f1 Mon Sep 17 00:00:00 2001
From: Joshua Lambert
Date: Thu, 4 Jan 2018 10:59:08 +0000
Subject: Include integration tests in CE/EE testing documentation
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 01d4a546b97..2b79f0825e2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -553,7 +553,7 @@ the feature you contribute through all of these steps.
1. Description explaining the relevancy (see following item)
1. Working and clean code that is commented where needed
-1. [Unit and system tests][testing] that pass on the CI server
+1. [Unit, integration, and system tests][testing] that pass on the CI server
1. Performance/scalability implications have been considered, addressed, and tested
1. [Documented][doc-styleguide] in the `/doc` directory
1. [Changelog entry added][changelog], if necessary
--
cgit v1.2.1
From e8acb3f11755811fca28d38bb0cbba44add7b0af Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 4 Jan 2018 12:09:14 +0100
Subject: Copy-edit end-to-end testing guide documentation
---
doc/development/testing_guide/end_to_end_tests.md | 34 ++++++++++++-----------
1 file changed, 18 insertions(+), 16 deletions(-)
diff --git a/doc/development/testing_guide/end_to_end_tests.md b/doc/development/testing_guide/end_to_end_tests.md
index 561547e1581..30efe3e3b76 100644
--- a/doc/development/testing_guide/end_to_end_tests.md
+++ b/doc/development/testing_guide/end_to_end_tests.md
@@ -23,24 +23,25 @@ You can find these nightly pipelines at [GitLab QA pipelines page][gitlab-qa-pip
It is also possible to trigger build of GitLab packages and then pass these
package to GitLab QA to run tests in a [pipeline][gitlab-qa-pipelines].
-Developers can trigger a `package-qa` manual action, that should be present in
-the merge request widget in your merge request.
+Developers can trigger the `package-qa` manual action, that should be present in
+the merge request widget.
-It is possible to trigger Gitlab QA pipeline from merge requests in GitLab CE
-and GitLab EE, but QA triggering manual action is also available in the Omnibus
-GitLab project as well.
+It is also possible to trigger Gitlab QA pipeline from merge requests in
+Omnibus GitLab project. You can find a manual action that is similar to
+`package-qa`, mentioned above, in your Omnibus-related merge requests as well.
Below you can read more about how to use it and how does it work.
#### How does it work?
-Currently, we are _multi-project pipeline_-like approach to run QA pipelines.
+Currently, we are using _multi-project pipeline_-like approach to run QA
+pipelines.
1. Developer triggers a manual action, that can be found in CE and EE merge
-requests, what starts a chain of pipelines.
+requests. This starts a chain of pipelines in multiple projects.
-1. The script, that is being executed, triggers a pipeline in GitLab Omnibus
-projects, and waits for the resulting status. We call this a _status attribution_.
+1. The script being executed triggers a pipeline in GitLab Omnibus and waits
+for the resulting status. We call this a _status attribution_.
1. GitLab packages are being built in Omnibus pipeline. Packages are going to be
pushed to Container Registry.
@@ -50,24 +51,25 @@ pipeline, that is now running in Omnibus, triggers a new pipeline in the GitLab
QA project. It also waits for a resulting status.
1. GitLab QA pulls images from the registry, spins-up containers and runs tests
-against a test environment that has been just orchestrated by `gitlab-qa` tool.
+against a test environment that has been just orchestrated by the `gitlab-qa`
+tool.
-1. The result of GitLab QA pipeline is being propagated upstream, through
+1. The result of the GitLab QA pipeline is being propagated upstream, through
Omnibus, back to CE / EE merge request.
#### How do I write tests?
In order to write new tests, you first need to learn more about GitLab QA
-architecture. There is some documentation about it in GitLab QA project
-[here][gitlab-qa-architecture].
+architecture. See the [documentation about it][gitlab-qa-architecture] in
+GitLab QA project.
-Once you decided were to put test environment orchestration scenarios and
-instance specs, take a looks at [relevant documentation][instance-qa-readme]
+Once you decided where to put test environment orchestration scenarios and
+instance specs, take a look at the [relevant documentation][instance-qa-readme]
and examples in [the `qa/` directory][instance-qa-examples].
## Where can I ask for help?
-You can ask question in `#qa` channel on Slack (GitLab internal) or you can
+You can ask question in the `#qa` channel on Slack (GitLab internal) or you can
find an issue you would like to work on in [the issue tracker][gitlab-qa-issues]
and start a new discussion there.
--
cgit v1.2.1
From 0ba0f9de08eb3d5113f4557b925506167484950a Mon Sep 17 00:00:00 2001
From: Ahmad Sherif
Date: Wed, 3 Jan 2018 13:31:06 +0100
Subject: Prepare Gitlab::Git::Repository#rebase for Gitaly migration
---
lib/gitlab/git/operation_service.rb | 5 +++++
lib/gitlab/git/repository.rb | 9 ++++++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb
index ef5bdbaf819..3fb0e2eed93 100644
--- a/lib/gitlab/git/operation_service.rb
+++ b/lib/gitlab/git/operation_service.rb
@@ -97,6 +97,11 @@ module Gitlab
end
end
+ def update_branch(branch_name, newrev, oldrev)
+ ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
+ update_ref_in_hooks(ref, newrev, oldrev)
+ end
+
private
# Returns [newrev, should_run_after_create, should_run_after_create_branch]
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 176bd953ca1..7c6349f4e84 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -1212,9 +1212,16 @@ module Gitlab
rebase_path = worktree_path(REBASE_WORKTREE_PREFIX, rebase_id)
env = git_env_for_user(user)
+ if remote_repository.is_a?(RemoteRepository)
+ env.merge!(remote_repository.fetch_env)
+ remote_repo_path = GITALY_INTERNAL_URL
+ else
+ remote_repo_path = remote_repository.path
+ end
+
with_worktree(rebase_path, branch, env: env) do
run_git!(
- %W(pull --rebase #{remote_repository.path} #{remote_branch}),
+ %W(pull --rebase #{remote_repo_path} #{remote_branch}),
chdir: rebase_path, env: env
)
--
cgit v1.2.1
From 88cc49fa17d212e087f6e8a5aec0b2a680cec6e3 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 4 Jan 2018 13:00:02 +0100
Subject: Add test for restoring associations with import/export
---
spec/lib/gitlab/import_export/project.json | 26 ++++++++++++++++++++--
.../import_export/project_tree_restorer_spec.rb | 12 ++++++++++
2 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index f0752649121..6778b23ee7f 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -6465,6 +6465,26 @@
}
}
],
+ "stages": [
+ {
+ "id": 11,
+ "project_id": 5,
+ "pipeline_id": 36,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z"
+ },
+ {
+ "id": 12,
+ "project_id": 5,
+ "pipeline_id": 36,
+ "name": "deploy",
+ "status": 2,
+ "created_at": "2016-03-22T15:45:45.772Z",
+ "updated_at": "2016-03-29T06:45:45.634Z"
+ }
+ ],
"statuses": [
{
"id": 71,
@@ -6487,6 +6507,7 @@
"stage": "test",
"trigger_request_id": null,
"stage_idx": 1,
+ "stage_id": 11,
"tag": null,
"ref": "master",
"user_id": null,
@@ -6515,15 +6536,16 @@
"runner_id": null,
"coverage": null,
"commit_id": 36,
- "commands": "$ build command",
+ "commands": "$ deploy command",
"job_id": null,
"name": "test build 2",
"deploy": false,
"options": null,
"allow_failure": false,
- "stage": "test",
+ "stage": "deploy",
"trigger_request_id": null,
"stage_idx": 1,
+ "stage_id": 12,
"tag": null,
"ref": "master",
"user_id": null,
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 0ab3afd0074..d4342f2b1a8 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -179,6 +179,18 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
end
end
+
+ context 'when restoring hierarchy of pipeline, stages and jobs' do
+ let(:pipeline) { Ci::Pipeline.first }
+
+ it 'restores pipeline stages' do
+ expect(pipeline.stages.count).to be 2
+ end
+
+ it 'correctly restores association between a stage and a job' do
+ expect(pipeline.statuses).to all(have_attributes(stage_id: a_value > 10))
+ end
+ end
end
end
--
cgit v1.2.1
From 099a59e8fd461a01b1b4f84583b46b4c7d6888e9 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 4 Jan 2018 13:11:24 +0100
Subject: Check if stage_id relation has been assigned only
---
spec/lib/gitlab/import_export/project_tree_restorer_spec.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index d4342f2b1a8..70a6d1a3c6a 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -188,7 +188,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
it 'correctly restores association between a stage and a job' do
- expect(pipeline.statuses).to all(have_attributes(stage_id: a_value > 10))
+ expect(pipeline.statuses).to all(have_attributes(stage_id: a_value > 0))
end
end
end
--
cgit v1.2.1
From ebdcbd4552b16b8aacaaaf0bdc1c600685d4e696 Mon Sep 17 00:00:00 2001
From: Alessio Caiazza
Date: Wed, 3 Jan 2018 09:57:48 +0100
Subject: Do not run ee_compat_check on security branches
Branches started from `security-X-Y` will likely fail on `ee_compat_check`,
the check tries to merge against EE `master` which may likely fail for MR that
are not targetted on `master`, like security fixes.
This commit disables `ee_compat_check` on branches starting with `security-`.
---
.gitlab-ci.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e98ac200332..038eeb2bf61 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -431,6 +431,7 @@ ee_compat_check:
- master
- tags
- /^[\d-]+-stable(-ee)?/
+ - /^security-/
- branches@gitlab-org/gitlab-ee
- branches@gitlab/gitlab-ee
retry: 0
--
cgit v1.2.1
From dac51ace521d7b2b2a5a5bb19167a8690ead242e Mon Sep 17 00:00:00 2001
From: Yorick Peterse
Date: Wed, 3 Jan 2018 17:44:29 +0100
Subject: Eager load event target authors whenever possible
This ensures that the "author" association of an event's "target"
association is eager loaded whenever the "target" association defines an
"author" association. This in turn solves the N+1 query problem we first
tried to solve in
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15788 but caused
problems when displaying milestones as those don't define an "author"
association.
The approach in this commit does mean that the authors are _always_
eager loaded since this takes place in the "belongs_to" block. This
however shouldn't pose too much of a problem, and as far as I can tell
there's no real way around this unfortunately.
---
app/models/event.rb | 13 ++++++++++++-
.../conditionally-eager-load-event-target-authors.yml | 5 +++++
spec/features/dashboard/activity_spec.rb | 7 +++++++
spec/models/event_spec.rb | 16 ++++++++++++++++
4 files changed, 40 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/conditionally-eager-load-event-target-authors.yml
diff --git a/app/models/event.rb b/app/models/event.rb
index 0997b056c6a..8a79100de5a 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -48,7 +48,18 @@ class Event < ActiveRecord::Base
belongs_to :author, class_name: "User"
belongs_to :project
- belongs_to :target, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
+
+ belongs_to :target, -> {
+ # If the association for "target" defines an "author" association we want to
+ # eager-load this so Banzai & friends don't end up performing N+1 queries to
+ # get the authors of notes, issues, etc.
+ if reflections['events'].active_record.reflect_on_association(:author)
+ includes(:author)
+ else
+ self
+ end
+ }, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
+
has_one :push_event_payload
# Callbacks
diff --git a/changelogs/unreleased/conditionally-eager-load-event-target-authors.yml b/changelogs/unreleased/conditionally-eager-load-event-target-authors.yml
new file mode 100644
index 00000000000..a5f1a958fa8
--- /dev/null
+++ b/changelogs/unreleased/conditionally-eager-load-event-target-authors.yml
@@ -0,0 +1,5 @@
+---
+title: Eager load event target authors whenever possible
+merge_request:
+author:
+type: performance
diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb
index bd115785646..a74a8aac2b2 100644
--- a/spec/features/dashboard/activity_spec.rb
+++ b/spec/features/dashboard/activity_spec.rb
@@ -24,6 +24,7 @@ feature 'Dashboard > Activity' do
end
let(:note) { create(:note, project: project, noteable: merge_request) }
+ let(:milestone) { create(:milestone, :active, project: project, title: '1.0') }
let!(:push_event) do
event = create(:push_event, project: project, author: user)
@@ -54,6 +55,10 @@ feature 'Dashboard > Activity' do
create(:event, :commented, project: project, target: note, author: user)
end
+ let!(:milestone_event) do
+ create(:event, :closed, project: project, target: milestone, author: user)
+ end
+
before do
project.add_master(user)
@@ -68,6 +73,7 @@ feature 'Dashboard > Activity' do
expect(page).to have_content('accepted')
expect(page).to have_content('closed')
expect(page).to have_content('commented on')
+ expect(page).to have_content('closed milestone')
end
end
@@ -107,6 +113,7 @@ feature 'Dashboard > Activity' do
expect(page).not_to have_content('accepted')
expect(page).to have_content('closed')
expect(page).not_to have_content('commented on')
+ expect(page).to have_content('closed milestone')
end
end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index e999192940c..67f49348acb 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -347,6 +347,22 @@ describe Event do
end
end
+ describe '#target' do
+ it 'eager loads the author of an event target' do
+ create(:closed_issue_event)
+
+ events = described_class.preload(:target).all.to_a
+ count = ActiveRecord::QueryRecorder
+ .new { events.first.target.author }.count
+
+ # This expectation exists to make sure the test doesn't pass when the
+ # author is for some reason not loaded at all.
+ expect(events.first.target.author).to be_an_instance_of(User)
+
+ expect(count).to be_zero
+ end
+ end
+
def create_push_event(project, user)
event = create(:push_event, project: project, author: user)
--
cgit v1.2.1
From e1f0d23c898d9133e36afec868abdcef4fb4e8e8 Mon Sep 17 00:00:00 2001
From: Jacob Schatz
Date: Thu, 4 Jan 2018 08:44:27 -0500
Subject: Moves prettier to dev dependency
---
package.json | 2 +-
yarn.lock | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package.json b/package.json
index 8c3932dccfd..3587b015fb3 100644
--- a/package.json
+++ b/package.json
@@ -61,7 +61,6 @@
"mousetrap": "^1.4.6",
"name-all-modules-plugin": "^1.0.1",
"pikaday": "^1.6.1",
- "prettier": "^1.9.2",
"prismjs": "^1.6.0",
"raphael": "^2.2.7",
"raven-js": "^3.14.0",
@@ -109,6 +108,7 @@
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.4",
"nodemon": "^1.11.0",
+ "prettier": "1.9.2",
"webpack-dev-server": "^2.6.1"
}
}
diff --git a/yarn.lock b/yarn.lock
index 381b1a243f8..b29fc022bde 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5146,14 +5146,14 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+prettier@1.9.2:
+ version "1.9.2"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.9.2.tgz#96bc2132f7a32338e6078aeb29727178c6335827"
+
prettier@^1.7.0:
version "1.8.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8"
-prettier@^1.9.2:
- version "1.9.2"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.9.2.tgz#96bc2132f7a32338e6078aeb29727178c6335827"
-
prismjs@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.6.0.tgz#118d95fb7a66dba2272e343b345f5236659db365"
--
cgit v1.2.1
From 528b5eeb761f627bb1972fa8a25a09dc1cea4556 Mon Sep 17 00:00:00 2001
From: Sean McGivern
Date: Wed, 3 Jan 2018 14:18:13 +0000
Subject: Fix error when viewing diffs without blobs
Old merge requests can have diffs without corresponding blobs. (This also may be
possible for commit diffs in corrupt repositories.)
We can't use the `&.` operator on the blobs, because the blob objects are never
nil, but `BatchLoader` instances that delegate to `Blob`. We can't use
`Object#try`, because `Blob` doesn't inherit from `Object`.
`BatchLoader` provides a `__sync` method that returns the delegated object, but
using `itself` also works because it's forwarded, and will work for
non-`BatchLoader` instances too. So the simplest solution is to just use that
with the `&.` operator.
---
...on-undefined-method-binary-for-nil-nilclass.yml | 5 ++++
lib/gitlab/diff/file.rb | 31 ++++++++++++++++------
spec/lib/gitlab/diff/file_spec.rb | 25 +++++++++++++++++
3 files changed, 53 insertions(+), 8 deletions(-)
create mode 100644 changelogs/unreleased/41468-error-500-trying-to-view-a-merge-request-json-undefined-method-binary-for-nil-nilclass.yml
diff --git a/changelogs/unreleased/41468-error-500-trying-to-view-a-merge-request-json-undefined-method-binary-for-nil-nilclass.yml b/changelogs/unreleased/41468-error-500-trying-to-view-a-merge-request-json-undefined-method-binary-for-nil-nilclass.yml
new file mode 100644
index 00000000000..f69116382f0
--- /dev/null
+++ b/changelogs/unreleased/41468-error-500-trying-to-view-a-merge-request-json-undefined-method-binary-for-nil-nilclass.yml
@@ -0,0 +1,5 @@
+---
+title: Fix viewing merge request diffs where the underlying blobs are unavailable
+merge_request:
+author:
+type: fixed
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index cd490aaa291..34b070dd375 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -116,8 +116,10 @@ module Gitlab
new_content_sha || old_content_sha
end
+ # Use #itself to check the value wrapped by a BatchLoader instance, rather
+ # than if the BatchLoader instance itself is falsey.
def blob
- new_blob || old_blob
+ new_blob&.itself || old_blob&.itself
end
attr_writer :highlighted_diff_lines
@@ -173,7 +175,7 @@ module Gitlab
end
def binary?
- has_binary_notice? || old_blob&.binary? || new_blob&.binary?
+ has_binary_notice? || try_blobs(:binary?)
end
def text?
@@ -181,15 +183,15 @@ module Gitlab
end
def external_storage_error?
- old_blob&.external_storage_error? || new_blob&.external_storage_error?
+ try_blobs(:external_storage_error?)
end
def stored_externally?
- old_blob&.stored_externally? || new_blob&.stored_externally?
+ try_blobs(:stored_externally?)
end
def external_storage
- old_blob&.external_storage || new_blob&.external_storage
+ try_blobs(:external_storage)
end
def content_changed?
@@ -204,15 +206,15 @@ module Gitlab
end
def size
- [old_blob&.size, new_blob&.size].compact.sum
+ valid_blobs.map(&:size).sum
end
def raw_size
- [old_blob&.raw_size, new_blob&.raw_size].compact.sum
+ valid_blobs.map(&:raw_size).sum
end
def raw_binary?
- old_blob&.raw_binary? || new_blob&.raw_binary?
+ try_blobs(:raw_binary?)
end
def raw_text?
@@ -235,6 +237,19 @@ module Gitlab
private
+ # The blob instances are instances of BatchLoader, which means calling
+ # &. directly on them won't work. Object#try also won't work, because Blob
+ # doesn't inherit from Object, but from BasicObject (via SimpleDelegator).
+ def try_blobs(meth)
+ old_blob&.itself&.public_send(meth) || new_blob&.itself&.public_send(meth)
+ end
+
+ # We can't use #compact for the same reason we can't use &., but calling
+ # #nil? explicitly does work because it is proxied to the blob itself.
+ def valid_blobs
+ [old_blob, new_blob].reject(&:nil?)
+ end
+
def text_position_properties(line)
{ old_line: line.old_line, new_line: line.new_line }
end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index ff9acfd08b9..9204ea37963 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -431,4 +431,29 @@ describe Gitlab::Diff::File do
end
end
end
+
+ context 'when neither blob exists' do
+ let(:blank_diff_refs) { Gitlab::Diff::DiffRefs.new(base_sha: Gitlab::Git::BLANK_SHA, head_sha: Gitlab::Git::BLANK_SHA) }
+ let(:diff_file) { described_class.new(diff, diff_refs: blank_diff_refs, repository: project.repository) }
+
+ describe '#blob' do
+ it 'returns a concrete nil so it can be used in boolean expressions' do
+ actual = diff_file.blob && true
+
+ expect(actual).to be_nil
+ end
+ end
+
+ describe '#binary?' do
+ it 'returns false' do
+ expect(diff_file).not_to be_binary
+ end
+ end
+
+ describe '#size' do
+ it 'returns zero' do
+ expect(diff_file.size).to be_zero
+ end
+ end
+ end
end
--
cgit v1.2.1
From b5fe3916752aafd5c79b2aa7a770fbd51f1b4bef Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Thu, 4 Jan 2018 15:44:00 +0100
Subject: Update some Gitaly annotations in Gitlab::Shell
---
lib/gitlab/shell.rb | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 9cdd3d22f18..18da242e1cb 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -71,7 +71,6 @@ module Gitlab
# Ex.
# add_repository("/path/to/storage", "gitlab/gitlab-ci")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def add_repository(storage, name)
relative_path = name.dup
relative_path << '.git' unless relative_path.end_with?('.git')
@@ -100,7 +99,7 @@ module Gitlab
# Ex.
# import_repository("/path/to/storage", "gitlab/gitlab-ci", "https://gitlab.com/gitlab-org/gitlab-test.git")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/874
def import_repository(storage, name, url)
# The timeout ensures the subprocess won't hang forever
cmd = gitlab_projects(storage, "#{name}.git")
@@ -122,7 +121,6 @@ module Gitlab
# Ex.
# fetch_remote(my_repo, "upstream")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false)
gitaly_migrate(:fetch_remote) do |is_enabled|
if is_enabled
@@ -142,7 +140,7 @@ module Gitlab
# Ex.
# mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/873
def mv_repository(storage, path, new_path)
gitlab_projects(storage, "#{path}.git").mv_project("#{new_path}.git")
end
@@ -156,7 +154,7 @@ module Gitlab
# Ex.
# fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "new-namespace/gitlab-ci")
#
- # Gitaly note: JV: not easy to migrate because this involves two Gitaly servers, not one.
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/817
def fork_repository(forked_from_storage, forked_from_disk_path, forked_to_storage, forked_to_disk_path)
gitlab_projects(forked_from_storage, "#{forked_from_disk_path}.git")
.fork_repository(forked_to_storage, "#{forked_to_disk_path}.git")
@@ -170,7 +168,7 @@ module Gitlab
# Ex.
# remove_repository("/path/to/storage", "gitlab/gitlab-ci")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/873
def remove_repository(storage, name)
gitlab_projects(storage, "#{name}.git").rm_project
end
@@ -221,7 +219,6 @@ module Gitlab
# Ex.
# add_namespace("/path/to/storage", "gitlab")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def add_namespace(storage, name)
Gitlab::GitalyClient.migrate(:add_namespace) do |enabled|
if enabled
@@ -243,7 +240,6 @@ module Gitlab
# Ex.
# rm_namespace("/path/to/storage", "gitlab")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def rm_namespace(storage, name)
Gitlab::GitalyClient.migrate(:remove_namespace) do |enabled|
if enabled
@@ -261,7 +257,6 @@ module Gitlab
# Ex.
# mv_namespace("/path/to/storage", "gitlab", "gitlabhq")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def mv_namespace(storage, old_name, new_name)
Gitlab::GitalyClient.migrate(:rename_namespace) do |enabled|
if enabled
--
cgit v1.2.1
From 44d15e414348ab7befaa22636b85d1c0d9064d08 Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Thu, 4 Jan 2018 16:34:37 +0100
Subject: get it working
---
lib/gitlab/import_export/command_line_util.rb | 4 ++++
lib/gitlab/import_export/repo_restorer.rb | 4 +++-
lib/gitlab/shell.rb | 4 ++++
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb
index 0135b3c6f22..349f17cf0f8 100644
--- a/lib/gitlab/import_export/command_line_util.rb
+++ b/lib/gitlab/import_export/command_line_util.rb
@@ -15,6 +15,10 @@ module Gitlab
execute(%W(#{git_bin_path} --git-dir=#{repo_path} bundle create #{bundle_path} --all))
end
+ def git_clone_bundle(repo_path:, bundle_path:)
+ execute(%W(#{git_bin_path} clone --bare -- #{bundle_path} #{repo_path}))
+ end
+
def mkdir_p(path)
FileUtils.mkdir_p(path, mode: DEFAULT_MODE)
FileUtils.chmod(DEFAULT_MODE, path)
diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb
index 32ca2809b2f..a7e00c71990 100644
--- a/lib/gitlab/import_export/repo_restorer.rb
+++ b/lib/gitlab/import_export/repo_restorer.rb
@@ -13,7 +13,9 @@ module Gitlab
def restore
return true unless File.exist?(@path_to_bundle)
- gitlab_shell.import_repository(@project.repository_storage_path, @project.disk_path, @path_to_bundle)
+ repo_path = @project.repository.path_to_repo
+ git_clone_bundle(repo_path: repo_path, bundle_path: @path_to_bundle)
+ Gitlab::Git::Repository.create_hooks(repo_path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path))
rescue => e
@shared.error(e)
false
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 9cdd3d22f18..1d0eae28f82 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -102,6 +102,10 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def import_repository(storage, name, url)
+ if url.start_with?('.') || url.start_with?('/')
+ raise Error.new("don't use disk paths with import_repository: #{url.inspect}")
+ end
+
# The timeout ensures the subprocess won't hang forever
cmd = gitlab_projects(storage, "#{name}.git")
success = cmd.import_project(url, git_timeout)
--
cgit v1.2.1
From 80242f246b69a803120bc06527b80601fafc526c Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Thu, 4 Jan 2018 16:37:18 +0100
Subject: Hide hooks stuff
---
lib/gitlab/import_export/command_line_util.rb | 1 +
lib/gitlab/import_export/repo_restorer.rb | 4 +---
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb
index 349f17cf0f8..dd5d35feab9 100644
--- a/lib/gitlab/import_export/command_line_util.rb
+++ b/lib/gitlab/import_export/command_line_util.rb
@@ -17,6 +17,7 @@ module Gitlab
def git_clone_bundle(repo_path:, bundle_path:)
execute(%W(#{git_bin_path} clone --bare -- #{bundle_path} #{repo_path}))
+ Gitlab::Git::Repository.create_hooks(repo_path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path))
end
def mkdir_p(path)
diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb
index a7e00c71990..d0e5cfcfd3e 100644
--- a/lib/gitlab/import_export/repo_restorer.rb
+++ b/lib/gitlab/import_export/repo_restorer.rb
@@ -13,9 +13,7 @@ module Gitlab
def restore
return true unless File.exist?(@path_to_bundle)
- repo_path = @project.repository.path_to_repo
- git_clone_bundle(repo_path: repo_path, bundle_path: @path_to_bundle)
- Gitlab::Git::Repository.create_hooks(repo_path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path))
+ git_clone_bundle(repo_path: @project.repository.path_to_repo, bundle_path: @path_to_bundle)
rescue => e
@shared.error(e)
false
--
cgit v1.2.1
From e28bf81e9aa2b00452e71e9e8dd5f485c541e7d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Coutable?=
Date: Thu, 4 Jan 2018 16:37:21 +0100
Subject: Rename db:seed_fu-{pg,mysql} to gitlab:setup-{pg,mysql}
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Rémy Coutable
---
.gitlab-ci.yml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e98ac200332..82bc62bc0ab 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -508,7 +508,7 @@ db:rollback-mysql:
<<: *db-rollback
<<: *use-mysql
-.db-seed_fu: &db-seed_fu
+.gitlab-setup: &gitlab-setup
<<: *dedicated-runner
<<: *except-docs-and-qa
<<: *pull-cache
@@ -529,12 +529,12 @@ db:rollback-mysql:
paths:
- log/development.log
-db:seed_fu-pg:
- <<: *db-seed_fu
+gitlab:setup-pg:
+ <<: *gitlab-setup
<<: *use-pg
-db:seed_fu-mysql:
- <<: *db-seed_fu
+gitlab:setup-mysql:
+ <<: *gitlab-setup
<<: *use-mysql
# Frontend-related jobs
--
cgit v1.2.1
From 3df6fa6c05ad86f1bc861a8f38d8096098110e37 Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Thu, 4 Jan 2018 21:33:25 +0530
Subject: Enclose props in quotes
---
app/assets/javascripts/groups/components/item_stats.vue | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index 803dc63d39c..3a94e57a028 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -43,27 +43,27 @@ export default {
css-class="number-subgroups"
icon-name="folder"
:title="s__('Subgroups')"
- :value=item.subgroupCount
+ :value="item.subgroupCount"
/>
Date: Thu, 4 Jan 2018 21:47:40 +0530
Subject: Use `__` instead of `s__` when context is not required
---
app/assets/javascripts/groups/components/item_stats.vue | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index 3a94e57a028..2e42fb6c9a6 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -42,21 +42,21 @@ export default {
v-if="isGroup"
css-class="number-subgroups"
icon-name="folder"
- :title="s__('Subgroups')"
+ :title="__('Subgroups')"
:value="item.subgroupCount"
/>
Date: Tue, 2 Jan 2018 12:57:28 -0500
Subject: Remove downcase from special path helper
---
app/helpers/projects_helper.rb | 2 +-
changelogs/unreleased/jramsay-41590-add-readme-case.yml | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/jramsay-41590-add-readme-case.yml
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 4a6b22b5ff6..f7bdcc6fd9c 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -389,7 +389,7 @@ module ProjectsHelper
end
def add_special_file_path(project, file_name:, commit_message: nil, branch_name: nil, context: nil)
- commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name.downcase }
+ commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name }
project_new_blob_path(
project,
project.default_branch || 'master',
diff --git a/changelogs/unreleased/jramsay-41590-add-readme-case.yml b/changelogs/unreleased/jramsay-41590-add-readme-case.yml
new file mode 100644
index 00000000000..37b2bd44e0e
--- /dev/null
+++ b/changelogs/unreleased/jramsay-41590-add-readme-case.yml
@@ -0,0 +1,5 @@
+---
+title: Fix inconsistent downcase of filenames in prefilled `Add` commit messages
+merge_request: 16232
+author: James Ramsay
+type: fixed
--
cgit v1.2.1
From 0a02b0d8eada41b72d19bee3f963d7cee5b19c57 Mon Sep 17 00:00:00 2001
From: Gauthier Wallet
Date: Thu, 4 Jan 2018 16:26:14 +0000
Subject: Update settings.md
---
doc/api/settings.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 0e4758cda2d..0b5b1f0c134 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -69,7 +69,7 @@ PUT /application/settings
| `after_sign_up_text` | string | no | Text shown to the user after signing up |
| `akismet_api_key` | string | no | API key for akismet spam protection |
| `akismet_enabled` | boolean | no | Enable or disable akismet spam protection |
-| `circuitbreaker_access_retries | integer | no | The number of attempts GitLab will make to access a storage. |
+| `circuitbreaker_access_retries` | integer | no | The number of attempts GitLab will make to access a storage. |
| `circuitbreaker_check_interval` | integer | no | Number of seconds in between storage checks. |
| `circuitbreaker_failure_count_threshold` | integer | no | The number of failures of after which GitLab will completely prevent access to the storage. |
| `circuitbreaker_failure_reset_time` | integer | no | Time in seconds GitLab will keep storage failure information. When no failures occur during this time, the failure information is reset. |
--
cgit v1.2.1
From ac2cb65ab3dc2688b3a1db9de661dc01ed196177 Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Thu, 4 Jan 2018 18:00:28 +0100
Subject: Remove the Commit#tree method
---
app/models/commit.rb | 2 +-
lib/gitlab/git/blob.rb | 4 ++--
lib/gitlab/git/commit.rb | 7 +++++--
spec/lib/gitlab/git/blob_spec.rb | 4 ++--
spec/lib/gitlab/git/commit_spec.rb | 1 -
spec/models/commit_spec.rb | 1 -
6 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 2be07ca7d3c..39d7f5b159d 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -371,7 +371,7 @@ class Commit
#
# Returns a symbol
def uri_type(path)
- entry = @raw.tree.path(path)
+ entry = @raw.rugged_tree_entry(path)
if entry[:type] == :blob
blob = ::Blob.decorate(Gitlab::Git::Blob.new(name: entry[:name]), @project)
blob.image? || blob.video? ? :raw : :blob
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index 228d97a87ab..c4caa306b5d 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -154,8 +154,8 @@ module Gitlab
end
def find_by_rugged(repository, sha, path, limit:)
- commit = repository.lookup(sha)
- root_tree = commit.tree
+ rugged_commit = repository.lookup(sha)
+ root_tree = rugged_commit.tree
blob_entry = find_entry_by_path(repository, root_tree.oid, path)
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index 145721dea76..016437b2419 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -15,8 +15,6 @@ module Gitlab
attr_accessor *SERIALIZE_KEYS # rubocop:disable Lint/AmbiguousOperator
- delegate :tree, to: :rugged_commit
-
def ==(other)
return false unless other.is_a?(Gitlab::Git::Commit)
@@ -452,6 +450,11 @@ module Gitlab
)
end
+ # Is this the same as Blob.find_entry_by_path ?
+ def rugged_tree_entry(path)
+ rugged_commit.tree.path(path)
+ end
+
private
def init_from_hash(hash)
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index c04a9688503..67838163b05 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -146,7 +146,7 @@ describe Gitlab::Git::Blob, seed_helper: true do
context 'when sha references a tree' do
it 'returns nil' do
- tree = Gitlab::Git::Commit.find(repository, 'master').tree
+ tree = repository.rugged.rev_parse('master^{tree}')
blob = Gitlab::Git::Blob.raw(repository, tree.oid)
@@ -237,7 +237,7 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
describe '.batch_lfs_pointers' do
- let(:tree_object) { Gitlab::Git::Commit.find(repository, 'master').tree }
+ let(:tree_object) { repository.rugged.rev_parse('master^{tree}') }
let(:non_lfs_blob) do
Gitlab::Git::Blob.find(
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 6d35734d306..6a07a3ca8b8 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -55,7 +55,6 @@ describe Gitlab::Git::Commit, seed_helper: true do
it { expect(@commit.parents).to eq(@gitlab_parents) }
it { expect(@commit.parent_id).to eq(@parents.first.oid) }
it { expect(@commit.no_commit_message).to eq("--no commit message") }
- it { expect(@commit.tree).to eq(@tree) }
after do
# Erase the new commit so other tests get the original repo
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 4f02dc33cd8..817254c7d1e 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -181,7 +181,6 @@ eos
it { is_expected.to respond_to(:parents) }
it { is_expected.to respond_to(:date) }
it { is_expected.to respond_to(:diffs) }
- it { is_expected.to respond_to(:tree) }
it { is_expected.to respond_to(:id) }
it { is_expected.to respond_to(:to_patch) }
end
--
cgit v1.2.1
From dcebe1494e35fcd8870b38f311c5176eab6b2a2f Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Thu, 4 Jan 2018 18:05:49 +0100
Subject: rubocop
---
lib/gitlab/shell.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 1d0eae28f82..bef944ef1f9 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -102,7 +102,7 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def import_repository(storage, name, url)
- if url.start_with?('.') || url.start_with?('/')
+ if url.start_with?('.', '/')
raise Error.new("don't use disk paths with import_repository: #{url.inspect}")
end
--
cgit v1.2.1
From 176b60d11055999d56e30b6fe0581fbede2740c4 Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Thu, 4 Jan 2018 18:38:39 +0100
Subject: Remove the Project#repo method
---
app/controllers/projects_controller.rb | 2 +-
app/models/project.rb | 6 +-----
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 6f609348402..6f229b08c0c 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -353,7 +353,7 @@ class ProjectsController < Projects::ApplicationController
end
def repo_exists?
- project.repository_exists? && !project.empty_repo? && project.repo
+ project.repository_exists? && !project.empty_repo?
rescue Gitlab::Git::Repository::NoRepository
project.repository.expire_exists_cache
diff --git a/app/models/project.rb b/app/models/project.rb
index 9c0bbf697e2..4784bbc8a44 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -992,10 +992,6 @@ class Project < ActiveRecord::Base
false
end
- def repo
- repository.rugged
- end
-
def url_to_repo
gitlab_shell.url_to_repo(full_path)
end
@@ -1438,7 +1434,7 @@ class Project < ActiveRecord::Base
# We'd need to keep track of project full path otherwise directory tree
# created with hashed storage enabled cannot be usefully imported using
# the import rake task.
- repo.config['gitlab.fullpath'] = gl_full_path
+ repository.rugged.config['gitlab.fullpath'] = gl_full_path
rescue Gitlab::Git::Repository::NoRepository => e
Rails.logger.error("Error writing to .git/config for project #{full_path} (#{id}): #{e.message}.")
nil
--
cgit v1.2.1
From e3f215f676488d74ff8ed61dea8e715e73db2934 Mon Sep 17 00:00:00 2001
From: Mike Greiling
Date: Thu, 4 Jan 2018 12:25:48 -0600
Subject: fix missing import of timeWeek which would cause errors in prometheus
graphs with deployments
---
.../javascripts/monitoring/utils/date_time_formatters.js | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/app/assets/javascripts/monitoring/utils/date_time_formatters.js b/app/assets/javascripts/monitoring/utils/date_time_formatters.js
index 48bdec1e030..068813ddee6 100644
--- a/app/assets/javascripts/monitoring/utils/date_time_formatters.js
+++ b/app/assets/javascripts/monitoring/utils/date_time_formatters.js
@@ -1,8 +1,18 @@
import { timeFormat as time } from 'd3-time-format';
-import { timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear } from 'd3-time';
+import { timeSecond, timeMinute, timeHour, timeDay, timeWeek, timeMonth, timeYear } from 'd3-time';
import { bisector } from 'd3-array';
-const d3 = { time, bisector, timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear };
+const d3 = {
+ time,
+ bisector,
+ timeSecond,
+ timeMinute,
+ timeHour,
+ timeDay,
+ timeWeek,
+ timeMonth,
+ timeYear,
+};
export const dateFormat = d3.time('%b %-d, %Y');
export const timeFormat = d3.time('%-I:%M%p');
--
cgit v1.2.1
From 0a35f372d232a0ac6b9355d27a9fb9e95b1ee959 Mon Sep 17 00:00:00 2001
From: Jose Ivan Vargas
Date: Thu, 4 Jan 2018 18:31:05 +0000
Subject: Added multi editor setting on the profile preferences page
---
app/assets/images/multi-editor-off.png | Bin 0 -> 4884 bytes
app/assets/images/multi-editor-on.png | Bin 0 -> 5464 bytes
app/assets/javascripts/profile/profile.js | 21 +++++++++++++++++++++
app/assets/stylesheets/framework/header.scss | 2 +-
app/assets/stylesheets/framework/variables.scss | 5 +++++
.../stylesheets/pages/profiles/preferences.scss | 16 ++++++++++++++++
app/views/layouts/header/_default.html.haml | 2 ++
app/views/profiles/preferences/show.html.haml | 17 +++++++++++++++++
.../jivl-activate-repo-cookie-preferences.yml | 5 +++++
.../user_visits_profile_preferences_page_spec.rb | 12 ++++++++++++
spec/features/projects/user_edits_files_spec.rb | 4 +++-
spec/support/cookie_helper.rb | 4 ++++
12 files changed, 86 insertions(+), 2 deletions(-)
create mode 100644 app/assets/images/multi-editor-off.png
create mode 100644 app/assets/images/multi-editor-on.png
create mode 100644 changelogs/unreleased/jivl-activate-repo-cookie-preferences.yml
diff --git a/app/assets/images/multi-editor-off.png b/app/assets/images/multi-editor-off.png
new file mode 100644
index 00000000000..82a6127f853
Binary files /dev/null and b/app/assets/images/multi-editor-off.png differ
diff --git a/app/assets/images/multi-editor-on.png b/app/assets/images/multi-editor-on.png
new file mode 100644
index 00000000000..2bcd29abf13
Binary files /dev/null and b/app/assets/images/multi-editor-on.png differ
diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js
index 0dc02f012e4..ba4ac850346 100644
--- a/app/assets/javascripts/profile/profile.js
+++ b/app/assets/javascripts/profile/profile.js
@@ -1,4 +1,5 @@
/* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */
+import Cookies from 'js-cookie';
import Flash from '../flash';
import { getPagePath } from '../lib/utils/common_utils';
@@ -7,6 +8,8 @@ import { getPagePath } from '../lib/utils/common_utils';
constructor({ form } = {}) {
this.onSubmitForm = this.onSubmitForm.bind(this);
this.form = form || $('.edit-user');
+ this.newRepoActivated = Cookies.get('new_repo');
+ this.setRepoRadio();
this.bindEvents();
this.initAvatarGlCrop();
}
@@ -25,6 +28,7 @@ import { getPagePath } from '../lib/utils/common_utils';
bindEvents() {
$('.js-preferences-form').on('change.preference', 'input[type=radio]', this.submitForm);
+ $('input[name="user[multi_file]"]').on('change', this.setNewRepoCookie);
$('#user_notification_email').on('change', this.submitForm);
$('#user_notified_of_own_activity').on('change', this.submitForm);
$('.update-username').on('ajax:before', this.beforeUpdateUsername);
@@ -82,6 +86,23 @@ import { getPagePath } from '../lib/utils/common_utils';
}
});
}
+
+ setNewRepoCookie() {
+ if (this.value === 'off') {
+ Cookies.remove('new_repo');
+ } else {
+ Cookies.set('new_repo', true, { expires_in: 365 });
+ }
+ }
+
+ setRepoRadio() {
+ const multiEditRadios = $('input[name="user[multi_file]"]');
+ if (this.newRepoActivated || this.newRepoActivated === 'true') {
+ multiEditRadios.filter('[value=on]').prop('checked', true);
+ } else {
+ multiEditRadios.filter('[value=off]').prop('checked', true);
+ }
+ }
}
$(function() {
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 29714e348a0..ad160f37641 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -516,7 +516,7 @@
.header-user {
.dropdown-menu-nav {
width: auto;
- min-width: 140px;
+ min-width: 160px;
margin-top: 4px;
color: $gl-text-color;
left: auto;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 1d6c7a5c472..f7853909f56 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -727,3 +727,8 @@ Popup
$popup-triangle-size: 15px;
$popup-triangle-border-size: 1px;
$popup-box-shadow-color: rgba(90, 90, 90, 0.05);
+
+/*
+Multi file editor
+*/
+$border-color-settings: #e1e1e1;
diff --git a/app/assets/stylesheets/pages/profiles/preferences.scss b/app/assets/stylesheets/pages/profiles/preferences.scss
index c197494b152..68d40b56133 100644
--- a/app/assets/stylesheets/pages/profiles/preferences.scss
+++ b/app/assets/stylesheets/pages/profiles/preferences.scss
@@ -20,6 +20,22 @@
}
}
+.multi-file-editor-options {
+ label {
+ margin-right: 20px;
+ text-align: center;
+ }
+
+ .preview {
+ font-size: 0;
+
+ img {
+ border: 1px solid $border-color-settings;
+ border-radius: 4px;
+ }
+ }
+}
+
.application-theme {
label {
margin-right: 20px;
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 99e7f3b568d..39eb71c2bac 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -56,6 +56,8 @@
= link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
%li
= link_to "Settings", profile_path
+ %li
+ = link_to "Turn on multi edit", profile_preferences_path
- if current_user
%li
= link_to "Help", help_path
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index 66d1d1e8d44..65328791ce5 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -3,6 +3,23 @@
= render 'profiles/head'
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f|
+ .col-lg-4
+ %h4.prepend-top-0
+ GitLab multi file editor
+ %p Unlock an additional editing experience which makes it possible to edit and commit multiple files
+ .col-lg-8.multi-file-editor-options
+ = label_tag do
+ .preview.append-bottom-10= image_tag "multi-editor-off.png"
+ = f.radio_button :multi_file, "off", checked: true
+ Off
+ = label_tag do
+ .preview.append-bottom-10= image_tag "multi-editor-on.png"
+ = f.radio_button :multi_file, "on", checked: false
+ On
+
+ .col-sm-12
+ %hr
+
.col-lg-4.application-theme
%h4.prepend-top-0
GitLab navigation theme
diff --git a/changelogs/unreleased/jivl-activate-repo-cookie-preferences.yml b/changelogs/unreleased/jivl-activate-repo-cookie-preferences.yml
new file mode 100644
index 00000000000..778eaa84381
--- /dev/null
+++ b/changelogs/unreleased/jivl-activate-repo-cookie-preferences.yml
@@ -0,0 +1,5 @@
+---
+title: Added option to user preferences to enable the multi file editor
+merge_request: 16056
+author:
+type: added
diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
index 90d6841af0e..266af8f4e3d 100644
--- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
+++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
@@ -32,6 +32,18 @@ describe 'User visits the profile preferences page' do
end
end
+ describe 'User changes their multi file editor preferences', :js do
+ it 'set the new_repo cookie when the option is ON' do
+ choose 'user_multi_file_on'
+ expect(get_cookie('new_repo')).not_to be_nil
+ end
+
+ it 'deletes the new_repo cookie when the option is OFF' do
+ choose 'user_multi_file_off'
+ expect(get_cookie('new_repo')).to be_nil
+ end
+ end
+
describe 'User changes their default dashboard', :js do
it 'creates a flash message' do
select 'Starred Projects', from: 'user_dashboard'
diff --git a/spec/features/projects/user_edits_files_spec.rb b/spec/features/projects/user_edits_files_spec.rb
index 5c5c6a398f6..05c2be473da 100644
--- a/spec/features/projects/user_edits_files_spec.rb
+++ b/spec/features/projects/user_edits_files_spec.rb
@@ -33,7 +33,9 @@ describe 'User edits files' do
binary_file = File.join(project.repository.root_ref, 'files/images/logo-black.png')
visit(project_blob_path(project, binary_file))
- expect(page).not_to have_link('edit')
+ page.within '.content' do
+ expect(page).not_to have_link('edit')
+ end
end
it 'commits an edited file', :js do
diff --git a/spec/support/cookie_helper.rb b/spec/support/cookie_helper.rb
index 224619c899c..d72925e1838 100644
--- a/spec/support/cookie_helper.rb
+++ b/spec/support/cookie_helper.rb
@@ -8,6 +8,10 @@ module CookieHelper
page.driver.browser.manage.add_cookie(name: name, value: value, **options)
end
+ def get_cookie(name)
+ page.driver.browser.manage.cookie_named(name)
+ end
+
private
def on_a_page?
--
cgit v1.2.1
From 5e148d4e931792733400f59864e1aa886ef55953 Mon Sep 17 00:00:00 2001
From: Felipe Artur
Date: Wed, 6 Dec 2017 17:07:47 -0200
Subject: EE-BACKPORT group boards
---
app/finders/labels_finder.rb | 19 +-
app/policies/group_policy.rb | 8 +-
doc/api/boards.md | 200 +++++++++++++++++++--
lib/api/api.rb | 4 +-
lib/api/boards.rb | 84 ++++-----
lib/api/boards_responses.rb | 50 ++++++
lib/api/entities.rb | 2 +
lib/api/helpers.rb | 15 +-
lib/api/labels.rb | 4 +-
lib/api/v3/labels.rb | 2 +-
spec/finders/labels_finder_spec.rb | 10 ++
spec/fixtures/api/schemas/public_api/v4/board.json | 86 +++++++++
.../fixtures/api/schemas/public_api/v4/boards.json | 4 +
.../api/schemas/public_api/v4/user/basic.json | 2 +-
spec/requests/api/boards_spec.rb | 179 ++----------------
spec/support/api/boards_shared_examples.rb | 180 +++++++++++++++++++
16 files changed, 601 insertions(+), 248 deletions(-)
create mode 100644 lib/api/boards_responses.rb
create mode 100644 spec/fixtures/api/schemas/public_api/v4/board.json
create mode 100644 spec/fixtures/api/schemas/public_api/v4/boards.json
create mode 100644 spec/support/api/boards_shared_examples.rb
diff --git a/app/finders/labels_finder.rb b/app/finders/labels_finder.rb
index ce432ddbfe6..6de9eb89468 100644
--- a/app/finders/labels_finder.rb
+++ b/app/finders/labels_finder.rb
@@ -1,4 +1,6 @@
class LabelsFinder < UnionFinder
+ include Gitlab::Utils::StrongMemoize
+
def initialize(current_user, params = {})
@current_user = current_user
@params = params
@@ -32,6 +34,8 @@ class LabelsFinder < UnionFinder
label_ids << project.labels
end
end
+ elsif only_group_labels?
+ label_ids << Label.where(group_id: group.id)
else
label_ids << Label.where(group_id: projects.group_ids)
label_ids << Label.where(project_id: projects.select(:id))
@@ -51,6 +55,13 @@ class LabelsFinder < UnionFinder
items.where(title: title)
end
+ def group
+ strong_memoize(:group) do
+ group = Group.find(params[:group_id])
+ authorized_to_read_labels?(group) && group
+ end
+ end
+
def group?
params[:group_id].present?
end
@@ -63,6 +74,10 @@ class LabelsFinder < UnionFinder
params[:project_ids].present?
end
+ def only_group_labels?
+ params[:only_group_labels]
+ end
+
def title
params[:title] || params[:name]
end
@@ -96,9 +111,9 @@ class LabelsFinder < UnionFinder
@projects
end
- def authorized_to_read_labels?(project)
+ def authorized_to_read_labels?(label_parent)
return true if skip_authorization
- Ability.allowed?(current_user, :read_label, project)
+ Ability.allowed?(current_user, :read_label, label_parent)
end
end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index d2d45e402b0..f0bcba588a2 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -28,12 +28,18 @@ class GroupPolicy < BasePolicy
with_options scope: :subject, score: 0
condition(:request_access_enabled) { @subject.request_access_enabled }
- rule { public_group } .enable :read_group
+ rule { public_group }.policy do
+ enable :read_group
+ enable :read_list
+ enable :read_label
+ end
+
rule { logged_in_viewable }.enable :read_group
rule { guest }.policy do
enable :read_group
enable :upload_file
+ enable :read_label
end
rule { admin } .enable :read_group
diff --git a/doc/api/boards.md b/doc/api/boards.md
index 69c47abc806..a5f455e1c43 100644
--- a/doc/api/boards.md
+++ b/doc/api/boards.md
@@ -15,10 +15,10 @@ GET /projects/:id/boards
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/boards
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards
```
Example response:
@@ -27,6 +27,19 @@ Example response:
[
{
"id" : 1,
+ "project": {
+ "id": 5,
+ "name": "Diaspora Project Site",
+ "name_with_namespace": "Diaspora / Diaspora Project Site",
+ "path": "diaspora-project-site",
+ "path_with_namespace": "diaspora/diaspora-project-site",
+ "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
+ "web_url": "http://example.com/diaspora/diaspora-project-site"
+ },
+ "milestone": {
+ "id": 12
+ "title": "10.0"
+ },
"lists" : [
{
"id" : 1,
@@ -60,6 +73,159 @@ Example response:
]
```
+## Single board
+
+Get a single board.
+
+```
+GET /projects/:id/boards/:board_id
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1
+```
+
+Example response:
+
+```json
+ {
+ "id": 1,
+ "name:": "project issue board",
+ "project": {
+ "id": 5,
+ "name": "Diaspora Project Site",
+ "name_with_namespace": "Diaspora / Diaspora Project Site",
+ "path": "diaspora-project-site",
+ "path_with_namespace": "diaspora/diaspora-project-site",
+ "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
+ "web_url": "http://example.com/diaspora/diaspora-project-site"
+ },
+ "milestone": {
+ "id": 12
+ "title": "10.0"
+ },
+ "lists" : [
+ {
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+ },
+ {
+ "id" : 2,
+ "label" : {
+ "name" : "Ready",
+ "color" : "#FF0000",
+ "description" : null
+ },
+ "position" : 2
+ },
+ {
+ "id" : 3,
+ "label" : {
+ "name" : "Production",
+ "color" : "#FF5F00",
+ "description" : null
+ },
+ "position" : 3
+ }
+ ]
+ }
+```
+
+## Create a board (EES-Only)
+
+Creates a board.
+
+```
+POST /projects/:id/boards
+```
+
+| 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 |
+| `name` | string | yes | The name of the new board |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards?name=newboard
+```
+
+Example response:
+
+```json
+ {
+ "id": 1,
+ "project": {
+ "id": 5,
+ "name": "Diaspora Project Site",
+ "name_with_namespace": "Diaspora / Diaspora Project Site",
+ "path": "diaspora-project-site",
+ "path_with_namespace": "diaspora/diaspora-project-site",
+ "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
+ "web_url": "http://example.com/diaspora/diaspora-project-site"
+ },
+ "name": "newboard",
+ "milestone": {
+ "id": 12
+ "title": "10.0"
+ },
+ "lists" : [
+ {
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+ },
+ {
+ "id" : 2,
+ "label" : {
+ "name" : "Ready",
+ "color" : "#FF0000",
+ "description" : null
+ },
+ "position" : 2
+ },
+ {
+ "id" : 3,
+ "label" : {
+ "name" : "Production",
+ "color" : "#FF5F00",
+ "description" : null
+ },
+ "position" : 3
+ }
+ ]
+ }
+```
+
+## Delete a board (EES-Only)
+
+Deletes a board.
+
+```
+DELETE /projects/:id/boards/:board_id
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1
+```
+
## List board lists
Get a list of the board's lists.
@@ -71,8 +237,8 @@ GET /projects/:id/boards/:board_id/lists
| 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 |
-| `board_id` | integer | yes | The ID of a board |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists
@@ -122,9 +288,9 @@ GET /projects/:id/boards/:board_id/lists/:list_id
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `board_id` | integer | yes | The ID of a board |
-| `list_id`| integer | yes | The ID of a board's list |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
+| `list_id`| integer | yes | The ID of a board's list |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1
@@ -154,9 +320,9 @@ POST /projects/:id/boards/:board_id/lists
| 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 |
-| `board_id` | integer | yes | The ID of a board |
-| `label_id` | integer | yes | The ID of a label |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
+| `label_id` | integer | yes | The ID of a label |
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists?label_id=5
@@ -186,10 +352,10 @@ PUT /projects/:id/boards/:board_id/lists/:list_id
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `board_id` | integer | yes | The ID of a board |
-| `list_id` | integer | yes | The ID of a board's list |
-| `position` | integer | yes | The position of the list |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
+| `list_id` | integer | yes | The ID of a board's list |
+| `position` | integer | yes | The position of the list |
```bash
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1?position=2
@@ -219,9 +385,9 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `board_id` | integer | yes | The ID of a board |
-| `list_id` | integer | yes | The ID of a board's list |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
+| `list_id` | integer | yes | The ID of a board's list |
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 8094597d238..e0d14281c96 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -119,6 +119,7 @@ module API
mount ::API::Features
mount ::API::Files
mount ::API::Groups
+ mount ::API::GroupMilestones
mount ::API::Internal
mount ::API::Issues
mount ::API::Jobs
@@ -129,8 +130,6 @@ module API
mount ::API::Members
mount ::API::MergeRequestDiffs
mount ::API::MergeRequests
- mount ::API::ProjectMilestones
- mount ::API::GroupMilestones
mount ::API::Namespaces
mount ::API::Notes
mount ::API::NotificationSettings
@@ -139,6 +138,7 @@ module API
mount ::API::PipelineSchedules
mount ::API::ProjectHooks
mount ::API::Projects
+ mount ::API::ProjectMilestones
mount ::API::ProjectSnippets
mount ::API::ProtectedBranches
mount ::API::Repositories
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 366b0dc9a6f..6c706b2b4e1 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -1,45 +1,46 @@
module API
class Boards < Grape::API
+ include BoardsResponses
include PaginationParams
before { authenticate! }
+ helpers do
+ def board_parent
+ user_project
+ end
+ end
+
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
- desc 'Get all project boards' do
- detail 'This feature was introduced in 8.13'
- success Entities::Board
- end
- params do
- use :pagination
- end
- get ':id/boards' do
- authorize!(:read_board, user_project)
- present paginate(user_project.boards), with: Entities::Board
+ segment ':id/boards' do
+ desc 'Get all project boards' do
+ detail 'This feature was introduced in 8.13'
+ success Entities::Board
+ end
+ params do
+ use :pagination
+ end
+ get '/' do
+ authorize!(:read_board, user_project)
+ present paginate(board_parent.boards), with: Entities::Board
+ end
+
+ desc 'Find a project board' do
+ detail 'This feature was introduced in 10.4'
+ success Entities::Board
+ end
+ get '/:board_id' do
+ present board, with: Entities::Board
+ end
end
params do
requires :board_id, type: Integer, desc: 'The ID of a board'
end
segment ':id/boards/:board_id' do
- helpers do
- def project_board
- board = user_project.boards.first
-
- if params[:board_id] == board.id
- board
- else
- not_found!('Board')
- end
- end
-
- def board_lists
- project_board.lists.destroyable
- end
- end
-
desc 'Get the lists of a project board' do
detail 'Does not include `done` list. This feature was introduced in 8.13'
success Entities::List
@@ -72,22 +73,13 @@ module API
requires :label_id, type: Integer, desc: 'The ID of an existing label'
end
post '/lists' do
- unless available_labels.exists?(params[:label_id])
+ unless available_labels_for(user_project).exists?(params[:label_id])
render_api_error!({ error: 'Label not found!' }, 400)
end
authorize!(:admin_list, user_project)
- service = ::Boards::Lists::CreateService.new(user_project, current_user,
- { label_id: params[:label_id] })
-
- list = service.execute(project_board)
-
- if list.valid?
- present list, with: Entities::List
- else
- render_validation_error!(list)
- end
+ create_list
end
desc 'Moves a board list to a new position' do
@@ -99,18 +91,11 @@ module API
requires :position, type: Integer, desc: 'The position of the list'
end
put '/lists/:list_id' do
- list = project_board.lists.movable.find(params[:list_id])
+ list = board_lists.find(params[:list_id])
authorize!(:admin_list, user_project)
- service = ::Boards::Lists::MoveService.new(user_project, current_user,
- { position: params[:position] })
-
- if service.execute(list)
- present list, with: Entities::List
- else
- render_api_error!({ error: "List could not be moved!" }, 400)
- end
+ move_list(list)
end
desc 'Delete a board list' do
@@ -124,12 +109,7 @@ module API
authorize!(:admin_list, user_project)
list = board_lists.find(params[:list_id])
- destroy_conditionally!(list) do |list|
- service = ::Boards::Lists::DestroyService.new(user_project, current_user)
- unless service.execute(list)
- render_api_error!({ error: 'List could not be deleted!' }, 400)
- end
- end
+ destroy_list(list)
end
end
end
diff --git a/lib/api/boards_responses.rb b/lib/api/boards_responses.rb
new file mode 100644
index 00000000000..ead0943a74d
--- /dev/null
+++ b/lib/api/boards_responses.rb
@@ -0,0 +1,50 @@
+module API
+ module BoardsResponses
+ extend ActiveSupport::Concern
+
+ included do
+ helpers do
+ def board
+ board_parent.boards.find(params[:board_id])
+ end
+
+ def board_lists
+ board.lists.destroyable
+ end
+
+ def create_list
+ create_list_service =
+ ::Boards::Lists::CreateService.new(board_parent, current_user, { label_id: params[:label_id] })
+
+ list = create_list_service.execute(board)
+
+ if list.valid?
+ present list, with: Entities::List
+ else
+ render_validation_error!(list)
+ end
+ end
+
+ def move_list(list)
+ move_list_service =
+ ::Boards::Lists::MoveService.new(board_parent, current_user, { position: params[:position].to_i })
+
+ if move_list_service.execute(list)
+ present list, with: Entities::List
+ else
+ render_api_error!({ error: "List could not be moved!" }, 400)
+ end
+ end
+
+ def destroy_list(list)
+ destroy_conditionally!(list) do |list|
+ service = ::Boards::Lists::DestroyService.new(board_parent, current_user)
+ unless service.execute(list)
+ render_api_error!({ error: 'List could not be deleted!' }, 400)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 4ad4a1f7867..86ac10c39d0 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -791,6 +791,8 @@ module API
class Board < Grape::Entity
expose :id
+ expose :project, using: Entities::BasicProjectDetails
+
expose :lists, using: Entities::List do |board|
board.lists.destroyable
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 9ba15893f55..c1f5ec2ab14 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -74,8 +74,15 @@ module API
page || not_found!('Wiki Page')
end
- def available_labels
- @available_labels ||= LabelsFinder.new(current_user, project_id: user_project.id).execute
+ def available_labels_for(label_parent)
+ search_params =
+ if label_parent.is_a?(Project)
+ { project_id: label_parent.id }
+ else
+ { group_id: label_parent.id, only_group_labels: true }
+ end
+
+ LabelsFinder.new(current_user, search_params).execute
end
def find_user(id)
@@ -141,7 +148,9 @@ module API
end
def find_project_label(id)
- label = available_labels.find_by_id(id) || available_labels.find_by_title(id)
+ labels = available_labels_for(user_project)
+ label = labels.find_by_id(id) || labels.find_by_title(id)
+
label || not_found!('Label')
end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index e41a1720ac1..81eaf56e48e 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -15,7 +15,7 @@ module API
use :pagination
end
get ':id/labels' do
- present paginate(available_labels), with: Entities::Label, current_user: current_user, project: user_project
+ present paginate(available_labels_for(user_project)), with: Entities::Label, current_user: current_user, project: user_project
end
desc 'Create a new label' do
@@ -30,7 +30,7 @@ module API
post ':id/labels' do
authorize! :admin_label, user_project
- label = available_labels.find_by(title: params[:name])
+ label = available_labels_for(user_project).find_by(title: params[:name])
conflict!('Label already exists') if label
priority = params.delete(:priority)
diff --git a/lib/api/v3/labels.rb b/lib/api/v3/labels.rb
index bd5eb2175e8..4157462ec2a 100644
--- a/lib/api/v3/labels.rb
+++ b/lib/api/v3/labels.rb
@@ -11,7 +11,7 @@ module API
success ::API::Entities::Label
end
get ':id/labels' do
- present available_labels, with: ::API::Entities::Label, current_user: current_user, project: user_project
+ present available_labels_for(user_project), with: ::API::Entities::Label, current_user: current_user, project: user_project
end
desc 'Delete an existing label' do
diff --git a/spec/finders/labels_finder_spec.rb b/spec/finders/labels_finder_spec.rb
index d507af3fd3d..06031aee217 100644
--- a/spec/finders/labels_finder_spec.rb
+++ b/spec/finders/labels_finder_spec.rb
@@ -56,6 +56,16 @@ describe LabelsFinder do
expect(finder.execute).to eq [group_label_2, group_label_1, project_label_5]
end
+
+ context 'when only_group_labels is true' do
+ it 'returns only group labels' do
+ group_1.add_developer(user)
+
+ finder = described_class.new(user, group_id: group_1.id, only_group_labels: true)
+
+ expect(finder.execute).to eq [group_label_2, group_label_1]
+ end
+ end
end
context 'filtering by project_id' do
diff --git a/spec/fixtures/api/schemas/public_api/v4/board.json b/spec/fixtures/api/schemas/public_api/v4/board.json
new file mode 100644
index 00000000000..d667f1d631c
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/board.json
@@ -0,0 +1,86 @@
+{
+ "type": "object",
+ "required" : [
+ "id",
+ "project",
+ "lists"
+ ],
+ "properties" : {
+ "id": { "type": "integer" },
+ "project": {
+ "type": ["object", "null"],
+ "required": [
+ "id",
+ "avatar_url",
+ "description",
+ "default_branch",
+ "tag_list",
+ "ssh_url_to_repo",
+ "http_url_to_repo",
+ "web_url",
+ "name",
+ "name_with_namespace",
+ "path",
+ "path_with_namespace",
+ "star_count",
+ "forks_count",
+ "created_at",
+ "last_activity_at"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "avatar_url": { "type": ["string", "null"] },
+ "description": { "type": ["string", "null"] },
+ "default_branch": { "type": ["string", "null"] },
+ "tag_list": { "type": "array" },
+ "ssh_url_to_repo": { "type": "string" },
+ "http_url_to_repo": { "type": "string" },
+ "web_url": { "type": "string" },
+ "name": { "type": "string" },
+ "name_with_namespace": { "type": "string" },
+ "path": { "type": "string" },
+ "path_with_namespace": { "type": "string" },
+ "star_count": { "type": "integer" },
+ "forks_count": { "type": "integer" },
+ "created_at": { "type": "date" },
+ "last_activity_at": { "type": "date" }
+ },
+ "additionalProperties": false
+ },
+ "lists": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required" : [
+ "id",
+ "label",
+ "position"
+ ],
+ "properties" : {
+ "id": { "type": "integer" },
+ "label": {
+ "type": ["object", "null"],
+ "required": [
+ "id",
+ "color",
+ "description",
+ "name"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "color": {
+ "type": "string",
+ "pattern": "^#[0-9A-Fa-f]{3}{1,2}+$"
+ },
+ "description": { "type": ["string", "null"] },
+ "name": { "type": "string" }
+ }
+ },
+ "position": { "type": ["integer", "null"] }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "additionalProperties": true
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/boards.json b/spec/fixtures/api/schemas/public_api/v4/boards.json
new file mode 100644
index 00000000000..117564ef77a
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/boards.json
@@ -0,0 +1,4 @@
+{
+ "type": "array",
+ "items": { "$ref": "board.json" }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/user/basic.json b/spec/fixtures/api/schemas/public_api/v4/user/basic.json
index 9f69d31971c..bf330d8278c 100644
--- a/spec/fixtures/api/schemas/public_api/v4/user/basic.json
+++ b/spec/fixtures/api/schemas/public_api/v4/user/basic.json
@@ -1,5 +1,5 @@
{
- "type": "object",
+ "type": ["object", "null"],
"required": [
"id",
"state",
diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb
index f65af69dc7f..c6c10025f7f 100644
--- a/spec/requests/api/boards_spec.rb
+++ b/spec/requests/api/boards_spec.rb
@@ -6,18 +6,18 @@ describe API::Boards do
set(:non_member) { create(:user) }
set(:guest) { create(:user) }
set(:admin) { create(:user, :admin) }
- set(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
+ set(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
set(:dev_label) do
- create(:label, title: 'Development', color: '#FFAABB', project: project)
+ create(:label, title: 'Development', color: '#FFAABB', project: board_parent)
end
set(:test_label) do
- create(:label, title: 'Testing', color: '#FFAACC', project: project)
+ create(:label, title: 'Testing', color: '#FFAACC', project: board_parent)
end
set(:ux_label) do
- create(:label, title: 'UX', color: '#FF0000', project: project)
+ create(:label, title: 'UX', color: '#FF0000', project: board_parent)
end
set(:dev_list) do
@@ -28,180 +28,25 @@ describe API::Boards do
create(:list, label: test_label, position: 2)
end
- set(:board) do
- create(:board, project: project, lists: [dev_list, test_list])
- end
-
- before do
- project.add_reporter(user)
- project.add_guest(guest)
- end
+ set(:milestone) { create(:milestone, project: board_parent) }
+ set(:board_label) { create(:label, project: board_parent) }
+ set(:board) { create(:board, project: board_parent, lists: [dev_list, test_list]) }
- describe "GET /projects/:id/boards" do
- let(:base_url) { "/projects/#{project.id}/boards" }
+ it_behaves_like 'group and project boards', "/projects/:id/boards"
- context "when unauthenticated" do
- it "returns authentication error" do
- get api(base_url)
-
- expect(response).to have_gitlab_http_status(401)
- end
- end
-
- context "when authenticated" do
- it "returns the project issue board" do
- get api(base_url, user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.length).to eq(1)
- expect(json_response.first['id']).to eq(board.id)
- expect(json_response.first['lists']).to be_an Array
- expect(json_response.first['lists'].length).to eq(2)
- expect(json_response.first['lists'].last).to have_key('position')
- end
- end
- end
-
- describe "GET /projects/:id/boards/:board_id/lists" do
- let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" }
-
- it 'returns issue board lists' do
- get api(base_url, user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.length).to eq(2)
- expect(json_response.first['label']['name']).to eq(dev_label.title)
- end
-
- it 'returns 404 if board not found' do
- get api("/projects/#{project.id}/boards/22343/lists", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- describe "GET /projects/:id/boards/:board_id/lists/:list_id" do
- let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" }
-
- it 'returns a list' do
- get api("#{base_url}/#{dev_list.id}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['id']).to eq(dev_list.id)
- expect(json_response['label']['name']).to eq(dev_label.title)
- expect(json_response['position']).to eq(1)
- end
-
- it 'returns 404 if list not found' do
- get api("#{base_url}/5324", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- describe "POST /projects/:id/board/lists" do
- let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" }
+ describe "POST /projects/:id/boards/lists" do
+ let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}/lists" }
it 'creates a new issue board list for group labels' do
group = create(:group)
group_label = create(:group_label, group: group)
- project.update(group: group)
+ board_parent.update(group: group)
- post api(base_url, user), label_id: group_label.id
+ post api(url, user), label_id: group_label.id
expect(response).to have_gitlab_http_status(201)
expect(json_response['label']['name']).to eq(group_label.title)
expect(json_response['position']).to eq(3)
end
-
- it 'creates a new issue board list for project labels' do
- post api(base_url, user), label_id: ux_label.id
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['label']['name']).to eq(ux_label.title)
- expect(json_response['position']).to eq(3)
- end
-
- it 'returns 400 when creating a new list if label_id is invalid' do
- post api(base_url, user), label_id: 23423
-
- expect(response).to have_gitlab_http_status(400)
- end
-
- it 'returns 403 for project members with guest role' do
- put api("#{base_url}/#{test_list.id}", guest), position: 1
-
- expect(response).to have_gitlab_http_status(403)
- end
- end
-
- describe "PUT /projects/:id/boards/:board_id/lists/:list_id to update only position" do
- let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" }
-
- it "updates a list" do
- put api("#{base_url}/#{test_list.id}", user),
- position: 1
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['position']).to eq(1)
- end
-
- it "returns 404 error if list id not found" do
- put api("#{base_url}/44444", user),
- position: 1
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it "returns 403 for project members with guest role" do
- put api("#{base_url}/#{test_list.id}", guest),
- position: 1
-
- expect(response).to have_gitlab_http_status(403)
- end
- end
-
- describe "DELETE /projects/:id/board/lists/:list_id" do
- let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" }
-
- it "rejects a non member from deleting a list" do
- delete api("#{base_url}/#{dev_list.id}", non_member)
-
- expect(response).to have_gitlab_http_status(403)
- end
-
- it "rejects a user with guest role from deleting a list" do
- delete api("#{base_url}/#{dev_list.id}", guest)
-
- expect(response).to have_gitlab_http_status(403)
- end
-
- it "returns 404 error if list id not found" do
- delete api("#{base_url}/44444", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- context "when the user is project owner" do
- set(:owner) { create(:user) }
-
- before do
- project.update(namespace: owner.namespace)
- end
-
- it "deletes the list if an admin requests it" do
- delete api("#{base_url}/#{dev_list.id}", owner)
-
- expect(response).to have_gitlab_http_status(204)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("#{base_url}/#{dev_list.id}", owner) }
- end
- end
end
end
diff --git a/spec/support/api/boards_shared_examples.rb b/spec/support/api/boards_shared_examples.rb
new file mode 100644
index 00000000000..943c1f6ffd7
--- /dev/null
+++ b/spec/support/api/boards_shared_examples.rb
@@ -0,0 +1,180 @@
+shared_examples_for 'group and project boards' do |route_definition, ee = false|
+ let(:root_url) { route_definition.gsub(":id", board_parent.id.to_s) }
+
+ before do
+ board_parent.add_reporter(user)
+ board_parent.add_guest(guest)
+ end
+
+ def expect_schema_match_for(response, schema_file, ee)
+ if ee
+ expect(response).to match_response_schema(schema_file, dir: "ee")
+ else
+ expect(response).to match_response_schema(schema_file)
+ end
+ end
+
+ describe "GET #{route_definition}" do
+ context "when unauthenticated" do
+ it "returns authentication error" do
+ get api(root_url)
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+ end
+
+ context "when authenticated" do
+ it "returns the issue boards" do
+ get api(root_url, user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+
+ expect_schema_match_for(response, 'public_api/v4/boards', ee)
+ end
+
+ describe "GET #{route_definition}/:board_id" do
+ let(:url) { "#{root_url}/#{board.id}" }
+
+ it 'get a single board by id' do
+ get api(url, user)
+
+ expect_schema_match_for(response, 'public_api/v4/board', ee)
+ end
+ end
+ end
+ end
+
+ describe "GET #{route_definition}/:board_id/lists" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it 'returns issue board lists' do
+ get api(url, user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(json_response.first['label']['name']).to eq(dev_label.title)
+ end
+
+ it 'returns 404 if board not found' do
+ get api("#{root_url}/22343/lists", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "GET #{route_definition}/:board_id/lists/:list_id" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it 'returns a list' do
+ get api("#{url}/#{dev_list.id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['id']).to eq(dev_list.id)
+ expect(json_response['label']['name']).to eq(dev_label.title)
+ expect(json_response['position']).to eq(1)
+ end
+
+ it 'returns 404 if list not found' do
+ get api("#{url}/5324", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "POST #{route_definition}/lists" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it 'creates a new issue board list for labels' do
+ post api(url, user), label_id: ux_label.id
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['label']['name']).to eq(ux_label.title)
+ expect(json_response['position']).to eq(3)
+ end
+
+ it 'returns 400 when creating a new list if label_id is invalid' do
+ post api(url, user), label_id: 23423
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'returns 403 for members with guest role' do
+ put api("#{url}/#{test_list.id}", guest), position: 1
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+
+ describe "PUT #{route_definition}/:board_id/lists/:list_id to update only position" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it "updates a list" do
+ put api("#{url}/#{test_list.id}", user),
+ position: 1
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['position']).to eq(1)
+ end
+
+ it "returns 404 error if list id not found" do
+ put api("#{url}/44444", user),
+ position: 1
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it "returns 403 for members with guest role" do
+ put api("#{url}/#{test_list.id}", guest),
+ position: 1
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+
+ describe "DELETE #{route_definition}/lists/:list_id" do
+ let(:url) { "#{root_url}/#{board.id}/lists" }
+
+ it "rejects a non member from deleting a list" do
+ delete api("#{url}/#{dev_list.id}", non_member)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+
+ it "rejects a user with guest role from deleting a list" do
+ delete api("#{url}/#{dev_list.id}", guest)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+
+ it "returns 404 error if list id not found" do
+ delete api("#{url}/44444", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ context "when the user is parent owner" do
+ set(:owner) { create(:user) }
+
+ before do
+ if board_parent.try(:namespace)
+ board_parent.update(namespace: owner.namespace)
+ else
+ board.parent.add_owner(owner)
+ end
+ end
+
+ it "deletes the list if an admin requests it" do
+ delete api("#{url}/#{dev_list.id}", owner)
+
+ expect(response).to have_gitlab_http_status(204)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) { api("#{url}/#{dev_list.id}", owner) }
+ end
+ end
+ end
+end
--
cgit v1.2.1
From 18bd8b3bd00ac664c7043e14b02a1fadc8605c16 Mon Sep 17 00:00:00 2001
From: Fatih Acet
Date: Thu, 4 Jan 2018 22:16:11 +0100
Subject: Fix issue boards scroll config.
---
app/assets/javascripts/boards/components/board_list.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/assets/javascripts/boards/components/board_list.js b/app/assets/javascripts/boards/components/board_list.js
index 29aeb8e84aa..84b76a6f1b1 100644
--- a/app/assets/javascripts/boards/components/board_list.js
+++ b/app/assets/javascripts/boards/components/board_list.js
@@ -115,7 +115,7 @@ export default {
},
mounted() {
const options = gl.issueBoards.getBoardSortableDefaultOptions({
- scroll: document.querySelectorAll('.boards-list')[0],
+ scroll: true,
group: 'issues',
disabled: this.disabled,
filter: '.board-list-count, .is-disabled',
--
cgit v1.2.1
From f834e2907d5111f3e2bcd8d0dd126f9e0dd0be7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Thu, 4 Jan 2018 19:13:30 +0100
Subject: Move cache reset to ci_cd_settings controller
---
.../projects/settings/ci_cd_controller.rb | 9 +++++
app/controllers/projects_controller.rb | 9 -----
app/views/projects/pipelines/index.html.haml | 2 +-
config/routes/project.rb | 5 ++-
.../projects/settings/ci_cd_controller_spec.rb | 47 ++++++++++++++++++++++
spec/controllers/projects_controller_spec.rb | 47 ----------------------
6 files changed, 60 insertions(+), 59 deletions(-)
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index b029b31f9af..1dcebcb15a6 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -11,6 +11,15 @@ module Projects
define_auto_devops_variables
end
+ def reset_cache
+ if ResetProjectCacheService.new(@project, current_user).execute
+ flash[:notice] = _("Project cache successfully reset.")
+ else
+ flash[:error] = _("Unable to reset project cache.")
+ end
+ redirect_to project_pipelines_path(@project)
+ end
+
private
def define_runners_variables
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 928555c200b..6f609348402 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -175,15 +175,6 @@ class ProjectsController < Projects::ApplicationController
)
end
- def reset_cache
- if ResetProjectCacheService.new(@project, current_user).execute
- flash[:notice] = _("Project cache successfully reset.")
- else
- flash[:error] = _("Unable to reset project cache.")
- end
- redirect_to project_pipelines_path(@project)
- end
-
def export
@project.add_export_job(current_user: current_user)
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
index d23cb626312..f8555f11aab 100644
--- a/app/views/projects/pipelines/index.html.haml
+++ b/app/views/projects/pipelines/index.html.haml
@@ -11,7 +11,7 @@
"can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
"has-ci" => @repository.gitlab_ci_yml,
"ci-lint-path" => ci_lint_path,
- "reset-cache-path" => reset_cache_project_path(@project) } }
+ "reset-cache-path" => reset_cache_project_settings_ci_cd_path(@project) } }
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('pipelines')
diff --git a/config/routes/project.rb b/config/routes/project.rb
index d79c6e141c8..905c906b194 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -407,7 +407,9 @@ constraints(ProjectUrlConstrainer.new) do
end
namespace :settings do
get :members, to: redirect("%{namespace_id}/%{project_id}/project_members")
- resource :ci_cd, only: [:show], controller: 'ci_cd'
+ resource :ci_cd, only: [:show], controller: 'ci_cd' do
+ get :reset_cache
+ end
resource :integrations, only: [:show]
resource :repository, only: [:show], controller: :repository
end
@@ -436,7 +438,6 @@ constraints(ProjectUrlConstrainer.new) do
get :download_export
get :activity
get :refs
- get :reset_cache
put :new_issuable_address
end
end
diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
index b8fe0f46f57..acd40f4a305 100644
--- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
@@ -17,4 +17,51 @@ describe Projects::Settings::CiCdController do
expect(response).to render_template(:show)
end
end
+
+ describe '#reset_cache' do
+ before do
+ sign_in(user)
+
+ project.add_master(user)
+
+ allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true)
+ end
+
+ subject { get :reset_cache, namespace_id: project.namespace, project_id: project }
+
+ it 'calls reset project cache service' do
+ expect(ResetProjectCacheService).to receive_message_chain(:new, :execute)
+
+ subject
+ end
+
+ it 'redirects to project pipelines path' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:redirect)
+ expect(response).to redirect_to(project_pipelines_path(project))
+ end
+
+ context 'when service returns successfully' do
+ it 'sets the flash notice variable' do
+ subject
+
+ expect(controller).to set_flash[:notice]
+ expect(controller).not_to set_flash[:error]
+ end
+ end
+
+ context 'when service does not return successfully' do
+ before do
+ allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false)
+ end
+
+ it 'sets the flash error variable' do
+ subject
+
+ expect(controller).not_to set_flash[:notice]
+ expect(controller).to set_flash[:error]
+ end
+ end
+ end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 2fc827742fe..e61187fb518 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -686,53 +686,6 @@ describe ProjectsController do
end
end
- describe '#reset_cache' do
- before do
- sign_in(user)
-
- project.add_master(user)
-
- allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true)
- end
-
- subject { get :reset_cache, namespace_id: project.namespace, id: project }
-
- it 'calls reset project cache service' do
- expect(ResetProjectCacheService).to receive_message_chain(:new, :execute)
-
- subject
- end
-
- it 'redirects to project pipelines path' do
- subject
-
- expect(response).to have_gitlab_http_status(:redirect)
- expect(response).to redirect_to(project_pipelines_path(project))
- end
-
- context 'when service returns successfully' do
- it 'sets the flash notice variable' do
- subject
-
- expect(controller).to set_flash[:notice]
- expect(controller).not_to set_flash[:error]
- end
- end
-
- context 'when service does not return successfully' do
- before do
- allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false)
- end
-
- it 'sets the flash error variable' do
- subject
-
- expect(controller).not_to set_flash[:notice]
- expect(controller).to set_flash[:error]
- end
- end
- end
-
describe '#export' do
before do
sign_in(user)
--
cgit v1.2.1
From 7d7d289b159fba332c68dc66b6f9f3b17428c3a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Thu, 4 Jan 2018 19:14:37 +0100
Subject: Add missing empty line in #reset_cache
---
app/controllers/projects/settings/ci_cd_controller.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index 1dcebcb15a6..86717bb7242 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -17,6 +17,7 @@ module Projects
else
flash[:error] = _("Unable to reset project cache.")
end
+
redirect_to project_pipelines_path(@project)
end
--
cgit v1.2.1
From 8cc14dd5371c33f389211fcee39dbb28686b2021 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Thu, 4 Jan 2018 19:40:07 +0100
Subject: Rename Project#cache_index to jobs_cache_index
---
app/models/ci/build.rb | 4 ++--
app/services/reset_project_cache_service.rb | 2 +-
db/migrate/20171222183504_add_cache_index_to_project.rb | 13 -------------
.../20171222183504_add_jobs_cache_index_to_project.rb | 13 +++++++++++++
db/schema.rb | 2 +-
spec/models/ci/build_spec.rb | 8 ++++----
spec/services/reset_project_cache_service_spec.rb | 8 ++++----
7 files changed, 25 insertions(+), 25 deletions(-)
delete mode 100644 db/migrate/20171222183504_add_cache_index_to_project.rb
create mode 100644 db/migrate/20171222183504_add_jobs_cache_index_to_project.rb
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index e4ca74f87f2..ff903a63c54 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -461,8 +461,8 @@ module Ci
end
def cache
- if options[:cache] && project.cache_index
- options[:cache].merge(key: "#{options[:cache][:key]}:#{project.cache_index}")
+ if options[:cache] && project.jobs_cache_index
+ options[:cache].merge(key: "#{options[:cache][:key]}:#{project.jobs_cache_index}")
else
[options[:cache]]
end
diff --git a/app/services/reset_project_cache_service.rb b/app/services/reset_project_cache_service.rb
index 0886c6b8315..a162a6eedb9 100644
--- a/app/services/reset_project_cache_service.rb
+++ b/app/services/reset_project_cache_service.rb
@@ -1,5 +1,5 @@
class ResetProjectCacheService < BaseService
def execute
- @project.increment!(:cache_index)
+ @project.increment!(:jobs_cache_index)
end
end
diff --git a/db/migrate/20171222183504_add_cache_index_to_project.rb b/db/migrate/20171222183504_add_cache_index_to_project.rb
deleted file mode 100644
index e1d73db1ab0..00000000000
--- a/db/migrate/20171222183504_add_cache_index_to_project.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddCacheIndexToProject < ActiveRecord::Migration
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- add_column :projects, :cache_index, :integer
- end
-end
diff --git a/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb
new file mode 100644
index 00000000000..58ac0177420
--- /dev/null
+++ b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb
@@ -0,0 +1,13 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddCacheIndexToProject < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ def change
+ add_column :projects, :jobs_cache_index, :integer
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index b7512f293a6..cd3f87062ab 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1447,7 +1447,7 @@ ActiveRecord::Schema.define(version: 20171222183504) do
t.boolean "repository_read_only"
t.boolean "merge_requests_ff_only_enabled", default: false
t.boolean "merge_requests_rebase_enabled", default: false, null: false
- t.integer "cache_index"
+ t.integer "jobs_cache_index"
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 96513281994..8cecaf16fdf 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -265,17 +265,17 @@ describe Ci::Build do
allow(build).to receive(:options).and_return(options)
end
- context 'when project has cache_index' do
+ context 'when project has jobs_cache_index' do
before do
- allow_any_instance_of(Project).to receive(:cache_index).and_return(1)
+ allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1)
end
it { is_expected.to include(key: "key:1") }
end
- context 'when project does not have cache_index' do
+ context 'when project does not have jobs_cache_index' do
before do
- allow_any_instance_of(Project).to receive(:cache_index).and_return(nil)
+ allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(nil)
end
it { is_expected.to eq([options[:cache]]) }
diff --git a/spec/services/reset_project_cache_service_spec.rb b/spec/services/reset_project_cache_service_spec.rb
index df969d08f39..de475d16586 100644
--- a/spec/services/reset_project_cache_service_spec.rb
+++ b/spec/services/reset_project_cache_service_spec.rb
@@ -8,21 +8,21 @@ describe ResetProjectCacheService do
context 'when project cache_index is nil' do
before do
- project.cache_index = nil
+ project.jobs_cache_index = nil
end
it 'sets project cache_index to one' do
- expect { subject }.to change { project.reload.cache_index }.from(nil).to(1)
+ expect { subject }.to change { project.reload.jobs_cache_index }.from(nil).to(1)
end
end
context 'when project cache_index is a numeric value' do
before do
- project.update_attributes(cache_index: 1)
+ project.update_attributes(jobs_cache_index: 1)
end
it 'increments project cache index' do
- expect { subject }.to change { project.reload.cache_index }.by(1)
+ expect { subject }.to change { project.reload.jobs_cache_index }.by(1)
end
end
end
--
cgit v1.2.1
From 2682966829b49b7fbeee02e5c070c8c14630ea6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Thu, 4 Jan 2018 19:43:31 +0100
Subject: Refactor Ci::Build#cache
---
app/models/ci/build.rb | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index ff903a63c54..d0ee08ab086 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -461,11 +461,14 @@ module Ci
end
def cache
- if options[:cache] && project.jobs_cache_index
- options[:cache].merge(key: "#{options[:cache][:key]}:#{project.jobs_cache_index}")
- else
- [options[:cache]]
+ cache = options[:cache]
+
+ if cache && project.jobs_cache_index
+ cache = cache.merge(
+ key: "#{cache[:key]}:#{project.jobs_cache_index}")
end
+
+ [cache]
end
def credentials
--
cgit v1.2.1
From 0f137d8e9cc4b44ab11c549860bf27e7244ad09d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Thu, 4 Jan 2018 21:22:23 +0100
Subject: Fix faulty Ci::Build#cache spec
---
spec/models/ci/build_spec.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 8cecaf16fdf..3eaeeebf97d 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -270,7 +270,7 @@ describe Ci::Build do
allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1)
end
- it { is_expected.to include(key: "key:1") }
+ it { is_expected.to be_an(Array).and all(include(key: "key:1")) }
end
context 'when project does not have jobs_cache_index' do
--
cgit v1.2.1
From 6d1548f86922d2489fd601c725a9748e3e563216 Mon Sep 17 00:00:00 2001
From: Winnie Hellmann
Date: Wed, 3 Jan 2018 14:51:32 +0100
Subject: Fix Webpack config for ConcatenatedModule
---
config/webpack.config.js | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 5f95255334c..95fa79990e2 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -1,5 +1,6 @@
'use strict';
+var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var webpack = require('webpack');
@@ -179,15 +180,34 @@ var config = {
if (chunk.name) {
return chunk.name;
}
- return chunk.mapModules((m) => {
+
+ const moduleNames = [];
+
+ function collectModuleNames(m) {
+ // handle ConcatenatedModule which does not have resource nor context set
+ if (m.modules) {
+ m.modules.forEach(collectModuleNames);
+ return;
+ }
+
const pagesBase = path.join(ROOT_PATH, 'app/assets/javascripts/pages');
+
if (m.resource.indexOf(pagesBase) === 0) {
- return path.relative(pagesBase, m.resource)
+ moduleNames.push(path.relative(pagesBase, m.resource)
.replace(/\/index\.[a-z]+$/, '')
- .replace(/\//g, '__');
+ .replace(/\//g, '__'));
+ } else {
+ moduleNames.push(path.relative(m.context, m.resource));
}
- return path.relative(m.context, m.resource);
- }).join('_');
+ }
+
+ chunk.forEachModule(collectModuleNames);
+
+ const hash = crypto.createHash('sha256')
+ .update(moduleNames.join('_'))
+ .digest('hex');
+
+ return `${moduleNames[0]}-${hash.substr(0, 6)}`;
}),
// create cacheable common library bundle for all vue chunks
--
cgit v1.2.1
From f01295a651ae8172823ce58031492d0b6d5220e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Coutable?=
Date: Thu, 4 Jan 2018 22:36:11 +0100
Subject: Ignore the Migration/Datetime cop in a migration that fix a column
type to datetime_with_timezone
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Rémy Coutable
---
db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb
index be18c5866ae..eeecc7b1de0 100644
--- a/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb
+++ b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb
@@ -1,6 +1,6 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
-
+# rubocop:disable Migration/Datetime
class ScheduleIssuesClosedAtTypeChange < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
--
cgit v1.2.1
From 5152cc3bfb8d60814063e86c3776030aa8891e0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?=
Date: Thu, 4 Jan 2018 19:27:37 -0300
Subject: Fix a bug where charlock_holmes was used needlessly to encode strings
---
lib/gitlab/encoding_helper.rb | 26 ++++++++++++++++----------
lib/gitlab/git.rb | 2 +-
spec/lib/gitlab/encoding_helper_spec.rb | 18 ++++++++++++++++++
3 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/lib/gitlab/encoding_helper.rb b/lib/gitlab/encoding_helper.rb
index 6b53eb4533d..c0edcabc6fd 100644
--- a/lib/gitlab/encoding_helper.rb
+++ b/lib/gitlab/encoding_helper.rb
@@ -14,14 +14,7 @@ module Gitlab
ENCODING_CONFIDENCE_THRESHOLD = 50
def encode!(message)
- return nil unless message.respond_to?(:force_encoding)
- return message if message.encoding == Encoding::UTF_8 && message.valid_encoding?
-
- if message.respond_to?(:frozen?) && message.frozen?
- message = message.dup
- end
-
- message.force_encoding("UTF-8")
+ message = force_encode_utf8(message)
return message if message.valid_encoding?
# return message if message type is binary
@@ -35,6 +28,8 @@ module Gitlab
# encode and clean the bad chars
message.replace clean(message)
+ rescue ArgumentError
+ return nil
rescue
encoding = detect ? detect[:encoding] : "unknown"
"--broken encoding: #{encoding}"
@@ -54,8 +49,8 @@ module Gitlab
end
def encode_utf8(message)
- return nil unless message.is_a?(String)
- return message if message.encoding == Encoding::UTF_8 && message.valid_encoding?
+ message = force_encode_utf8(message)
+ return message if message.valid_encoding?
detect = CharlockHolmes::EncodingDetector.detect(message)
if detect && detect[:encoding]
@@ -69,6 +64,8 @@ module Gitlab
else
clean(message)
end
+ rescue ArgumentError
+ return nil
end
def encode_binary(s)
@@ -83,6 +80,15 @@ module Gitlab
private
+ def force_encode_utf8(message)
+ raise ArgumentError unless message.respond_to?(:force_encoding)
+ return message if message.encoding == Encoding::UTF_8 && message.valid_encoding?
+
+ message = message.dup if message.respond_to?(:frozen?) && message.frozen?
+
+ message.force_encoding("UTF-8")
+ end
+
def clean(message)
message.encode("UTF-16BE", undef: :replace, invalid: :replace, replace: "")
.encode("UTF-8")
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 1f7c35cafaa..71647099f83 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -11,7 +11,7 @@ module Gitlab
include Gitlab::EncodingHelper
def ref_name(ref)
- encode_utf8(ref).sub(/\Arefs\/(tags|heads|remotes)\//, '')
+ encode!(ref).sub(/\Arefs\/(tags|heads|remotes)\//, '')
end
def branch_name(ref)
diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb
index 87ec2698fc1..4e9367323cb 100644
--- a/spec/lib/gitlab/encoding_helper_spec.rb
+++ b/spec/lib/gitlab/encoding_helper_spec.rb
@@ -120,6 +120,24 @@ describe Gitlab::EncodingHelper do
it 'returns empty string on conversion errors' do
expect { ext_class.encode_utf8('') }.not_to raise_error(ArgumentError)
end
+
+ context 'with strings that can be forcefully encoded into utf8' do
+ let(:test_string) do
+ "refs/heads/FixSymbolsTitleDropdown".encode("ASCII-8BIT")
+ end
+ let(:expected_string) do
+ "refs/heads/FixSymbolsTitleDropdown".encode("UTF-8")
+ end
+
+ subject { ext_class.encode_utf8(test_string) }
+
+ it "doesn't use CharlockHolmes if the encoding can be forced into utf_8" do
+ expect(CharlockHolmes::EncodingDetector).not_to receive(:detect)
+
+ expect(subject).to eq(expected_string)
+ expect(subject.encoding.name).to eq('UTF-8')
+ end
+ end
end
describe '#clean' do
--
cgit v1.2.1
From 6fb4a533b74c861a1e533604da462efb6d309de0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Thu, 4 Jan 2018 23:33:17 +0100
Subject: Add feature test for resetting runner caches
---
spec/features/projects/pipelines/pipelines_spec.rb | 36 ++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index b87b47d0e1a..69a836292fc 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -545,6 +545,42 @@ describe 'Pipelines', :js do
end
end
end
+
+ describe 'Reset runner caches' do
+ let(:project) { create(:project, :repository) }
+
+ before do
+ create(:ci_empty_pipeline, status: 'success', project: project, sha: project.commit.id, ref: 'master')
+ project.team << [user, :master]
+ visit project_pipelines_path(project)
+ end
+
+ it 'has a clear caches button' do
+ expect(page).to have_link 'Clear runner caches'
+ end
+
+ describe 'user clicks the button' do
+ subject { click_link 'Clear runner caches' }
+
+ context 'when project already has jobs_cache_index' do
+ before do
+ project.update_attributes(jobs_cache_index: 1)
+ end
+
+ it 'increments jobs_cache_index' do
+ expect { subject }.to change { project.reload.jobs_cache_index }.by(1)
+ expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
+ end
+ end
+
+ context 'when project does not have jobs_cache_index' do
+ it 'sets jobs_cache_index to 1' do
+ expect { subject }.to change { project.reload.jobs_cache_index }.from(nil).to(1)
+ expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
+ end
+ end
+ end
+ end
end
context 'when user is not logged in' do
--
cgit v1.2.1
From 93e9793ce38bb9b5d519f5ca86cb56201549ef19 Mon Sep 17 00:00:00 2001
From: Mayra Cabrera
Date: Thu, 4 Jan 2018 22:35:41 +0000
Subject: Create Kubernetes based on Application Templates
---
app/models/concerns/deployment_platform.rb | 47 ++++++++++++++
app/models/project.rb | 7 +--
app/models/service.rb | 5 ++
...kubernetes-integration-application-template.yml | 5 ++
.../projects/import_export/export_file_spec.rb | 2 +-
spec/models/concerns/deployment_platform_spec.rb | 73 ++++++++++++++++++++++
spec/models/project_spec.rb | 19 ------
spec/models/service_spec.rb | 8 +++
8 files changed, 140 insertions(+), 26 deletions(-)
create mode 100644 app/models/concerns/deployment_platform.rb
create mode 100644 changelogs/unreleased/41056-create-cluster-from-kubernetes-integration-application-template.yml
create mode 100644 spec/models/concerns/deployment_platform_spec.rb
diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb
new file mode 100644
index 00000000000..e1373455e98
--- /dev/null
+++ b/app/models/concerns/deployment_platform.rb
@@ -0,0 +1,47 @@
+module DeploymentPlatform
+ def deployment_platform
+ @deployment_platform ||= find_cluster_platform_kubernetes
+ @deployment_platform ||= find_kubernetes_service_integration
+ @deployment_platform ||= build_cluster_and_deployment_platform
+ end
+
+ private
+
+ def find_cluster_platform_kubernetes
+ clusters.find_by(enabled: true)&.platform_kubernetes
+ end
+
+ def find_kubernetes_service_integration
+ services.deployment.reorder(nil).find_by(active: true)
+ end
+
+ def build_cluster_and_deployment_platform
+ return unless kubernetes_service_template
+
+ cluster = ::Clusters::Cluster.create(cluster_attributes_from_service_template)
+ cluster.platform_kubernetes if cluster.persisted?
+ end
+
+ def kubernetes_service_template
+ @kubernetes_service_template ||= KubernetesService.active.find_by_template
+ end
+
+ def cluster_attributes_from_service_template
+ {
+ name: 'kubernetes-template',
+ projects: [self],
+ provider_type: :user,
+ platform_type: :kubernetes,
+ platform_kubernetes_attributes: platform_kubernetes_attributes_from_service_template
+ }
+ end
+
+ def platform_kubernetes_attributes_from_service_template
+ {
+ api_url: kubernetes_service_template.api_url,
+ ca_pem: kubernetes_service_template.ca_pem,
+ token: kubernetes_service_template.token,
+ namespace: kubernetes_service_template.namespace
+ }
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 9c0bbf697e2..5d6c1b30587 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -19,6 +19,7 @@ class Project < ActiveRecord::Base
include Routable
include GroupDescendant
include Gitlab::SQL::Pattern
+ include DeploymentPlatform
extend Gitlab::ConfigHelper
extend Gitlab::CurrentSettings
@@ -904,12 +905,6 @@ class Project < ActiveRecord::Base
@ci_service ||= ci_services.reorder(nil).find_by(active: true)
end
- # TODO: This will be extended for multiple enviroment clusters
- def deployment_platform
- @deployment_platform ||= clusters.find_by(enabled: true)&.platform_kubernetes
- @deployment_platform ||= services.where(category: :deployment).reorder(nil).find_by(active: true)
- end
-
def monitoring_services
services.where(category: :monitoring)
end
diff --git a/app/models/service.rb b/app/models/service.rb
index 176b472e724..24ba3039707 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -44,6 +44,7 @@ class Service < ActiveRecord::Base
scope :pipeline_hooks, -> { where(pipeline_events: true, active: true) }
scope :wiki_page_hooks, -> { where(wiki_page_events: true, active: true) }
scope :external_issue_trackers, -> { issue_trackers.active.without_defaults }
+ scope :deployment, -> { where(category: 'deployment') }
default_value_for :category, 'common'
@@ -271,6 +272,10 @@ class Service < ActiveRecord::Base
nil
end
+ def self.find_by_template
+ find_by(template: true)
+ end
+
private
def cache_project_has_external_issue_tracker
diff --git a/changelogs/unreleased/41056-create-cluster-from-kubernetes-integration-application-template.yml b/changelogs/unreleased/41056-create-cluster-from-kubernetes-integration-application-template.yml
new file mode 100644
index 00000000000..2dd6fc5f1b5
--- /dev/null
+++ b/changelogs/unreleased/41056-create-cluster-from-kubernetes-integration-application-template.yml
@@ -0,0 +1,5 @@
+---
+title: Allow automatic creation of Kubernetes Integration from template
+merge_request: 16104
+author:
+type: added
diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb
index 461aa39d0ad..6732cf61767 100644
--- a/spec/features/projects/import_export/export_file_spec.rb
+++ b/spec/features/projects/import_export/export_file_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
# Integration test that exports a file using the Import/Export feature
# It looks up for any sensitive word inside the JSON, so if a sensitive word is found
-# we''l have to either include it adding the model that includes it to the +safe_list+
+# we'll have to either include it adding the model that includes it to the +safe_list+
# or make sure the attribute is blacklisted in the +import_export.yml+ configuration
feature 'Import/Export - project export integration test', :js do
include Select2Helper
diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb
new file mode 100644
index 00000000000..7bb89fe41dc
--- /dev/null
+++ b/spec/models/concerns/deployment_platform_spec.rb
@@ -0,0 +1,73 @@
+require 'rails_helper'
+
+describe DeploymentPlatform do
+ let(:project) { create(:project) }
+
+ describe '#deployment_platform' do
+ subject { project.deployment_platform }
+
+ context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service and a Kubernetes template configured' do
+ let!(:kubernetes_service) { create(:kubernetes_service, template: true) }
+
+ it 'returns a platform kubernetes' do
+ expect(subject).to be_a_kind_of(Clusters::Platforms::Kubernetes)
+ end
+
+ it 'creates a cluster and a platform kubernetes' do
+ expect { subject }
+ .to change { Clusters::Cluster.count }.by(1)
+ .and change { Clusters::Platforms::Kubernetes.count }.by(1)
+ end
+
+ it 'includes appropriate attributes for Cluster' do
+ cluster = subject.cluster
+ expect(cluster.name).to eq('kubernetes-template')
+ expect(cluster.project).to eq(project)
+ expect(cluster.provider_type).to eq('user')
+ expect(cluster.platform_type).to eq('kubernetes')
+ end
+
+ it 'creates a platform kubernetes' do
+ expect { subject }.to change { Clusters::Platforms::Kubernetes.count }.by(1)
+ end
+
+ it 'copies attributes from Clusters::Platform::Kubernetes template into the new Cluster::Platforms::Kubernetes' do
+ expect(subject.api_url).to eq(kubernetes_service.api_url)
+ expect(subject.ca_pem).to eq(kubernetes_service.ca_pem)
+ expect(subject.token).to eq(kubernetes_service.token)
+ expect(subject.namespace).to eq(kubernetes_service.namespace)
+ end
+ end
+
+ context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service and no Kubernetes template configured' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'when user configured kubernetes from CI/CD > Clusters' do
+ let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
+ let(:platform_kubernetes) { cluster.platform_kubernetes }
+
+ it 'returns the Kubernetes platform' do
+ expect(subject).to eq(platform_kubernetes)
+ end
+ end
+
+ context 'when user configured kubernetes integration from project services' do
+ let!(:kubernetes_service) { create(:kubernetes_service, project: project) }
+
+ it 'returns the Kubernetes service' do
+ expect(subject).to eq(kubernetes_service)
+ end
+ end
+
+ context 'when the cluster creation fails' do
+ let!(:kubernetes_service) { create(:kubernetes_service, template: true) }
+
+ before do
+ allow_any_instance_of(Clusters::Cluster).to receive(:persisted?).and_return(false)
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index cea22bbd184..3c2ed043b82 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -3137,25 +3137,6 @@ describe Project do
end
end
- describe '#deployment_platform' do
- subject { project.deployment_platform }
-
- let(:project) { create(:project) }
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let!(:kubernetes_service) { create(:kubernetes_service, project: project) }
-
- it { is_expected.to eq(kubernetes_service) }
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
- let(:platform_kubernetes) { cluster.platform_kubernetes }
-
- it { is_expected.to eq(platform_kubernetes) }
- end
- end
-
describe '#write_repository_config' do
set(:project) { create(:project, :repository) }
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 540615de117..ab6678cab38 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -272,4 +272,12 @@ describe Service do
expect(service.deprecation_message).to be_nil
end
end
+
+ describe '.find_by_template' do
+ let!(:kubernetes_service) { create(:kubernetes_service, template: true) }
+
+ it 'returns service template' do
+ expect(KubernetesService.find_by_template).to eq(kubernetes_service)
+ end
+ end
end
--
cgit v1.2.1
From 2cf2df8ea07703852247fdfbde73113d585aeb3d Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Thu, 4 Jan 2018 22:40:44 +0000
Subject: Update svg icons
---
app/assets/images/icons.json | 2 +-
app/assets/images/icons.svg | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json
index 1a418c2f88b..38c1faccbf1 100644
--- a/app/assets/images/icons.json
+++ b/app/assets/images/icons.json
@@ -1 +1 @@
-{"iconCount":186,"spriteSize":84748,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
+{"iconCount":186,"spriteSize":84748,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
\ No newline at end of file
diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg
index b426700d315..42f5377a10e 100644
--- a/app/assets/images/icons.svg
+++ b/app/assets/images/icons.svg
@@ -1 +1 @@
-
+
\ No newline at end of file
--
cgit v1.2.1
From 1859dc867092c1ba31335cf67047c9b6141466b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 00:02:26 +0100
Subject: Add back bottom margins for integration form
---
app/views/projects/clusters/_integration_form.html.haml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/views/projects/clusters/_integration_form.html.haml b/app/views/projects/clusters/_integration_form.html.haml
index 1eac2c9dc1f..9d593ffc021 100644
--- a/app/views/projects/clusters/_integration_form.html.haml
+++ b/app/views/projects/clusters/_integration_form.html.haml
@@ -1,6 +1,6 @@
= form_for @cluster, url: namespace_project_cluster_path(@project.namespace, @project, @cluster), as: :cluster do |field|
= form_errors(@cluster)
- .form-group
+ .form-group.append-bottom-20
%h5= s_('ClusterIntegration|Integration status')
%p
- if @cluster.enabled?
@@ -10,7 +10,7 @@
= s_('ClusterIntegration|Cluster integration is enabled for this project.')
- else
= s_('ClusterIntegration|Cluster integration is disabled for this project.')
- %label
+ %label.append-bottom-10
= field.hidden_field :enabled, { class: 'js-toggle-input'}
%button{ type: 'button',
--
cgit v1.2.1
From ccfd8a1240ddd4255f0dd561940d9325306d2a7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 00:06:43 +0100
Subject: Remove GCP cluster check page placeholder
---
app/views/projects/clusters/gcp/check.html.haml | 1 -
1 file changed, 1 deletion(-)
delete mode 100644 app/views/projects/clusters/gcp/check.html.haml
diff --git a/app/views/projects/clusters/gcp/check.html.haml b/app/views/projects/clusters/gcp/check.html.haml
deleted file mode 100644
index e965047ad7c..00000000000
--- a/app/views/projects/clusters/gcp/check.html.haml
+++ /dev/null
@@ -1 +0,0 @@
-Hello
--
cgit v1.2.1
From b4e9e07cdd5cbfdcbcf93c56a3b0b005602b40fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 00:09:33 +0100
Subject: Remove polling interval from GcpController
---
app/controllers/projects/clusters/gcp_controller.rb | 2 --
1 file changed, 2 deletions(-)
diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb
index 27c11ce554d..93b44623d3c 100644
--- a/app/controllers/projects/clusters/gcp_controller.rb
+++ b/app/controllers/projects/clusters/gcp_controller.rb
@@ -4,8 +4,6 @@ class Projects::Clusters::GcpController < Projects::ApplicationController
before_action :authorize_google_project_billing, only: [:new]
before_action :authorize_create_cluster!, only: [:new, :create]
- STATUS_POLLING_INTERVAL = 1.minute.to_i
-
def login
begin
state = generate_session_key_redirect(gcp_new_namespace_project_clusters_path.to_s)
--
cgit v1.2.1
From 92a72ce43749226a8dc75f7522d09125a5b4b8cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 00:10:40 +0100
Subject: Change CheckGcpProjectBillingWorker lease to 15s
---
app/workers/check_gcp_project_billing_worker.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb
index 254b0959063..5c3a4ff4a35 100644
--- a/app/workers/check_gcp_project_billing_worker.rb
+++ b/app/workers/check_gcp_project_billing_worker.rb
@@ -1,7 +1,7 @@
class CheckGcpProjectBillingWorker
include ApplicationWorker
- LEASE_TIMEOUT = 1.minute.to_i
+ LEASE_TIMEOUT = 15.seconds.to_i
def self.redis_shared_state_key_for(token)
"gitlab:gcp:#{token}:billing_enabled"
--
cgit v1.2.1
From 7d1fdcdc836921d2f2324265752107519f47a6de Mon Sep 17 00:00:00 2001
From: Drew Blessing
Date: Wed, 8 Nov 2017 15:32:12 -0600
Subject: Modify `LDAP::Person` to return username value based on attributes
`Gitlab::LDAP::Person` did not respect the LDAP attributes username
configuration and would simply return the uid value. There are
cases where users would like to specify a different username field
to allow more friendly GitLab usernames. For example, it's common
in AD to have sAMAccountName be an employee ID like `A12345` while
the local part of the email address is more human-friendly.
---
changelogs/unreleased/ldap_username_attributes.yml | 5 ++
lib/gitlab/ldap/adapter.rb | 2 +-
lib/gitlab/ldap/config.rb | 2 +-
lib/gitlab/ldap/person.rb | 36 +++++++++--
spec/lib/gitlab/ldap/adapter_spec.rb | 10 ++-
spec/lib/gitlab/ldap/person_spec.rb | 73 +++++++++++++++++++++-
spec/lib/gitlab/o_auth/user_spec.rb | 20 ++++++
7 files changed, 135 insertions(+), 13 deletions(-)
create mode 100644 changelogs/unreleased/ldap_username_attributes.yml
diff --git a/changelogs/unreleased/ldap_username_attributes.yml b/changelogs/unreleased/ldap_username_attributes.yml
new file mode 100644
index 00000000000..89bbca58fc9
--- /dev/null
+++ b/changelogs/unreleased/ldap_username_attributes.yml
@@ -0,0 +1,5 @@
+---
+title: Modify `LDAP::Person` to return username value based on attributes
+merge_request:
+author:
+type: fixed
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index 0afaa2306b5..76863e77dc3 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -74,7 +74,7 @@ module Gitlab
def user_options(fields, value, limit)
options = {
- attributes: Gitlab::LDAP::Person.ldap_attributes(config).compact.uniq,
+ attributes: Gitlab::LDAP::Person.ldap_attributes(config),
base: config.base
}
diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb
index c8f19cd52d5..0d9a554fc18 100644
--- a/lib/gitlab/ldap/config.rb
+++ b/lib/gitlab/ldap/config.rb
@@ -148,7 +148,7 @@ module Gitlab
def default_attributes
{
- 'username' => %w(uid userid sAMAccountName),
+ 'username' => %w(uid sAMAccountName userid),
'email' => %w(mail email userPrincipalName),
'name' => 'cn',
'first_name' => 'givenName',
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 38d7a9ba2f5..e81cec6ba1a 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -6,6 +6,8 @@ module Gitlab
# Source: http://ctogonewild.com/2009/09/03/bitmask-searches-in-ldap/
AD_USER_DISABLED = Net::LDAP::Filter.ex("userAccountControl:1.2.840.113556.1.4.803", "2")
+ InvalidEntryError = Class.new(StandardError)
+
attr_accessor :entry, :provider
def self.find_by_uid(uid, adapter)
@@ -29,11 +31,12 @@ module Gitlab
def self.ldap_attributes(config)
[
- 'dn', # Used in `dn`
- config.uid, # Used in `uid`
- *config.attributes['name'], # Used in `name`
- *config.attributes['email'] # Used in `email`
- ]
+ 'dn',
+ config.uid,
+ *config.attributes['name'],
+ *config.attributes['email'],
+ *config.attributes['username']
+ ].compact.uniq
end
def self.normalize_dn(dn)
@@ -60,6 +63,8 @@ module Gitlab
Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" }
@entry = entry
@provider = provider
+
+ validate_entry
end
def name
@@ -71,7 +76,13 @@ module Gitlab
end
def username
- uid
+ username = attribute_value(:username)
+
+ # Depending on the attribute, multiple values may
+ # be returned. We need only one for username.
+ # Ex. `uid` returns only one value but `mail` may
+ # return an array of multiple email addresses.
+ [username].flatten.first
end
def email
@@ -104,6 +115,19 @@ module Gitlab
entry.public_send(selected_attr) # rubocop:disable GitlabSecurity/PublicSend
end
+
+ def validate_entry
+ allowed_attrs = self.class.ldap_attributes(config).map(&:downcase)
+
+ # Net::LDAP::Entry transforms keys to symbols. Change to strings to compare.
+ entry_attrs = entry.attribute_names.map { |n| n.to_s.downcase }
+ invalid_attrs = entry_attrs - allowed_attrs
+
+ if invalid_attrs.any?
+ raise InvalidEntryError,
+ "#{self.class.name} initialized with Net::LDAP::Entry containing invalid attributes(s): #{invalid_attrs}"
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index d9ddb4326be..6132abd9b35 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -16,7 +16,7 @@ describe Gitlab::LDAP::Adapter do
expect(adapter).to receive(:ldap_search) do |arg|
expect(arg[:filter].to_s).to eq('(uid=johndoe)')
expect(arg[:base]).to eq('dc=example,dc=com')
- expect(arg[:attributes]).to match(%w{dn uid cn mail email userPrincipalName})
+ expect(arg[:attributes]).to match(ldap_attributes)
end.and_return({})
adapter.users('uid', 'johndoe')
@@ -26,7 +26,7 @@ describe Gitlab::LDAP::Adapter do
expect(adapter).to receive(:ldap_search).with(
base: 'uid=johndoe,ou=users,dc=example,dc=com',
scope: Net::LDAP::SearchScope_BaseObject,
- attributes: %w{dn uid cn mail email userPrincipalName},
+ attributes: ldap_attributes,
filter: nil
).and_return({})
@@ -63,7 +63,7 @@ describe Gitlab::LDAP::Adapter do
it 'uses the right uid attribute when non-default' do
stub_ldap_config(uid: 'sAMAccountName')
expect(adapter).to receive(:ldap_search).with(
- hash_including(attributes: %w{dn sAMAccountName cn mail email userPrincipalName})
+ hash_including(attributes: ldap_attributes)
).and_return({})
adapter.users('sAMAccountName', 'johndoe')
@@ -137,4 +137,8 @@ describe Gitlab::LDAP::Adapter do
end
end
end
+
+ def ldap_attributes
+ Gitlab::LDAP::Person.ldap_attributes(Gitlab::LDAP::Config.new('ldapmain'))
+ end
end
diff --git a/spec/lib/gitlab/ldap/person_spec.rb b/spec/lib/gitlab/ldap/person_spec.rb
index d204050ef66..ff29d9aa5be 100644
--- a/spec/lib/gitlab/ldap/person_spec.rb
+++ b/spec/lib/gitlab/ldap/person_spec.rb
@@ -8,13 +8,16 @@ describe Gitlab::LDAP::Person do
before do
stub_ldap_config(
options: {
+ 'uid' => 'uid',
'attributes' => {
- 'name' => 'cn',
- 'email' => %w(mail email userPrincipalName)
+ 'name' => 'cn',
+ 'email' => %w(mail email userPrincipalName),
+ 'username' => username_attribute
}
}
)
end
+ let(:username_attribute) { %w(uid sAMAccountName userid) }
describe '.normalize_dn' do
subject { described_class.normalize_dn(given) }
@@ -44,6 +47,34 @@ describe Gitlab::LDAP::Person do
end
end
+ describe '.ldap_attributes' do
+ it 'returns a compact and unique array' do
+ stub_ldap_config(
+ options: {
+ 'uid' => nil,
+ 'attributes' => {
+ 'name' => 'cn',
+ 'email' => 'mail',
+ 'username' => %w(uid mail memberof)
+ }
+ }
+ )
+ config = Gitlab::LDAP::Config.new('ldapmain')
+ ldap_attributes = described_class.ldap_attributes(config)
+
+ expect(ldap_attributes).to match_array(%w(dn uid cn mail memberof))
+ end
+ end
+
+ describe '.validate_entry' do
+ it 'raises InvalidEntryError' do
+ entry['foo'] = 'bar'
+
+ expect { described_class.new(entry, 'ldapmain') }
+ .to raise_error(Gitlab::LDAP::Person::InvalidEntryError)
+ end
+ end
+
describe '#name' do
it 'uses the configured name attribute and handles values as an array' do
name = 'John Doe'
@@ -72,6 +103,44 @@ describe Gitlab::LDAP::Person do
end
end
+ describe '#username' do
+ context 'with default uid username attribute' do
+ let(:username_attribute) { 'uid' }
+
+ it 'returns the proper username value' do
+ attr_value = 'johndoe'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+
+ context 'with a different username attribute' do
+ let(:username_attribute) { 'sAMAccountName' }
+
+ it 'returns the proper username value' do
+ attr_value = 'johndoe'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+
+ context 'with a non-standard username attribute' do
+ let(:username_attribute) { 'mail' }
+
+ it 'returns the proper username value' do
+ attr_value = 'john.doe@example.com'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+ end
+
def assert_generic_test(test_description, got, expected)
test_failure_message = "Failed test description: '#{test_description}'\n\n expected: #{expected}\n got: #{got}"
expect(got).to eq(expected), test_failure_message
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 6334bcd0156..45fff4c5787 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -275,6 +275,26 @@ describe Gitlab::OAuth::User do
end
end
+ context 'and a corresponding LDAP person with a non-default username' do
+ before do
+ allow(ldap_user).to receive(:uid) { uid }
+ allow(ldap_user).to receive(:username) { 'johndoe@example.com' }
+ allow(ldap_user).to receive(:email) { %w(johndoe@example.com john2@example.com) }
+ allow(ldap_user).to receive(:dn) { dn }
+ end
+
+ context 'and no account for the LDAP user' do
+ it 'creates a user favoring the LDAP username and strips email domain' do
+ allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
+
+ oauth_user.save
+
+ expect(gl_user).to be_valid
+ expect(gl_user.username).to eql 'johndoe'
+ end
+ end
+ end
+
context "and no corresponding LDAP person" do
before do
allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil)
--
cgit v1.2.1
From 27a590f901fc7504f70069d884c532e9a49a49e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 00:37:00 +0100
Subject: Fix jobs_cache_index migration class name
---
db/migrate/20171222183504_add_jobs_cache_index_to_project.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb
index 58ac0177420..607e9d027d7 100644
--- a/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb
+++ b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb
@@ -1,7 +1,7 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
-class AddCacheIndexToProject < ActiveRecord::Migration
+class AddJobsCacheIndexToProject < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
--
cgit v1.2.1
From 571db1a27fa9df038eb56a1c6ae049fc01b48a6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 00:35:19 +0100
Subject: Return list of billing enabled projects
---
app/services/check_gcp_project_billing_service.rb | 2 +-
app/workers/check_gcp_project_billing_worker.rb | 4 ++--
spec/services/check_gcp_project_billing_service_spec.rb | 9 +++++----
spec/workers/check_gcp_project_billing_worker_spec.rb | 4 ++--
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/app/services/check_gcp_project_billing_service.rb b/app/services/check_gcp_project_billing_service.rb
index 88e9d7de8de..854adf2177d 100644
--- a/app/services/check_gcp_project_billing_service.rb
+++ b/app/services/check_gcp_project_billing_service.rb
@@ -1,7 +1,7 @@
class CheckGcpProjectBillingService
def execute(token)
client = GoogleApi::CloudPlatform::Client.new(token, nil)
- client.projects_list.any? do |project|
+ client.projects_list.select do |project|
client.projects_get_billing_info(project.name).billingEnabled
end
end
diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb
index 5c3a4ff4a35..8d80f9c9be3 100644
--- a/app/workers/check_gcp_project_billing_worker.rb
+++ b/app/workers/check_gcp_project_billing_worker.rb
@@ -11,9 +11,9 @@ class CheckGcpProjectBillingWorker
return unless token
return unless try_obtain_lease_for(token)
- billing_enabled = CheckGcpProjectBillingService.new.execute(token)
+ billing_enabled_projects = CheckGcpProjectBillingService.new.execute(token)
Gitlab::Redis::SharedState.with do |redis|
- redis.set(self.class.redis_shared_state_key_for(token), billing_enabled)
+ redis.set(self.class.redis_shared_state_key_for(token), !billing_enabled_projects.empty?)
end
end
diff --git a/spec/services/check_gcp_project_billing_service_spec.rb b/spec/services/check_gcp_project_billing_service_spec.rb
index 1b23b43b0d5..f0e39ba6f49 100644
--- a/spec/services/check_gcp_project_billing_service_spec.rb
+++ b/spec/services/check_gcp_project_billing_service_spec.rb
@@ -2,13 +2,14 @@ require 'spec_helper'
describe CheckGcpProjectBillingService do
let(:service) { described_class.new }
+ let(:projects) { [double(name: 'first_project'), double(name: 'second_project')] }
describe '#execute' do
before do
expect_any_instance_of(GoogleApi::CloudPlatform::Client)
- .to receive(:projects_list).and_return([double(name: 'project_name')])
+ .to receive(:projects_list).and_return(projects)
- expect_any_instance_of(GoogleApi::CloudPlatform::Client)
+ allow_any_instance_of(GoogleApi::CloudPlatform::Client)
.to receive_message_chain(:projects_get_billing_info, :billingEnabled)
.and_return(project_billing_enabled)
end
@@ -18,13 +19,13 @@ describe CheckGcpProjectBillingService do
context 'google account has a billing enabled gcp project' do
let(:project_billing_enabled) { true }
- it { is_expected.to eq(true) }
+ it { is_expected.to eq(projects) }
end
context 'google account does not have a billing enabled gcp project' do
let(:project_billing_enabled) { false }
- it { is_expected.to eq(false) }
+ it { is_expected.to eq([]) }
end
end
end
diff --git a/spec/workers/check_gcp_project_billing_worker_spec.rb b/spec/workers/check_gcp_project_billing_worker_spec.rb
index d7984ad0c1b..cdb114749ee 100644
--- a/spec/workers/check_gcp_project_billing_worker_spec.rb
+++ b/spec/workers/check_gcp_project_billing_worker_spec.rb
@@ -11,7 +11,7 @@ describe CheckGcpProjectBillingWorker do
end
it 'calls the service' do
- expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute)
+ expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return([double])
subject
end
@@ -19,7 +19,7 @@ describe CheckGcpProjectBillingWorker do
it 'stores billing status in redis' do
redis_double = double
- expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return(true)
+ expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return([double])
expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double)
expect(redis_double).to receive(:set).with(described_class.redis_shared_state_key_for(token), anything)
--
cgit v1.2.1
From f4c2eeb2a6885821f8b72f46deb49a55a062bd8c Mon Sep 17 00:00:00 2001
From: Eric Eastwood
Date: Thu, 4 Jan 2018 16:15:09 -0600
Subject: Fix custom name in branch creation for issue in Firefox
Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/41563
`event.srcElement` is non-standard,
https://developer.mozilla.org/en-US/docs/Web/API/Event/srcElement
---
app/assets/javascripts/create_merge_request_dropdown.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js
index 23425672b16..eedbd3feeb5 100644
--- a/app/assets/javascripts/create_merge_request_dropdown.js
+++ b/app/assets/javascripts/create_merge_request_dropdown.js
@@ -276,13 +276,13 @@ export default class CreateMergeRequestDropdown {
let target;
let value;
- if (event.srcElement === this.branchInput) {
+ if (event.target === this.branchInput) {
target = 'branch';
value = this.branchInput.value;
- } else if (event.srcElement === this.refInput) {
+ } else if (event.target === this.refInput) {
target = 'ref';
- value = event.srcElement.value.slice(0, event.srcElement.selectionStart) +
- event.srcElement.value.slice(event.srcElement.selectionEnd);
+ value = event.target.value.slice(0, event.target.selectionStart) +
+ event.target.value.slice(event.target.selectionEnd);
} else {
return false;
}
--
cgit v1.2.1
From b27b1e60f0c7c718ae0502d380b1cb0c7fc15700 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 01:46:52 +0100
Subject: Rename cache_index in safe_model_attributes
---
spec/lib/gitlab/import_export/safe_model_attributes.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 7e09f486854..ec577903eb5 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -459,7 +459,7 @@ Project:
- delete_error
- merge_requests_ff_only_enabled
- merge_requests_rebase_enabled
-- cache_index
+- jobs_cache_index
Author:
- name
ProjectFeature:
--
cgit v1.2.1
From 2b00c91a576f922e2f94756567d1e3601ce11248 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 03:11:04 +0100
Subject: Fix jobs cache reset functional spec
---
spec/features/projects/pipelines/pipelines_spec.rb | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index e8fc56ab11e..592c99fc64a 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -551,7 +551,7 @@ describe 'Pipelines', :js do
before do
create(:ci_empty_pipeline, status: 'success', project: project, sha: project.commit.id, ref: 'master')
- project.team << [user, :master]
+ project.add_master(user)
visit project_pipelines_path(project)
end
@@ -560,22 +560,20 @@ describe 'Pipelines', :js do
end
describe 'user clicks the button' do
- subject { click_link 'Clear runner caches' }
-
context 'when project already has jobs_cache_index' do
before do
project.update_attributes(jobs_cache_index: 1)
end
it 'increments jobs_cache_index' do
- expect { subject }.to change { project.reload.jobs_cache_index }.by(1)
+ click_link 'Clear runner caches'
expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
end
end
context 'when project does not have jobs_cache_index' do
it 'sets jobs_cache_index to 1' do
- expect { subject }.to change { project.reload.jobs_cache_index }.from(nil).to(1)
+ click_link 'Clear runner caches'
expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
end
end
--
cgit v1.2.1
From 8b3b28b8d81acc719701a3c2bfc05b6f7c22c4f2 Mon Sep 17 00:00:00 2001
From: Lin Jen-Shin
Date: Fri, 5 Jan 2018 15:32:31 +0800
Subject: Just try to detect and assign once
---
app/models/concerns/deployment_platform.rb | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb
index e1373455e98..89d0474a596 100644
--- a/app/models/concerns/deployment_platform.rb
+++ b/app/models/concerns/deployment_platform.rb
@@ -1,8 +1,9 @@
module DeploymentPlatform
def deployment_platform
- @deployment_platform ||= find_cluster_platform_kubernetes
- @deployment_platform ||= find_kubernetes_service_integration
- @deployment_platform ||= build_cluster_and_deployment_platform
+ @deployment_platform ||=
+ find_cluster_platform_kubernetes ||
+ find_kubernetes_service_integration ||
+ build_cluster_and_deployment_platform
end
private
--
cgit v1.2.1
From 27a75ea1757d1c1b67bf501ec333221ed5e92d04 Mon Sep 17 00:00:00 2001
From: Jan Provaznik
Date: Wed, 20 Dec 2017 10:01:21 +0100
Subject: Backport 'Rebase' feature from EE to CE
When a project uses fast-forward merging strategy user has
to rebase MRs to target branch before it can be merged.
Now user can do rebase in UI by clicking 'Rebase' button
instead of doing rebase locally.
This feature was already present in EE, this is only backport
of the feature to CE. Couple of changes:
* removed rebase license check
* renamed migration (changed timestamp)
Closes #40301
---
.../components/states/mr_widget_rebase.vue | 133 ++++++++++++++++++++
.../vue_merge_request_widget/dependencies.js | 1 +
.../vue_merge_request_widget/mr_widget_options.js | 3 +
.../services/mr_widget_service.js | 4 +
.../stores/get_state_key.js | 2 +
.../stores/mr_widget_store.js | 8 ++
.../vue_merge_request_widget/stores/state_maps.js | 3 +
.../projects/merge_requests_controller.rb | 17 +++
app/models/merge_request.rb | 9 +-
app/models/repository.rb | 7 ++
app/presenters/merge_request_presenter.rb | 18 +++
app/serializers/merge_request_basic_entity.rb | 1 +
app/serializers/merge_request_widget_entity.rb | 10 ++
app/services/merge_requests/rebase_service.rb | 30 +++++
.../merge_requests/working_copy_base_service.rb | 24 ++++
.../_merge_request_fast_forward_settings.html.haml | 2 +-
.../_merge_request_rebase_settings.html.haml | 2 +-
app/workers/all_queues.yml | 1 +
app/workers/rebase_worker.rb | 12 ++
changelogs/unreleased/40301-rebase.yml | 5 +
config/routes/project.rb | 1 +
...3729_add_rebase_commit_sha_to_merge_requests.rb | 7 ++
db/schema.rb | 3 +-
.../project/merge_requests/fast_forward_merge.md | 4 +-
.../project/merge_requests/img/ff_merge_mr.png | Bin 21380 -> 0 bytes
.../project/merge_requests/img/ff_merge_rebase.png | Bin 0 -> 26945 bytes
features/project/ff_merge_requests.feature | 17 +++
features/steps/project/ff_merge_requests.rb | 22 ++++
lib/gitlab/git/operation_service.rb | 5 +
.../projects/merge_requests_controller_spec.rb | 58 +++++++++
.../api/schemas/entities/merge_request_basic.json | 1 +
.../api/schemas/entities/merge_request_widget.json | 6 +-
.../components/mr_widget_rebase_spec.js | 115 ++++++++++++++++++
spec/models/merge_request_spec.rb | 46 +++++++
spec/models/project_spec.rb | 19 ++-
spec/presenters/merge_request_presenter_spec.rb | 63 ++++++++++
.../merge_request_widget_entity_spec.rb | 16 +++
.../services/merge_requests/rebase_service_spec.rb | 134 +++++++++++++++++++++
.../projects/merge_requests/show.html.haml_spec.rb | 2 +
spec/workers/rebase_worker_spec.rb | 27 +++++
40 files changed, 825 insertions(+), 13 deletions(-)
create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
create mode 100644 app/services/merge_requests/rebase_service.rb
create mode 100644 app/services/merge_requests/working_copy_base_service.rb
create mode 100644 app/workers/rebase_worker.rb
create mode 100644 changelogs/unreleased/40301-rebase.yml
create mode 100644 db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests.rb
delete mode 100644 doc/user/project/merge_requests/img/ff_merge_mr.png
create mode 100644 doc/user/project/merge_requests/img/ff_merge_rebase.png
create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js
create mode 100644 spec/services/merge_requests/rebase_service_spec.rb
create mode 100644 spec/workers/rebase_worker_spec.rb
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
new file mode 100644
index 00000000000..09276ba2769
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+ Rebase in progress
+
+
+
+
+ Fast-forward merge is not possible.
+ Rebase the source branch onto
+ {{mr.targetBranch}}
+ to allow this merge request to be merged.
+
+
+
+
+
+
+ Fast-forward merge is not possible.
+ Rebase the source branch onto the target branch or merge target
+ branch into source branch to allow this merge request to be merged.
+
+
+ {{rebasingError}}
+
+
+
+
+
+
diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
index 5bd8b99420a..940f3d9b2d0 100644
--- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js
+++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
@@ -32,6 +32,7 @@ export { default as UnresolvedDiscussionsState } from './components/states/mr_wi
export { default as PipelineBlockedState } from './components/states/mr_widget_pipeline_blocked';
export { default as PipelineFailedState } from './components/states/mr_widget_pipeline_failed';
export { default as MergeWhenPipelineSucceedsState } from './components/states/mr_widget_merge_when_pipeline_succeeds';
+export { default as RebaseState } from './components/states/mr_widget_rebase.vue';
export { default as AutoMergeFailed } from './components/states/mr_widget_auto_merge_failed';
export { default as CheckingState } from './components/states/mr_widget_checking';
export { default as MRWidgetStore } from './stores/mr_widget_store';
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
index fdae06200de..2075f8e4fec 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js
@@ -10,6 +10,7 @@ import {
MergedState,
ClosedState,
MergingState,
+ RebaseState,
WipState,
ArchivedState,
ConflictsState,
@@ -79,6 +80,7 @@ export default {
ciEnvironmentsStatusPath: store.ciEnvironmentsStatusPath,
statusPath: store.statusPath,
mergeActionsContentPath: store.mergeActionsContentPath,
+ rebasePath: store.rebasePath,
};
return new MRWidgetService(endpoints);
},
@@ -232,6 +234,7 @@ export default {
'mr-widget-pipeline-failed': PipelineFailedState,
'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState,
'mr-widget-auto-merge-failed': AutoMergeFailed,
+ 'mr-widget-rebase': RebaseState,
},
template: `
diff --git a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
index 7c0bbdd403f..fecbfec2214 100644
--- a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
+++ b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
@@ -37,6 +37,10 @@ export default class MRWidgetService {
return axios.get(this.endpoints.mergeActionsContentPath);
}
+ rebase() {
+ return axios.post(this.endpoints.rebasePath);
+ }
+
static stopEnvironment(url) {
return axios.post(url);
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
index 2bace3311c8..f7f0c1b6cb7 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
@@ -25,6 +25,8 @@ export default function deviseState(data) {
return this.mergeError ? stateKey.autoMergeFailed : stateKey.mergeWhenPipelineSucceeds;
} else if (!this.canMerge) {
return stateKey.notAllowedToMerge;
+ } else if (this.shouldBeRebased) {
+ return stateKey.rebase;
} else if (this.canBeMerged) {
return stateKey.readyToMerge;
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 474c17ec133..ed004b3bb08 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -26,6 +26,7 @@ export default class MergeRequestStore {
this.divergedCommitsCount = data.diverged_commits_count;
this.pipeline = data.pipeline || {};
this.deployments = this.deployments || data.deployments || [];
+ this.initRebase(data);
if (data.issues_links) {
const links = data.issues_links;
@@ -124,6 +125,13 @@ export default class MergeRequestStore {
return this.state === stateKey.nothingToMerge;
}
+ initRebase(data) {
+ this.canPushToSourceBranch = data.can_push_to_source_branch;
+ this.rebaseInProgress = data.rebase_in_progress;
+ this.approvalsLeft = !data.approved;
+ this.rebasePath = data.rebase_path;
+ }
+
static buildMetrics(metrics) {
if (!metrics) {
return {};
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
index de980c175fb..29d5bd4a1da 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
@@ -17,6 +17,7 @@ const stateToComponentMap = {
failedToMerge: 'mr-widget-failed-to-merge',
autoMergeFailed: 'mr-widget-auto-merge-failed',
shaMismatch: 'mr-widget-sha-mismatch',
+ rebase: 'mr-widget-rebase',
};
const statesToShowHelpWidget = [
@@ -29,6 +30,7 @@ const statesToShowHelpWidget = [
'pipelineFailed',
'pipelineBlocked',
'autoMergeFailed',
+ 'rebase',
];
export const stateKey = {
@@ -46,6 +48,7 @@ export const stateKey = {
mergeWhenPipelineSucceeds: 'mergeWhenPipelineSucceeds',
notAllowedToMerge: 'notAllowedToMerge',
readyToMerge: 'readyToMerge',
+ rebase: 'rebase',
};
export default {
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 6b59c8461a3..2e8a738b6d9 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -10,6 +10,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :authorize_update_issuable!, only: [:close, :edit, :update, :remove_wip, :sort]
before_action :set_issuables_index, only: [:index]
before_action :authenticate_user!, only: [:assign_related_issues]
+ before_action :check_user_can_push_to_source_branch!, only: [:rebase]
def index
@merge_requests = @issuables
@@ -223,6 +224,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
render json: environments
end
+ def rebase
+ RebaseWorker.perform_async(@merge_request.id, current_user.id)
+
+ render nothing: true, status: 200
+ end
+
protected
alias_method :subscribable_resource, :merge_request
@@ -322,4 +329,14 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@finder_type = MergeRequestsFinder
super
end
+
+ def check_user_can_push_to_source_branch!
+ return access_denied! unless @merge_request.source_branch_exists?
+
+ access_check = ::Gitlab::UserAccess
+ .new(current_user, project: @merge_request.source_project)
+ .can_push_to_branch?(@merge_request.source_branch)
+
+ access_denied! unless access_check
+ end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index c39789b047d..ef58816937c 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -156,6 +156,13 @@ class MergeRequest < ActiveRecord::Base
'!'
end
+ def rebase_in_progress?
+ # The source project can be deleted
+ return false unless source_project
+
+ source_project.repository.rebase_in_progress?(id)
+ end
+
# Use this method whenever you need to make sure the head_pipeline is synced with the
# branch head commit, for example checking if a merge request can be merged.
# For more information check: https://gitlab.com/gitlab-org/gitlab-ce/issues/40004
@@ -607,7 +614,7 @@ class MergeRequest < ActiveRecord::Base
check_if_can_be_merged
- can_be_merged?
+ can_be_merged? && !should_be_rebased?
end
def mergeable_state?(skip_ci_check: false)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index b1fd981965c..4bedcbfb6a2 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1099,6 +1099,13 @@ class Repository
@project.repository_storage_path
end
+ def rebase(user, merge_request)
+ raw.rebase(user, merge_request.id, branch: merge_request.source_branch,
+ branch_sha: merge_request.source_branch_sha,
+ remote_repository: merge_request.target_project.repository.raw,
+ remote_branch: merge_request.target_branch)
+ end
+
private
# TODO Generice finder, later split this on finders by Ref or Oid
diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb
index ab4c87c0169..c6806b7cc26 100644
--- a/app/presenters/merge_request_presenter.rb
+++ b/app/presenters/merge_request_presenter.rb
@@ -76,6 +76,12 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
end
+ def rebase_path
+ if !rebase_in_progress? && should_be_rebased? && user_can_push_to_source_branch?
+ rebase_project_merge_request_path(project, merge_request)
+ end
+ end
+
def target_branch_tree_path
if target_branch_exists?
project_tree_path(project, target_branch)
@@ -152,6 +158,10 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
user_can_collaborate_with_project? && can_be_cherry_picked?
end
+ def can_push_to_source_branch?
+ source_branch_exists? && user_can_push_to_source_branch?
+ end
+
private
def conflicts
@@ -174,6 +184,14 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end.sort.to_sentence
end
+ def user_can_push_to_source_branch?
+ return false unless source_branch_exists?
+
+ ::Gitlab::UserAccess
+ .new(current_user, project: source_project)
+ .can_push_to_branch?(source_branch)
+ end
+
def user_can_collaborate_with_project?
can?(current_user, :push_code, project) ||
(current_user && current_user.already_forked?(project))
diff --git a/app/serializers/merge_request_basic_entity.rb b/app/serializers/merge_request_basic_entity.rb
index d54a6516aed..e4aec977f01 100644
--- a/app/serializers/merge_request_basic_entity.rb
+++ b/app/serializers/merge_request_basic_entity.rb
@@ -4,4 +4,5 @@ class MergeRequestBasicEntity < IssuableSidebarEntity
expose :merge_error
expose :state
expose :source_branch_exists?, as: :source_branch_exists
+ expose :rebase_in_progress?, as: :rebase_in_progress
end
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index e905e6876c2..48cd2317f46 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -23,6 +23,16 @@ class MergeRequestWidgetEntity < IssuableEntity
MergeRequestMetricsEntity.new(metrics).as_json
end
+ expose :rebase_commit_sha
+ expose :rebase_in_progress?, as: :rebase_in_progress
+
+ expose :can_push_to_source_branch do |merge_request|
+ presenter(merge_request).can_push_to_source_branch?
+ end
+ expose :rebase_path do |merge_request|
+ presenter(merge_request).rebase_path
+ end
+
# User entities
expose :merge_user, using: UserEntity
diff --git a/app/services/merge_requests/rebase_service.rb b/app/services/merge_requests/rebase_service.rb
new file mode 100644
index 00000000000..0d5a25fa28e
--- /dev/null
+++ b/app/services/merge_requests/rebase_service.rb
@@ -0,0 +1,30 @@
+module MergeRequests
+ class RebaseService < MergeRequests::WorkingCopyBaseService
+ def execute(merge_request)
+ @merge_request = merge_request
+
+ if rebase
+ success
+ else
+ error('Failed to rebase. Should be done manually')
+ end
+ end
+
+ def rebase
+ if merge_request.rebase_in_progress?
+ log_error('Rebase task canceled: Another rebase is already in progress', save_message_on_model: true)
+ return false
+ end
+
+ rebase_sha = repository.rebase(current_user, merge_request)
+
+ merge_request.update_attributes(rebase_commit_sha: rebase_sha)
+
+ true
+ rescue => e
+ log_error('Failed to rebase branch:')
+ log_error(e.message, save_message_on_model: true)
+ false
+ end
+ end
+end
diff --git a/app/services/merge_requests/working_copy_base_service.rb b/app/services/merge_requests/working_copy_base_service.rb
new file mode 100644
index 00000000000..186e05bf966
--- /dev/null
+++ b/app/services/merge_requests/working_copy_base_service.rb
@@ -0,0 +1,24 @@
+module MergeRequests
+ class WorkingCopyBaseService < MergeRequests::BaseService
+ attr_reader :merge_request
+
+ def source_project
+ @source_project ||= merge_request.source_project
+ end
+
+ def target_project
+ @target_project ||= merge_request.target_project
+ end
+
+ def log_error(message, save_message_on_model: false)
+ Gitlab::GitLogger.error("#{self.class.name} error (#{merge_request.to_reference(full: true)}): #{message}")
+
+ merge_request.update(merge_error: message) if save_message_on_model
+ end
+
+ # Don't try to print expensive instance variables.
+ def inspect
+ "#<#{self.class} #{merge_request.to_reference(full: true)}>"
+ end
+ end
+end
diff --git a/app/views/projects/_merge_request_fast_forward_settings.html.haml b/app/views/projects/_merge_request_fast_forward_settings.html.haml
index 9d357293a2f..8129c72feb2 100644
--- a/app/views/projects/_merge_request_fast_forward_settings.html.haml
+++ b/app/views/projects/_merge_request_fast_forward_settings.html.haml
@@ -10,4 +10,4 @@
No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.
%br
%span.descr
- When fast-forward merge is not possible, the user must first rebase locally.
+ When fast-forward merge is not possible, the user is given the option to rebase.
diff --git a/app/views/projects/_merge_request_rebase_settings.html.haml b/app/views/projects/_merge_request_rebase_settings.html.haml
index c52e09573a6..54e0b73d24c 100644
--- a/app/views/projects/_merge_request_rebase_settings.html.haml
+++ b/app/views/projects/_merge_request_rebase_settings.html.haml
@@ -10,4 +10,4 @@
This way you could make sure that if this merge request would build, after merging to target branch it would also build.
%br
%span.descr
- When fast-forward merge is not possible, the user must first rebase locally.
+ When fast-forward merge is not possible, the user is given the option to rebase.
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 268b7028fd9..fafd9e5ef00 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -89,6 +89,7 @@
- project_service
- propagate_service_template
- reactive_caching
+- rebase
- repository_fork
- repository_import
- storage_migrator
diff --git a/app/workers/rebase_worker.rb b/app/workers/rebase_worker.rb
new file mode 100644
index 00000000000..090987778a2
--- /dev/null
+++ b/app/workers/rebase_worker.rb
@@ -0,0 +1,12 @@
+class RebaseWorker
+ include ApplicationWorker
+
+ def perform(merge_request_id, current_user_id)
+ current_user = User.find(current_user_id)
+ merge_request = MergeRequest.find(merge_request_id)
+
+ MergeRequests::RebaseService
+ .new(merge_request.source_project, current_user)
+ .execute(merge_request)
+ end
+end
diff --git a/changelogs/unreleased/40301-rebase.yml b/changelogs/unreleased/40301-rebase.yml
new file mode 100644
index 00000000000..1c0fc0cd8ae
--- /dev/null
+++ b/changelogs/unreleased/40301-rebase.yml
@@ -0,0 +1,5 @@
+---
+title: Allow user to rebase merge requests.
+merge_request:
+author:
+type: added
diff --git a/config/routes/project.rb b/config/routes/project.rb
index c3ad53a387f..1354c4c5537 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -96,6 +96,7 @@ constraints(ProjectUrlConstrainer.new) do
post :toggle_subscription
post :remove_wip
post :assign_related_issues
+ post :rebase
scope constraints: { format: nil }, action: :show do
get :commits, defaults: { tab: 'commits' }
diff --git a/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests.rb b/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests.rb
new file mode 100644
index 00000000000..2ce156fa92e
--- /dev/null
+++ b/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests.rb
@@ -0,0 +1,7 @@
+class AddRebaseCommitShaToMergeRequests < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column :merge_requests, :rebase_commit_sha, :string
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 778d66f16b0..740e80ccfd4 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20171229225929) do
+ActiveRecord::Schema.define(version: 20171230123729) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -1099,6 +1099,7 @@ ActiveRecord::Schema.define(version: 20171229225929) do
t.string "merge_jid"
t.boolean "discussion_locked"
t.integer "latest_merge_request_diff_id"
+ t.string "rebase_commit_sha"
end
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
diff --git a/doc/user/project/merge_requests/fast_forward_merge.md b/doc/user/project/merge_requests/fast_forward_merge.md
index 085170d9f03..3cd91a185e3 100644
--- a/doc/user/project/merge_requests/fast_forward_merge.md
+++ b/doc/user/project/merge_requests/fast_forward_merge.md
@@ -9,7 +9,7 @@ When the fast-forward merge ([`--ff-only`][ffonly]) setting is enabled, no merge
commits will be created and all merges are fast-forwarded, which means that
merging is only allowed if the branch could be fast-forwarded.
-When a fast-forward merge is not possible, the user must rebase the branch manually.
+When a fast-forward merge is not possible, the user is given the option to rebase.
## Use cases
@@ -25,7 +25,7 @@ merge commits. In such cases, the fast-forward merge is the perfect candidate.
Now, when you visit the merge request page, you will be able to accept it
**only if a fast-forward merge is possible**.
-
+
If the target branch is ahead of the source branch, you need to rebase the
source branch locally before you will be able to do a fast-forward merge.
diff --git a/doc/user/project/merge_requests/img/ff_merge_mr.png b/doc/user/project/merge_requests/img/ff_merge_mr.png
deleted file mode 100644
index 241cc990343..00000000000
Binary files a/doc/user/project/merge_requests/img/ff_merge_mr.png and /dev/null differ
diff --git a/doc/user/project/merge_requests/img/ff_merge_rebase.png b/doc/user/project/merge_requests/img/ff_merge_rebase.png
new file mode 100644
index 00000000000..f6139f189ce
Binary files /dev/null and b/doc/user/project/merge_requests/img/ff_merge_rebase.png differ
diff --git a/features/project/ff_merge_requests.feature b/features/project/ff_merge_requests.feature
index 995e52f9332..39035d551d1 100644
--- a/features/project/ff_merge_requests.feature
+++ b/features/project/ff_merge_requests.feature
@@ -22,3 +22,20 @@ Feature: Project Ff Merge Requests
Then I should see ff-only merge button
When I accept this merge request
Then I should see merged request
+
+ @javascript
+ Scenario: I do rebase before ff-only merge
+ Given ff merge enabled
+ And rebase before merge enabled
+ When I visit merge request page "Bug NS-05"
+ Then I should see rebase button
+ When I press rebase button
+ Then I should see rebase in progress message
+
+ @javascript
+ Scenario: I do rebase before regular merge
+ Given rebase before merge enabled
+ When I visit merge request page "Bug NS-05"
+ Then I should see rebase button
+ When I press rebase button
+ Then I should see rebase in progress message
diff --git a/features/steps/project/ff_merge_requests.rb b/features/steps/project/ff_merge_requests.rb
index d68fe71e16e..27efcfd65b6 100644
--- a/features/steps/project/ff_merge_requests.rb
+++ b/features/steps/project/ff_merge_requests.rb
@@ -17,6 +17,10 @@ class Spinach::Features::ProjectFfMergeRequests < Spinach::FeatureSteps
author: project.users.first)
end
+ step 'merge request is mergeable' do
+ expect(page).to have_button 'Merge'
+ end
+
step 'I should see ff-only merge button' do
expect(page).to have_content "Fast-forward merge without a merge commit"
expect(page).to have_button 'Merge'
@@ -45,6 +49,10 @@ class Spinach::Features::ProjectFfMergeRequests < Spinach::FeatureSteps
project.save!
end
+ step 'I should see rebase button' do
+ expect(page).to have_button "Rebase"
+ end
+
step 'merge request "Bug NS-05" is rebased' do
merge_request.source_branch = 'flatten-dir'
merge_request.target_branch = 'improve/awesome'
@@ -59,6 +67,20 @@ class Spinach::Features::ProjectFfMergeRequests < Spinach::FeatureSteps
merge_request.save!
end
+ step 'rebase before merge enabled' do
+ project = merge_request.target_project
+ project.merge_requests_rebase_enabled = true
+ project.save!
+ end
+
+ step 'I press rebase button' do
+ click_button "Rebase"
+ end
+
+ step "I should see rebase in progress message" do
+ expect(page).to have_content("Rebase in progress")
+ end
+
def merge_request
@merge_request ||= MergeRequest.find_by!(title: "Bug NS-05")
end
diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb
index ef5bdbaf819..3fb0e2eed93 100644
--- a/lib/gitlab/git/operation_service.rb
+++ b/lib/gitlab/git/operation_service.rb
@@ -97,6 +97,11 @@ module Gitlab
end
end
+ def update_branch(branch_name, newrev, oldrev)
+ ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
+ update_ref_in_hooks(ref, newrev, oldrev)
+ end
+
private
# Returns [newrev, should_run_after_create, should_run_after_create_branch]
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 45c424af8c4..c8cc6b374f6 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -684,4 +684,62 @@ describe Projects::MergeRequestsController do
format: :json
end
end
+
+ describe 'POST #rebase' do
+ let(:viewer) { user }
+
+ def post_rebase
+ post :rebase, namespace_id: project.namespace, project_id: project, id: merge_request
+ end
+
+ def expect_rebase_worker_for(user)
+ expect(RebaseWorker).to receive(:perform_async).with(merge_request.id, user.id)
+ end
+
+ context 'successfully' do
+ it 'enqeues a RebaseWorker' do
+ expect_rebase_worker_for(viewer)
+
+ post_rebase
+
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context 'with a forked project' do
+ let(:fork_project) { create(:project, :repository, forked_from_project: project) }
+ let(:fork_owner) { fork_project.owner }
+
+ before do
+ merge_request.update!(source_project: fork_project)
+ fork_project.add_reporter(user)
+ end
+
+ context 'user cannot push to source branch' do
+ it 'returns 404' do
+ expect_rebase_worker_for(viewer).never
+
+ post_rebase
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'user can push to source branch' do
+ before do
+ project.add_reporter(fork_owner)
+
+ sign_in(fork_owner)
+ end
+
+ it 'returns 200' do
+ expect_rebase_worker_for(fork_owner)
+
+ post_rebase
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+ end
end
diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json
index 995f13381ad..f1199468d53 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_basic.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json
@@ -9,6 +9,7 @@
"human_time_estimate": { "type": ["string", "null"] },
"human_total_time_spent": { "type": ["string", "null"] },
"merge_error": { "type": ["string", "null"] },
+ "rebase_in_progress": { "type": "boolean" },
"assignee_id": { "type": ["integer", "null"] },
"subscribed": { "type": ["boolean", "null"] },
"participants": { "type": "array" }
diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index 9de27bee751..7f662098216 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -103,7 +103,11 @@
"remove_source_branch": { "type": ["boolean", "null"] },
"merge_ongoing": { "type": "boolean" },
"ff_only_enabled": { "type": ["boolean", false] },
- "should_be_rebased": { "type": "boolean" }
+ "should_be_rebased": { "type": "boolean" },
+ "rebase_commit_sha": { "type": ["string", "null"] },
+ "rebase_in_progress": { "type": "boolean" },
+ "can_push_to_source_branch": { "type": "boolean" },
+ "rebase_path": { "type": ["string", "null"] }
},
"additionalProperties": false
}
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js
new file mode 100644
index 00000000000..66ecaa316c8
--- /dev/null
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js
@@ -0,0 +1,115 @@
+import Vue from 'vue';
+import eventHub from '~/vue_merge_request_widget/event_hub';
+import component from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('Merge request widget rebase component', () => {
+ let Component;
+ let vm;
+ beforeEach(() => {
+ Component = Vue.extend(component);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('While rebasing', () => {
+ it('should show progress message', () => {
+ vm = mountComponent(Component, {
+ mr: { rebaseInProgress: true },
+ service: {},
+ });
+
+ expect(
+ vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(),
+ ).toContain('Rebase in progress');
+ });
+ });
+
+ describe('With permissions', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ },
+ service: {},
+ });
+ });
+
+ it('it should render rebase button and warning message', () => {
+ const text = vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim();
+ expect(text).toContain('Fast-forward merge is not possible.');
+ expect(text).toContain('Rebase the source branch onto the target branch or merge target');
+ expect(text).toContain('branch into source branch to allow this merge request to be merged.');
+ });
+
+ it('it should render error message when it fails', (done) => {
+ vm.rebasingError = 'Something went wrong!';
+
+ Vue.nextTick(() => {
+ expect(
+ vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(),
+ ).toContain('Something went wrong!');
+ done();
+ });
+ });
+ });
+
+ describe('Without permissions', () => {
+ it('should render a message explaining user does not have permissions', () => {
+ vm = mountComponent(Component, {
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: false,
+ targetBranch: 'foo',
+ },
+ service: {},
+ });
+
+ const text = vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim();
+
+ expect(text).toContain('Fast-forward merge is not possible.');
+ expect(text).toContain('Rebase the source branch onto');
+ expect(text).toContain('foo');
+ expect(text).toContain('to allow this merge request to be merged.');
+ });
+ });
+
+ describe('methods', () => {
+ it('checkRebaseStatus', (done) => {
+ spyOn(eventHub, '$emit');
+ vm = mountComponent(Component, {
+ mr: {},
+ service: {
+ rebase() {
+ return Promise.resolve();
+ },
+ poll() {
+ return Promise.resolve({
+ data: {
+ rebase_in_progress: false,
+ merge_error: null,
+ },
+ });
+ },
+ },
+ });
+
+ vm.rebase();
+
+ // Wait for the rebase request
+ vm.$nextTick()
+ // Wait for the polling request
+ .then(vm.$nextTick())
+ // Wait for the eventHub to be called
+ .then(vm.$nextTick())
+ .then(() => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index d8ebd46faab..07b3e1c1758 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -1903,4 +1903,50 @@ describe MergeRequest do
end
end
end
+
+ describe '#should_be_rebased?' do
+ let(:project) { create(:project, :repository) }
+
+ it 'returns false for the same source and target branches' do
+ merge_request = create(:merge_request, source_project: project, target_project: project)
+
+ expect(merge_request.should_be_rebased?).to be_falsey
+ end
+ end
+
+ describe '#rebase_in_progress?' do
+ # Create merge request and project before we stub file calls
+ before do
+ subject
+ end
+
+ it 'returns true when there is a current rebase directory' do
+ allow(File).to receive(:exist?).and_return(true)
+ allow(File).to receive(:mtime).and_return(Time.now)
+
+ expect(subject.rebase_in_progress?).to be_truthy
+ end
+
+ it 'returns false when there is no rebase directory' do
+ allow(File).to receive(:exist?).and_return(false)
+
+ expect(subject.rebase_in_progress?).to be_falsey
+ end
+
+ it 'returns false when the rebase directory has expired' do
+ allow(File).to receive(:exist?).and_return(true)
+ allow(File).to receive(:mtime).and_return(20.minutes.ago)
+
+ expect(subject.rebase_in_progress?).to be_falsey
+ end
+
+ it 'returns false when the source project has been removed' do
+ allow(subject).to receive(:source_project).and_return(nil)
+ allow(File).to receive(:exist?).and_return(true)
+ allow(File).to receive(:mtime).and_return(Time.now)
+
+ expect(File).not_to have_received(:exist?)
+ expect(subject.rebase_in_progress?).to be_falsey
+ end
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 3c2ed043b82..13e5345ee4c 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -418,14 +418,21 @@ describe Project do
end
describe '#merge_method' do
- it 'returns "ff" merge_method when ff is enabled' do
- project = build(:project, merge_requests_ff_only_enabled: true)
- expect(project.merge_method).to be :ff
+ using RSpec::Parameterized::TableSyntax
+
+ where(:ff, :rebase, :method) do
+ true | true | :ff
+ true | false | :ff
+ false | true | :rebase_merge
+ false | false | :merge
end
- it 'returns "merge" merge_method when ff is disabled' do
- project = build(:project, merge_requests_ff_only_enabled: false)
- expect(project.merge_method).to be :merge
+ with_them do
+ let(:project) { build(:project, merge_requests_rebase_enabled: rebase, merge_requests_ff_only_enabled: ff) }
+
+ subject { project.merge_method }
+
+ it { is_expected.to eq(method) }
end
end
diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb
index 969c4753f33..e3b37739e8e 100644
--- a/spec/presenters/merge_request_presenter_spec.rb
+++ b/spec/presenters/merge_request_presenter_spec.rb
@@ -404,4 +404,67 @@ describe MergeRequestPresenter do
.to eq("#{resource.source_branch}")
end
end
+
+ describe '#rebase_path' do
+ before do
+ allow(resource).to receive(:rebase_in_progress?) { rebase_in_progress }
+ allow(resource).to receive(:should_be_rebased?) { should_be_rebased }
+
+ allow_any_instance_of(Gitlab::UserAccess::RequestCacheExtension)
+ .to receive(:can_push_to_branch?)
+ .with(resource.source_branch)
+ .and_return(can_push_to_branch)
+ end
+
+ subject do
+ described_class.new(resource, current_user: user).rebase_path
+ end
+
+ context 'when can rebase' do
+ let(:rebase_in_progress) { false }
+ let(:can_push_to_branch) { true }
+ let(:should_be_rebased) { true }
+
+ before do
+ allow(resource).to receive(:source_branch_exists?) { true }
+ end
+
+ it 'returns path' do
+ is_expected
+ .to eq("/#{project.full_path}/merge_requests/#{resource.iid}/rebase")
+ end
+ end
+
+ context 'when cannot rebase' do
+ context 'when rebase in progress' do
+ let(:rebase_in_progress) { true }
+ let(:can_push_to_branch) { true }
+ let(:should_be_rebased) { true }
+
+ it 'returns nil' do
+ is_expected.to be_nil
+ end
+ end
+
+ context 'when user cannot merge' do
+ let(:rebase_in_progress) { false }
+ let(:can_push_to_branch) { false }
+ let(:should_be_rebased) { true }
+
+ it 'returns nil' do
+ is_expected.to be_nil
+ end
+ end
+
+ context 'should not be rebased' do
+ let(:rebase_in_progress) { false }
+ let(:can_push_to_branch) { true }
+ let(:should_be_rebased) { false }
+
+ it 'returns nil' do
+ is_expected.to be_nil
+ end
+ end
+ end
+ end
end
diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb
index e25552eb0d8..80a271ba7fb 100644
--- a/spec/serializers/merge_request_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_widget_entity_spec.rb
@@ -190,4 +190,20 @@ describe MergeRequestWidgetEntity do
end
end
end
+
+ describe 'when source project is deleted' do
+ let(:project) { create(:project, :repository) }
+ let(:fork_project) { create(:project, :repository, forked_from_project: project) }
+ let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) }
+
+ it 'returns a blank rebase_path' do
+ allow(merge_request).to receive(:should_be_rebased?).and_return(true)
+ fork_project.destroy
+ merge_request.reload
+
+ entity = described_class.new(merge_request, request: request).as_json
+
+ expect(entity[:rebase_path]).to be_nil
+ end
+ end
end
diff --git a/spec/services/merge_requests/rebase_service_spec.rb b/spec/services/merge_requests/rebase_service_spec.rb
new file mode 100644
index 00000000000..d1b37cdd073
--- /dev/null
+++ b/spec/services/merge_requests/rebase_service_spec.rb
@@ -0,0 +1,134 @@
+require 'spec_helper'
+
+describe MergeRequests::RebaseService do
+ include ProjectForksHelper
+
+ let(:user) { create(:user) }
+ let(:merge_request) do
+ create(:merge_request,
+ source_branch: 'feature_conflict',
+ target_branch: 'master')
+ end
+ let(:project) { merge_request.project }
+ let(:repository) { project.repository.raw }
+
+ subject(:service) { described_class.new(project, user, {}) }
+
+ before do
+ project.add_master(user)
+ end
+
+ describe '#execute' do
+ context 'when another rebase is already in progress' do
+ before do
+ allow(merge_request).to receive(:rebase_in_progress?).and_return(true)
+ end
+
+ it 'saves the error message' do
+ subject.execute(merge_request)
+
+ expect(merge_request.reload.merge_error).to eq 'Rebase task canceled: Another rebase is already in progress'
+ end
+
+ it 'returns an error' do
+ expect(service.execute(merge_request)).to match(status: :error,
+ message: 'Failed to rebase. Should be done manually')
+ end
+ end
+
+ context 'when unexpected error occurs' do
+ before do
+ allow(repository).to receive(:run_git!).and_raise('Something went wrong')
+ end
+
+ it 'saves the error message' do
+ subject.execute(merge_request)
+
+ expect(merge_request.reload.merge_error).to eq 'Something went wrong'
+ end
+
+ it 'returns an error' do
+ expect(service.execute(merge_request)).to match(status: :error,
+ message: 'Failed to rebase. Should be done manually')
+ end
+ end
+
+ context 'with git command failure' do
+ before do
+ allow(repository).to receive(:run_git!).and_raise(Gitlab::Git::Repository::GitError, 'Something went wrong')
+ end
+
+ it 'saves the error message' do
+ subject.execute(merge_request)
+
+ expect(merge_request.reload.merge_error).to eq 'Something went wrong'
+ end
+
+ it 'returns an error' do
+ expect(service.execute(merge_request)).to match(status: :error,
+ message: 'Failed to rebase. Should be done manually')
+ end
+ end
+
+ context 'valid params' do
+ before do
+ service.execute(merge_request)
+ end
+
+ it 'rebases source branch' do
+ parent_sha = merge_request.source_project.repository.commit(merge_request.source_branch).parents.first.sha
+ target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
+ expect(parent_sha).to eq(target_branch_sha)
+ end
+
+ it 'records the new SHA on the merge request' do
+ head_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
+ expect(merge_request.reload.rebase_commit_sha).to eq(head_sha)
+ end
+
+ it 'logs correct author and commiter' do
+ head_commit = merge_request.source_project.repository.commit(merge_request.source_branch)
+
+ expect(head_commit.author_email).to eq('dmitriy.zaporozhets@gmail.com')
+ expect(head_commit.author_name).to eq('Dmitriy Zaporozhets')
+ expect(head_commit.committer_email).to eq(user.email)
+ expect(head_commit.committer_name).to eq(user.name)
+ end
+
+ context 'git commands' do
+ it 'sets GL_REPOSITORY env variable when calling git commands' do
+ expect(repository).to receive(:popen).exactly(3)
+ .with(anything, anything, hash_including('GL_REPOSITORY'))
+ .and_return(['', 0])
+
+ service.execute(merge_request)
+ end
+ end
+
+ context 'fork' do
+ let(:forked_project) do
+ fork_project(project, user, repository: true)
+ end
+
+ let(:merge_request_from_fork) do
+ forked_project.repository.create_file(
+ user,
+ 'new-file-to-target',
+ '',
+ message: 'Add new file to target',
+ branch_name: 'master')
+
+ create(:merge_request,
+ source_branch: 'master', source_project: forked_project,
+ target_branch: 'master', target_project: project)
+ end
+
+ it 'rebases source branch' do
+ parent_sha = forked_project.repository.commit(merge_request_from_fork.source_branch).parents.first.sha
+ target_branch_sha = project.repository.commit(merge_request_from_fork.target_branch).sha
+ expect(parent_sha).to eq(target_branch_sha)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/views/projects/merge_requests/show.html.haml_spec.rb b/spec/views/projects/merge_requests/show.html.haml_spec.rb
index 28d54c2fb77..264e0ce0b40 100644
--- a/spec/views/projects/merge_requests/show.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/show.html.haml_spec.rb
@@ -54,6 +54,8 @@ describe 'projects/merge_requests/show.html.haml' do
it 'closes the merge request if the source project does not exist' do
closed_merge_request.update_attributes(state: 'open')
forked_project.destroy
+ # Reload merge request so MergeRequest#source_project turns to `nil`
+ closed_merge_request.reload
render
diff --git a/spec/workers/rebase_worker_spec.rb b/spec/workers/rebase_worker_spec.rb
new file mode 100644
index 00000000000..20aff020dbb
--- /dev/null
+++ b/spec/workers/rebase_worker_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe RebaseWorker, '#perform' do
+ context 'when rebasing an MR from a fork where upstream has protected branches' do
+ let(:upstream_project) { create(:project, :repository) }
+ let(:fork_project) { create(:project, :repository) }
+
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: fork_project,
+ source_branch: 'feature_conflict',
+ target_project: upstream_project,
+ target_branch: 'master')
+ end
+
+ before do
+ create(:forked_project_link, forked_to_project: fork_project, forked_from_project: upstream_project)
+ end
+
+ it 'sets the correct project for running hooks' do
+ expect(MergeRequests::RebaseService)
+ .to receive(:new).with(fork_project, merge_request.author).and_call_original
+
+ subject.perform(merge_request, merge_request.author)
+ end
+ end
+end
--
cgit v1.2.1
From 304851dc90c06d770042bf3cb0af887b6f3497e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jarka=20Kadlecova=CC=81?=
Date: Thu, 4 Jan 2018 13:29:48 +0100
Subject: Refactor RelativePositioning so that it can be used by other classes
---
app/models/concerns/relative_positioning.rb | 18 +++++++++++-------
app/models/issue.rb | 6 ++++++
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb
index 835f26aa57b..afacdb8cb12 100644
--- a/app/models/concerns/relative_positioning.rb
+++ b/app/models/concerns/relative_positioning.rb
@@ -10,12 +10,12 @@ module RelativePositioning
after_save :save_positionable_neighbours
end
- def project_ids
- [project.id]
+ def min_relative_position
+ self.class.in_parents(parent_ids).minimum(:relative_position)
end
def max_relative_position
- self.class.in_projects(project_ids).maximum(:relative_position)
+ self.class.in_parents(parent_ids).maximum(:relative_position)
end
def prev_relative_position
@@ -23,7 +23,7 @@ module RelativePositioning
if self.relative_position
prev_pos = self.class
- .in_projects(project_ids)
+ .in_parents(parent_ids)
.where('relative_position < ?', self.relative_position)
.maximum(:relative_position)
end
@@ -36,7 +36,7 @@ module RelativePositioning
if self.relative_position
next_pos = self.class
- .in_projects(project_ids)
+ .in_parents(parent_ids)
.where('relative_position > ?', self.relative_position)
.minimum(:relative_position)
end
@@ -63,7 +63,7 @@ module RelativePositioning
pos_after = before.next_relative_position
if before.shift_after?
- issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_after)
+ issue_to_move = self.class.in_parents(parent_ids).find_by!(relative_position: pos_after)
issue_to_move.move_after
@positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables
@@ -78,7 +78,7 @@ module RelativePositioning
pos_before = after.prev_relative_position
if after.shift_before?
- issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_before)
+ issue_to_move = self.class.in_parents(parent_ids).find_by!(relative_position: pos_before)
issue_to_move.move_before
@positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables
@@ -92,6 +92,10 @@ module RelativePositioning
self.relative_position = position_between(max_relative_position || START_POSITION, MAX_POSITION)
end
+ def move_to_start
+ self.relative_position = position_between(min_relative_position || START_POSITION, MIN_POSITION)
+ end
+
# Indicates if there is an issue that should be shifted to free the place
def shift_after?
next_pos = next_relative_position
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 4eafc1316d6..f2d111ba926 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -35,6 +35,8 @@ class Issue < ActiveRecord::Base
validates :project, presence: true
+ alias_attribute :parent_id, :project_id
+
scope :in_projects, ->(project_ids) { where(project_id: project_ids) }
scope :assigned, -> { where('EXISTS (SELECT TRUE FROM issue_assignees WHERE issue_id = issues.id)') }
@@ -78,6 +80,10 @@ class Issue < ActiveRecord::Base
acts_as_paranoid
+ class << self
+ alias_method :in_parents, :in_projects
+ end
+
def self.reference_prefix
'#'
end
--
cgit v1.2.1
From 6b15784ce7d893ed509c00d9f51a4702787799ed Mon Sep 17 00:00:00 2001
From: Zeger-Jan van de Weg
Date: Fri, 5 Jan 2018 09:41:05 +0000
Subject: Fix typos in a code comment
---
lib/gitlab/git/blob.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index bd91125d3b6..a1755143abe 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -138,8 +138,8 @@ module Gitlab
# Gitaly will think that setting the limit to 0 means unlimited, while
# the client might only need the metadata and thus set the limit to 0.
- # In this method we'll than set the limit to 1, but clear the byte of data
- # that we got back so fot the outside world it looks like the limit was
+ # In this method we'll then set the limit to 1, but clear the byte of data
+ # that we got back so for the outside world it looks like the limit was
# actually 0.
req_limit = limit == 0 ? 1 : limit
--
cgit v1.2.1
From 3514b7248cf00bcee8a6b3133e4e157f656d30c6 Mon Sep 17 00:00:00 2001
From: Alessio Caiazza
Date: Tue, 13 Jun 2017 22:03:34 +0200
Subject: Add status attribute to runner api entity
---
.../unreleased/feature-api_runners_online.yml | 5 +++--
doc/api/runners.md | 23 ++++++++++++++++------
lib/api/entities.rb | 1 +
3 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/changelogs/unreleased/feature-api_runners_online.yml b/changelogs/unreleased/feature-api_runners_online.yml
index f5077507e5b..08f4dd16f28 100644
--- a/changelogs/unreleased/feature-api_runners_online.yml
+++ b/changelogs/unreleased/feature-api_runners_online.yml
@@ -1,4 +1,5 @@
---
-title: Add online attribute to runner api entity
+title: Add online and status attribute to runner api entity
merge_request: 11750
-author: Alessio Caiazza
+author:
+type: added
diff --git a/doc/api/runners.md b/doc/api/runners.md
index 50981ed96bc..7495c6cdedb 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -31,7 +31,8 @@ Example response:
"id": 6,
"is_shared": false,
"name": null,
- "online": true
+ "online": true,
+ "status": "online"
},
{
"active": true,
@@ -39,7 +40,8 @@ Example response:
"id": 8,
"is_shared": false,
"name": null,
- "online": false
+ "online": false,
+ "status": "offline"
}
]
```
@@ -72,7 +74,8 @@ Example response:
"id": 1,
"is_shared": true,
"name": null,
- "online": true
+ "online": true,
+ "status": "online"
},
{
"active": true,
@@ -81,6 +84,7 @@ Example response:
"is_shared": true,
"name": null,
"online": false
+ "status": "offline"
},
{
"active": true,
@@ -89,6 +93,7 @@ Example response:
"is_shared": false,
"name": null,
"online": true
+ "status": "paused"
},
{
"active": true,
@@ -96,7 +101,8 @@ Example response:
"id": 8,
"is_shared": false,
"name": null,
- "online": false
+ "online": false,
+ "status": "offline"
}
]
```
@@ -129,6 +135,7 @@ Example response:
"contacted_at": "2016-01-25T16:39:48.066Z",
"name": null,
"online": true,
+ "status": "online",
"platform": null,
"projects": [
{
@@ -184,6 +191,7 @@ Example response:
"contacted_at": "2016-01-25T16:39:48.066Z",
"name": null,
"online": true,
+ "status": "online",
"platform": null,
"projects": [
{
@@ -336,7 +344,8 @@ Example response:
"id": 8,
"is_shared": false,
"name": null,
- "online": false
+ "online": false,
+ "status": "offline"
},
{
"active": true,
@@ -345,6 +354,7 @@ Example response:
"is_shared": true,
"name": null,
"online": true
+ "status": "paused"
}
]
```
@@ -375,7 +385,8 @@ Example response:
"id": 9,
"is_shared": false,
"name": null,
- "online": true
+ "online": true,
+ "status": "online"
}
```
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index c612dde7f73..f5fa5fef389 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -863,6 +863,7 @@ module API
expose :is_shared
expose :name
expose :online?, as: :online
+ expose :status
end
class RunnerDetails < Runner
--
cgit v1.2.1
From 13926246020fb41599e1a7b908912bb2e61f114f Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Fri, 5 Jan 2018 11:16:18 +0100
Subject: add deprecation and removal issue to docs
---
doc/administration/raketasks/check.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index 7dabc014bad..831b73237b6 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -28,6 +28,12 @@ exactly which repositories are causing the trouble.
### Check all GitLab repositories
+>**Note:**
+>
+> - `gitlab:repo:check` has been deprecated in favour of `gitlab:git:fsck`
+> - [Deprecated][ce-15931] in GitLab 10.4.
+> - `gitlab:repo:check` will be removed in the future. [Removal issue][ce-41699]
+
This task loops through all repositories on the GitLab server and runs the
3 integrity checks described previously.
@@ -76,3 +82,6 @@ The LDAP check Rake task will test the bind_dn and password credentials
(if configured) and will list a sample of LDAP users. This task is also
executed as part of the `gitlab:check` task, but can run independently.
See [LDAP Rake Tasks - LDAP Check](ldap.md#check) for details.
+
+[ce-15931]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15931
+[ce-41699]: https://gitlab.com/gitlab-org/gitlab-ce/issues/41699
--
cgit v1.2.1
From 0feb2437e1318fa1b3157bf322d6759bb32bc01a Mon Sep 17 00:00:00 2001
From: James Lopez
Date: Fri, 5 Jan 2018 10:30:57 +0000
Subject: Update check.md
---
doc/administration/raketasks/check.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index 831b73237b6..c39cb49b1c6 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -30,7 +30,7 @@ exactly which repositories are causing the trouble.
>**Note:**
>
-> - `gitlab:repo:check` has been deprecated in favour of `gitlab:git:fsck`
+> - `gitlab:repo:check` has been deprecated in favor of `gitlab:git:fsck`
> - [Deprecated][ce-15931] in GitLab 10.4.
> - `gitlab:repo:check` will be removed in the future. [Removal issue][ce-41699]
--
cgit v1.2.1
From 7c91863b43dbb4027e9b888d5064a3c1d3dabcf4 Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Fri, 5 Jan 2018 10:56:09 +0000
Subject: Use computed prop in expand button
---
app/assets/javascripts/vue_shared/components/expand_button.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/assets/javascripts/vue_shared/components/expand_button.vue b/app/assets/javascripts/vue_shared/components/expand_button.vue
index 96991c4e268..05e48ed297f 100644
--- a/app/assets/javascripts/vue_shared/components/expand_button.vue
+++ b/app/assets/javascripts/vue_shared/components/expand_button.vue
@@ -35,7 +35,7 @@
type="button"
v-show="isCollapsed"
class="text-expander btn-blank"
- aria-label="Click to Expand Text"
+ :aria-label="ariaLabel"
@click="onClick">
...
--
cgit v1.2.1
From 5d1391b6818b61e3b7ba4742d6487382484f9643 Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Fri, 5 Jan 2018 12:29:01 +0100
Subject: Fix specs
---
spec/models/namespace_spec.rb | 10 +++++++---
spec/models/project_spec.rb | 8 ++++----
spec/services/projects/create_service_spec.rb | 2 +-
.../projects/hashed_storage/migrate_repository_service_spec.rb | 2 +-
spec/services/projects/transfer_service_spec.rb | 4 ++--
5 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 0678cae9b93..b3f160f3119 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -250,9 +250,13 @@ describe Namespace do
parent.update(path: 'mygroup_new')
- expect(project_in_parent_group.repo.config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}"
- expect(hashed_project_in_subgroup.repo.config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}"
- expect(legacy_project_in_subgroup.repo.config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}"
+ expect(project_rugged(project_in_parent_group).config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}"
+ expect(project_rugged(hashed_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}"
+ expect(project_rugged(legacy_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}"
+ end
+
+ def project_rugged(project)
+ project.repository.rugged
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index cea22bbd184..8111365bed1 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2632,7 +2632,7 @@ describe Project do
project.rename_repo
- expect(project.repo.config['gitlab.fullpath']).to eq(project.full_path)
+ expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path)
end
end
@@ -2793,7 +2793,7 @@ describe Project do
it 'updates project full path in .git/config' do
project.rename_repo
- expect(project.repo.config['gitlab.fullpath']).to eq(project.full_path)
+ expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path)
end
end
@@ -3162,13 +3162,13 @@ describe Project do
it 'writes full path in .git/config when key is missing' do
project.write_repository_config
- expect(project.repo.config['gitlab.fullpath']).to eq project.full_path
+ expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
end
it 'updates full path in .git/config when key is present' do
project.write_repository_config(gl_full_path: 'old/path')
- expect { project.write_repository_config }.to change { project.repo.config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
+ expect { project.write_repository_config }.to change { project.repository.rugged.config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
end
it 'does not raise an error with an empty repository' do
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 1833078f37c..9a44dfde41b 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -255,7 +255,7 @@ describe Projects::CreateService, '#execute' do
it 'writes project full path to .git/config' do
project = create_project(user, opts)
- expect(project.repo.config['gitlab.fullpath']).to eq project.full_path
+ expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
end
def create_project(user, opts)
diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
index ded864beb1d..7b536cc05cb 100644
--- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
@@ -37,7 +37,7 @@ describe Projects::HashedStorage::MigrateRepositoryService do
it 'writes project full path to .git/config' do
service.execute
- expect(project.repo.config['gitlab.fullpath']).to eq project.full_path
+ expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
end
end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 7377c748698..39f6388c25e 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -58,7 +58,7 @@ describe Projects::TransferService do
it 'updates project full path in .git/config' do
transfer_project(project, user, group)
- expect(project.repo.config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}"
+ expect(project.repository.rugged.config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}"
end
end
@@ -95,7 +95,7 @@ describe Projects::TransferService do
it 'rolls back project full path in .git/config' do
attempt_project_transfer
- expect(project.repo.config['gitlab.fullpath']).to eq project.full_path
+ expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
end
it "doesn't send move notifications" do
--
cgit v1.2.1
From c5e2c0665fe7e4937689cfedaa064aa64f538c8b Mon Sep 17 00:00:00 2001
From: "Jacob Vosmaer (GitLab)"
Date: Fri, 5 Jan 2018 11:31:12 +0000
Subject: Allow local tests to use a modified Gitaly
---
doc/development/gitaly.md | 23 +++++++++++++++++
lib/gitlab/setup_helper.rb | 61 ++++++++++++++++++++++++++++++++++++++++++++
lib/tasks/gitlab/gitaly.rake | 57 ++---------------------------------------
spec/support/test_env.rb | 7 +++++
4 files changed, 93 insertions(+), 55 deletions(-)
create mode 100644 lib/gitlab/setup_helper.rb
diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md
index ca2048c7019..26abf967dcf 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -97,6 +97,29 @@ describe 'Gitaly Request count tests' do
end
```
+## Running tests with a locally modified version of Gitaly
+
+Normally, gitlab-ce/ee tests use a local clone of Gitaly in `tmp/tests/gitaly`
+pinned at the version specified in GITALY_SERVER_VERSION. If you want
+to run tests locally against a modified version of Gitaly you can
+replace `tmp/tests/gitaly` with a symlink.
+
+```shell
+rm -rf tmp/tests/gitaly
+ln -s /path/to/gitaly tmp/tests/gitaly
+```
+
+Make sure you run `make` in your local Gitaly directory before running
+tests. Otherwise, Gitaly will fail to boot.
+
+If you make changes to your local Gitaly in between test runs you need
+to manually run `make` again.
+
+Note that CI tests will not use your locally modified version of
+Gitaly. To use a custom Gitaly version in CI you need to update
+GITALY_SERVER_VERSION. You can use the format `=revision` to use a
+non-tagged commit from https://gitlab.com/gitlab-org/gitaly in CI.
+
---
[Return to Development documentation](README.md)
diff --git a/lib/gitlab/setup_helper.rb b/lib/gitlab/setup_helper.rb
new file mode 100644
index 00000000000..d01213bb6e0
--- /dev/null
+++ b/lib/gitlab/setup_helper.rb
@@ -0,0 +1,61 @@
+module Gitlab
+ module SetupHelper
+ class << self
+ # We cannot create config.toml files for all possible Gitaly configuations.
+ # For instance, if Gitaly is running on another machine then it makes no
+ # sense to write a config.toml file on the current machine. This method will
+ # only generate a configuration for the most common and simplest case: when
+ # we have exactly one Gitaly process and we are sure it is running locally
+ # because it uses a Unix socket.
+ # For development and testing purposes, an extra storage is added to gitaly,
+ # which is not known to Rails, but must be explicitly stubbed.
+ def gitaly_configuration_toml(gitaly_dir, gitaly_ruby: true)
+ storages = []
+ address = nil
+
+ Gitlab.config.repositories.storages.each do |key, val|
+ if address
+ if address != val['gitaly_address']
+ raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address."
+ end
+ elsif URI(val['gitaly_address']).scheme != 'unix'
+ raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses."
+ else
+ address = val['gitaly_address']
+ end
+
+ storages << { name: key, path: val['path'] }
+ end
+
+ if Rails.env.test?
+ storages << { name: 'test_second_storage', path: Rails.root.join('tmp', 'tests', 'second_storage').to_s }
+ end
+
+ config = { socket_path: address.sub(%r{\Aunix:}, ''), storage: storages }
+ config[:auth] = { token: 'secret' } if Rails.env.test?
+ config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby
+ config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }
+ config[:bin_dir] = Gitlab.config.gitaly.client_path
+
+ TOML.dump(config)
+ end
+
+ # rubocop:disable Rails/Output
+ def create_gitaly_configuration(dir, force: false)
+ config_path = File.join(dir, 'config.toml')
+ FileUtils.rm_f(config_path) if force
+
+ File.open(config_path, File::WRONLY | File::CREAT | File::EXCL) do |f|
+ f.puts gitaly_configuration_toml(dir)
+ end
+ rescue Errno::EEXIST
+ puts "Skipping config.toml generation:"
+ puts "A configuration file already exists."
+ rescue ArgumentError => e
+ puts "Skipping config.toml generation:"
+ puts e.message
+ end
+ # rubocop:enable Rails/Output
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake
index 4d880c05f99..4507b841964 100644
--- a/lib/tasks/gitlab/gitaly.rake
+++ b/lib/tasks/gitlab/gitaly.rake
@@ -21,8 +21,8 @@ namespace :gitlab do
command << 'BUNDLE_FLAGS=--no-deployment' if Rails.env.test?
+ Gitlab::SetupHelper.create_gitaly_configuration(args.dir)
Dir.chdir(args.dir) do
- create_gitaly_configuration
# In CI we run scripts/gitaly-test-build instead of this command
unless ENV['CI'].present?
Bundler.with_original_env { run_command!(command) }
@@ -39,60 +39,7 @@ namespace :gitlab do
# Exclude gitaly-ruby configuration because that depends on the gitaly
# installation directory.
- puts gitaly_configuration_toml(gitaly_ruby: false)
- end
-
- private
-
- # We cannot create config.toml files for all possible Gitaly configuations.
- # For instance, if Gitaly is running on another machine then it makes no
- # sense to write a config.toml file on the current machine. This method will
- # only generate a configuration for the most common and simplest case: when
- # we have exactly one Gitaly process and we are sure it is running locally
- # because it uses a Unix socket.
- # For development and testing purposes, an extra storage is added to gitaly,
- # which is not known to Rails, but must be explicitly stubbed.
- def gitaly_configuration_toml(gitaly_ruby: true)
- storages = []
- address = nil
-
- Gitlab.config.repositories.storages.each do |key, val|
- if address
- if address != val['gitaly_address']
- raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address."
- end
- elsif URI(val['gitaly_address']).scheme != 'unix'
- raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses."
- else
- address = val['gitaly_address']
- end
-
- storages << { name: key, path: val['path'] }
- end
-
- if Rails.env.test?
- storages << { name: 'test_second_storage', path: Rails.root.join('tmp', 'tests', 'second_storage').to_s }
- end
-
- config = { socket_path: address.sub(%r{\Aunix:}, ''), storage: storages }
- config[:auth] = { token: 'secret' } if Rails.env.test?
- config[:'gitaly-ruby'] = { dir: File.join(Dir.pwd, 'ruby') } if gitaly_ruby
- config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }
- config[:bin_dir] = Gitlab.config.gitaly.client_path
-
- TOML.dump(config)
- end
-
- def create_gitaly_configuration
- File.open("config.toml", File::WRONLY | File::CREAT | File::EXCL) do |f|
- f.puts gitaly_configuration_toml
- end
- rescue Errno::EEXIST
- puts "Skipping config.toml generation:"
- puts "A configuration file already exists."
- rescue ArgumentError => e
- puts "Skipping config.toml generation:"
- puts e.message
+ puts Gitlab::SetupHelper.gitaly_configuration_toml('', gitaly_ruby: false)
end
end
end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 1d99746b09f..664698fcbaf 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -1,4 +1,5 @@
require 'rspec/mocks'
+require 'toml'
module TestEnv
extend self
@@ -147,6 +148,9 @@ module TestEnv
version: Gitlab::GitalyClient.expected_server_version,
task: "gitlab:gitaly:install[#{gitaly_dir}]") do
+ # Always re-create config, in case it's outdated. This is fast anyway.
+ Gitlab::SetupHelper.create_gitaly_configuration(gitaly_dir, force: true)
+
start_gitaly(gitaly_dir)
end
end
@@ -347,6 +351,9 @@ module TestEnv
end
def component_needs_update?(component_folder, expected_version)
+ # Allow local overrides of the component for tests during development
+ return false if Rails.env.test? && File.symlink?(component_folder)
+
version = File.read(File.join(component_folder, 'VERSION')).strip
# Notice that this will always yield true when using branch versions
--
cgit v1.2.1
From 2c47f0924fc5534035905746046ab0f5e9c99f23 Mon Sep 17 00:00:00 2001
From: Winnie Hellmann
Date: Wed, 3 Jan 2018 10:21:17 +0100
Subject: Add id to modal.vue to support data-toggle="modal"
---
.../javascripts/groups/components/item_actions.vue | 6 +-
.../ide/components/new_dropdown/index.vue | 8 +-
.../ide/components/new_dropdown/modal.vue | 8 +-
.../ide/components/repo_commit_section.vue | 2 +-
.../ide/components/repo_edit_button.vue | 2 +-
.../account/components/delete_account_modal.vue | 111 +++++++++------------
app/assets/javascripts/profile/account/index.js | 8 ++
.../javascripts/vue_shared/components/modal.vue | 30 ++++--
.../vue_shared/components/recaptcha_modal.vue | 2 +-
app/views/profiles/accounts/show.html.haml | 6 +-
changelogs/unreleased/winh-modal-target-id.yml | 5 +
.../groups/components/item_actions_spec.js | 12 +--
.../components/delete_account_modal_spec.js | 8 +-
.../repo/components/new_dropdown/index_spec.js | 13 +--
.../vue_shared/components/modal_spec.js | 62 +++++++++++-
15 files changed, 168 insertions(+), 115 deletions(-)
create mode 100644 changelogs/unreleased/winh-modal-target-id.yml
diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue
index 58ba5aff7cf..b98cfcf7563 100644
--- a/app/assets/javascripts/groups/components/item_actions.vue
+++ b/app/assets/javascripts/groups/components/item_actions.vue
@@ -45,11 +45,9 @@ export default {
onLeaveGroup() {
this.modalStatus = true;
},
- leaveGroup(leaveConfirmed) {
+ leaveGroup() {
this.modalStatus = false;
- if (leaveConfirmed) {
- eventHub.$emit('leaveGroup', this.group, this.parentGroup);
- }
+ eventHub.$emit('leaveGroup', this.group, this.parentGroup);
},
},
};
diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue
index 6e67e99a70f..d475813c4f7 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/index.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue
@@ -32,10 +32,10 @@
methods: {
createNewItem(type) {
this.modalType = type;
- this.toggleModalOpen();
+ this.openModal = true;
},
- toggleModalOpen() {
- this.openModal = !this.openModal;
+ hideModal() {
+ this.openModal = false;
},
},
};
@@ -95,7 +95,7 @@
:branch-id="branch"
:path="path"
:parent="parent"
- @toggle="toggleModalOpen"
+ @hide="hideModal"
/>
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index f1313b79589..79e197ad08b 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -84,11 +84,13 @@
= s_('Profiles|Deleting an account has the following effects:')
= render 'users/deletion_guidance', user: current_user
+ %button#delete-account-button.btn.btn-danger.disabled{ data: { toggle: 'modal',
+ target: '#delete-account-modal' } }
+ = s_('Profiles|Delete account')
+
#delete-account-modal{ data: { action_url: user_registration_path,
confirm_with_password: ('true' if current_user.confirm_deletion_with_password?),
username: current_user.username } }
- %button.btn.btn-danger.disabled
- = s_('Profiles|Delete account')
- else
- if @user.solo_owned_groups.present?
%p
diff --git a/changelogs/unreleased/winh-modal-target-id.yml b/changelogs/unreleased/winh-modal-target-id.yml
new file mode 100644
index 00000000000..f8d5b72be50
--- /dev/null
+++ b/changelogs/unreleased/winh-modal-target-id.yml
@@ -0,0 +1,5 @@
+---
+title: Add id to modal.vue to support data-toggle="modal"
+merge_request: 16189
+author:
+type: other
diff --git a/spec/javascripts/groups/components/item_actions_spec.js b/spec/javascripts/groups/components/item_actions_spec.js
index 7a5c1da4d1d..6d6fb410859 100644
--- a/spec/javascripts/groups/components/item_actions_spec.js
+++ b/spec/javascripts/groups/components/item_actions_spec.js
@@ -47,17 +47,11 @@ describe('ItemActionsComponent', () => {
it('should change `modalStatus` prop to `false` and emit `leaveGroup` event with required params when called with `leaveConfirmed` as `true`', () => {
spyOn(eventHub, '$emit');
vm.modalStatus = true;
- vm.leaveGroup(true);
- expect(vm.modalStatus).toBeFalsy();
- expect(eventHub.$emit).toHaveBeenCalledWith('leaveGroup', vm.group, vm.parentGroup);
- });
- it('should change `modalStatus` prop to `false` and should NOT emit `leaveGroup` event when called with `leaveConfirmed` as `false`', () => {
- spyOn(eventHub, '$emit');
- vm.modalStatus = true;
- vm.leaveGroup(false);
+ vm.leaveGroup();
+
expect(vm.modalStatus).toBeFalsy();
- expect(eventHub.$emit).not.toHaveBeenCalled();
+ expect(eventHub.$emit).toHaveBeenCalledWith('leaveGroup', vm.group, vm.parentGroup);
});
});
});
diff --git a/spec/javascripts/profile/account/components/delete_account_modal_spec.js b/spec/javascripts/profile/account/components/delete_account_modal_spec.js
index 2e94948cfb2..588b61196a5 100644
--- a/spec/javascripts/profile/account/components/delete_account_modal_spec.js
+++ b/spec/javascripts/profile/account/components/delete_account_modal_spec.js
@@ -51,7 +51,7 @@ describe('DeleteAccountModal component', () => {
Vue.nextTick()
.then(() => {
expect(vm.enteredPassword).toBe(input.value);
- expect(submitButton).toHaveClass('disabled');
+ expect(submitButton).toHaveAttr('disabled', 'disabled');
submitButton.click();
expect(form.submit).not.toHaveBeenCalled();
})
@@ -68,7 +68,7 @@ describe('DeleteAccountModal component', () => {
Vue.nextTick()
.then(() => {
expect(vm.enteredPassword).toBe(input.value);
- expect(submitButton).not.toHaveClass('disabled');
+ expect(submitButton).not.toHaveAttr('disabled', 'disabled');
submitButton.click();
expect(form.submit).toHaveBeenCalled();
})
@@ -101,7 +101,7 @@ describe('DeleteAccountModal component', () => {
Vue.nextTick()
.then(() => {
expect(vm.enteredUsername).toBe(input.value);
- expect(submitButton).toHaveClass('disabled');
+ expect(submitButton).toHaveAttr('disabled', 'disabled');
submitButton.click();
expect(form.submit).not.toHaveBeenCalled();
})
@@ -118,7 +118,7 @@ describe('DeleteAccountModal component', () => {
Vue.nextTick()
.then(() => {
expect(vm.enteredUsername).toBe(input.value);
- expect(submitButton).not.toHaveClass('disabled');
+ expect(submitButton).not.toHaveAttr('disabled', 'disabled');
submitButton.click();
expect(form.submit).toHaveBeenCalled();
})
diff --git a/spec/javascripts/repo/components/new_dropdown/index_spec.js b/spec/javascripts/repo/components/new_dropdown/index_spec.js
index b001c1655b4..6efbbf6d75e 100644
--- a/spec/javascripts/repo/components/new_dropdown/index_spec.js
+++ b/spec/javascripts/repo/components/new_dropdown/index_spec.js
@@ -57,15 +57,16 @@ describe('new dropdown component', () => {
});
});
- describe('toggleModalOpen', () => {
+ describe('hideModal', () => {
+ beforeAll((done) => {
+ vm.openModal = true;
+ Vue.nextTick(done);
+ });
+
it('closes modal after toggling', (done) => {
- vm.toggleModalOpen();
+ vm.hideModal();
Vue.nextTick()
- .then(() => {
- expect(vm.$el.querySelector('.modal')).not.toBeNull();
- })
- .then(vm.toggleModalOpen)
.then(() => {
expect(vm.$el.querySelector('.modal')).toBeNull();
})
diff --git a/spec/javascripts/vue_shared/components/modal_spec.js b/spec/javascripts/vue_shared/components/modal_spec.js
index 721f4044659..fe75a86cac8 100644
--- a/spec/javascripts/vue_shared/components/modal_spec.js
+++ b/spec/javascripts/vue_shared/components/modal_spec.js
@@ -2,11 +2,65 @@ import Vue from 'vue';
import modal from '~/vue_shared/components/modal.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
+const modalComponent = Vue.extend(modal);
+
describe('Modal', () => {
- it('does not render a primary button if no primaryButtonLabel', () => {
- const modalComponent = Vue.extend(modal);
- const vm = mountComponent(modalComponent);
+ let vm;
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('props', () => {
+ describe('without primaryButtonLabel', () => {
+ beforeEach(() => {
+ vm = mountComponent(modalComponent, {
+ primaryButtonLabel: null,
+ });
+ });
+
+ it('does not render a primary button', () => {
+ expect(vm.$el.querySelector('.js-primary-button')).toBeNull();
+ });
+ });
+
+ describe('with id', () => {
+ it('does not render a primary button', () => {
+ beforeEach(() => {
+ vm = mountComponent(modalComponent, {
+ id: 'my-modal',
+ });
+ });
+
+ it('assigns the id to the modal', () => {
+ expect(vm.$el.querySelector('#my-modal.modal')).not.toBeNull();
+ });
+
+ it('does not show the modal immediately', () => {
+ expect(vm.$el.querySelector('#my-modal.modal')).not.toHaveClass('show');
+ });
+
+ it('does not show a backdrop', () => {
+ expect(vm.$el.querySelector('modal-backdrop')).toBeNull();
+ });
+ });
+ });
+
+ it('works with data-toggle="modal"', (done) => {
+ setFixtures(`
+
+
+ `);
+
+ const modalContainer = document.getElementById('modal-container');
+ const modalButton = document.getElementById('modal-button');
+ vm = mountComponent(modalComponent, {
+ id: 'my-modal',
+ }, modalContainer);
+ const modalElement = vm.$el.querySelector('#my-modal');
+ $(modalElement).on('shown.bs.modal', () => done());
- expect(vm.$el.querySelector('.js-primary-button')).toBeNull();
+ modalButton.click();
+ });
});
});
--
cgit v1.2.1
From 153ea1830153b7d7c3be5ac2e7ca60486c9b2700 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jarka=20Kadlecova=CC=81?=
Date: Fri, 5 Jan 2018 10:15:03 +0100
Subject: Refactor matchers for background migrations
---
app/models/issue.rb | 2 +-
.../prepare_untracked_uploads_spec.rb | 13 +------------
.../migrate_stage_id_reference_in_background_spec.rb | 6 +++---
spec/migrations/migrate_stages_statuses_spec.rb | 6 +++---
.../schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb | 12 ------------
.../schedule_merge_request_diff_migrations_spec.rb | 6 +++---
...chedule_merge_request_diff_migrations_take_two_spec.rb | 6 +++---
...equest_latest_merge_request_diff_id_migrations_spec.rb | 6 +++---
...opulate_merge_request_metrics_with_events_data_spec.rb | 4 ++--
spec/migrations/track_untracked_uploads_spec.rb | 12 ------------
spec/support/background_migrations_matchers.rb | 15 ++++++++++++++-
11 files changed, 33 insertions(+), 55 deletions(-)
diff --git a/app/models/issue.rb b/app/models/issue.rb
index f2d111ba926..ad4a3c737ff 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -35,7 +35,7 @@ class Issue < ActiveRecord::Base
validates :project, presence: true
- alias_attribute :parent_id, :project_id
+ alias_attribute :parent_ids, :project_id
scope :in_projects, ->(project_ids) { where(project_id: project_ids) }
diff --git a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
index cd3f1a45270..8bb9ebe0419 100644
--- a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
+++ b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
@@ -2,21 +2,10 @@ require 'spec_helper'
describe Gitlab::BackgroundMigration::PrepareUntrackedUploads, :sidekiq do
include TrackUntrackedUploadsHelpers
+ include MigrationsHelpers
let!(:untracked_files_for_uploads) { described_class::UntrackedFile }
- matcher :be_scheduled_migration do |*expected|
- match do |migration|
- BackgroundMigrationWorker.jobs.any? do |job|
- job['args'] == [migration, expected]
- end
- end
-
- failure_message do |migration|
- "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!"
- end
- end
-
before do
DatabaseCleaner.clean
diff --git a/spec/migrations/migrate_stage_id_reference_in_background_spec.rb b/spec/migrations/migrate_stage_id_reference_in_background_spec.rb
index 9b92f4b70b0..a837498e1b1 100644
--- a/spec/migrations/migrate_stage_id_reference_in_background_spec.rb
+++ b/spec/migrations/migrate_stage_id_reference_in_background_spec.rb
@@ -35,9 +35,9 @@ describe MigrateStageIdReferenceInBackground, :migration, :sidekiq do
Timecop.freeze do
migrate!
- expect(described_class::MIGRATION).to be_scheduled_migration(2.minutes, 1, 2)
- expect(described_class::MIGRATION).to be_scheduled_migration(2.minutes, 3, 3)
- expect(described_class::MIGRATION).to be_scheduled_migration(4.minutes, 4, 5)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 1, 2)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 3, 3)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 4, 5)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
diff --git a/spec/migrations/migrate_stages_statuses_spec.rb b/spec/migrations/migrate_stages_statuses_spec.rb
index 094c9bc604e..79d2708f9ad 100644
--- a/spec/migrations/migrate_stages_statuses_spec.rb
+++ b/spec/migrations/migrate_stages_statuses_spec.rb
@@ -50,9 +50,9 @@ describe MigrateStagesStatuses, :migration do
Timecop.freeze do
migrate!
- expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes, 1, 1)
- expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes, 2, 2)
- expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes, 3, 3)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 1, 1)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 2, 2)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 3, 3)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
diff --git a/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb b/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb
index 0e884a7d910..65ec07da31c 100644
--- a/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb
+++ b/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb
@@ -2,18 +2,6 @@ require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20171005130944_schedule_create_gpg_key_subkeys_from_gpg_keys')
describe ScheduleCreateGpgKeySubkeysFromGpgKeys, :migration, :sidekiq do
- matcher :be_scheduled_migration do |*expected|
- match do |migration|
- BackgroundMigrationWorker.jobs.any? do |job|
- job['args'] == [migration, expected]
- end
- end
-
- failure_message do |migration|
- "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!"
- end
- end
-
before do
create(:gpg_key, id: 1, key: GpgHelpers::User1.public_key)
create(:gpg_key, id: 2, key: GpgHelpers::User3.public_key)
diff --git a/spec/migrations/schedule_merge_request_diff_migrations_spec.rb b/spec/migrations/schedule_merge_request_diff_migrations_spec.rb
index 76afb6c19cf..d230f064444 100644
--- a/spec/migrations/schedule_merge_request_diff_migrations_spec.rb
+++ b/spec/migrations/schedule_merge_request_diff_migrations_spec.rb
@@ -24,9 +24,9 @@ describe ScheduleMergeRequestDiffMigrations, :migration, :sidekiq do
Timecop.freeze do
migrate!
- expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes, 1, 1)
- expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes, 2, 2)
- expect(described_class::MIGRATION).to be_scheduled_migration(15.minutes, 4, 4)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 1, 1)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 2, 2)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, 4, 4)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
diff --git a/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb b/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb
index cf323973384..1aab4ae1650 100644
--- a/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb
+++ b/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb
@@ -24,9 +24,9 @@ describe ScheduleMergeRequestDiffMigrationsTakeTwo, :migration, :sidekiq do
Timecop.freeze do
migrate!
- expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes, 1, 1)
- expect(described_class::MIGRATION).to be_scheduled_migration(20.minutes, 2, 2)
- expect(described_class::MIGRATION).to be_scheduled_migration(30.minutes, 4, 4)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 1, 1)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(20.minutes, 2, 2)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(30.minutes, 4, 4)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
diff --git a/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb b/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb
index 158d0bc02ed..c9fdbe95d13 100644
--- a/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb
+++ b/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb
@@ -44,9 +44,9 @@ describe ScheduleMergeRequestLatestMergeRequestDiffIdMigrations, :migration, :si
Timecop.freeze do
migrate!
- expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes, merge_request_1.id, merge_request_1.id)
- expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes, merge_request_2.id, merge_request_2.id)
- expect(described_class::MIGRATION).to be_scheduled_migration(15.minutes, merge_request_4.id, merge_request_4.id)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, merge_request_1.id, merge_request_1.id)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, merge_request_2.id, merge_request_2.id)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, merge_request_4.id, merge_request_4.id)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
diff --git a/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb b/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb
index 97e089c5cb8..2e6b2cff0ab 100644
--- a/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb
+++ b/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb
@@ -12,10 +12,10 @@ describe SchedulePopulateMergeRequestMetricsWithEventsData, :migration, :sidekiq
migrate!
expect(described_class::MIGRATION)
- .to be_scheduled_migration(10.minutes, mrs.first.id, mrs.second.id)
+ .to be_scheduled_delayed_migration(10.minutes, mrs.first.id, mrs.second.id)
expect(described_class::MIGRATION)
- .to be_scheduled_migration(20.minutes, mrs.third.id, mrs.third.id)
+ .to be_scheduled_delayed_migration(20.minutes, mrs.third.id, mrs.third.id)
expect(BackgroundMigrationWorker.jobs.size).to eq(2)
end
diff --git a/spec/migrations/track_untracked_uploads_spec.rb b/spec/migrations/track_untracked_uploads_spec.rb
index 7fe7a140e2f..fe4d5b8a279 100644
--- a/spec/migrations/track_untracked_uploads_spec.rb
+++ b/spec/migrations/track_untracked_uploads_spec.rb
@@ -4,18 +4,6 @@ require Rails.root.join('db', 'post_migrate', '20171103140253_track_untracked_up
describe TrackUntrackedUploads, :migration, :sidekiq do
include TrackUntrackedUploadsHelpers
- matcher :be_scheduled_migration do
- match do |migration|
- BackgroundMigrationWorker.jobs.any? do |job|
- job['args'] == [migration]
- end
- end
-
- failure_message do |migration|
- "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!"
- end
- end
-
it 'correctly schedules the follow-up background migration' do
Sidekiq::Testing.fake! do
migrate!
diff --git a/spec/support/background_migrations_matchers.rb b/spec/support/background_migrations_matchers.rb
index 423c0e4cefc..f4127efc6ae 100644
--- a/spec/support/background_migrations_matchers.rb
+++ b/spec/support/background_migrations_matchers.rb
@@ -1,4 +1,4 @@
-RSpec::Matchers.define :be_scheduled_migration do |delay, *expected|
+RSpec::Matchers.define :be_scheduled_delayed_migration do |delay, *expected|
match do |migration|
BackgroundMigrationWorker.jobs.any? do |job|
job['args'] == [migration, expected] &&
@@ -11,3 +11,16 @@ RSpec::Matchers.define :be_scheduled_migration do |delay, *expected|
'not scheduled in expected time!'
end
end
+
+RSpec::Matchers.define :be_scheduled_migration do |*expected|
+ match do |migration|
+ BackgroundMigrationWorker.jobs.any? do |job|
+ args = job['args'].size == 1 ? [BackgroundMigrationWorker.jobs[0]['args'][0], []] : job['args']
+ args == [migration, expected]
+ end
+ end
+
+ failure_message do |migration|
+ "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!"
+ end
+end
--
cgit v1.2.1
From c4600805b58e4fc705a6733cd92fa5518a267e9f Mon Sep 17 00:00:00 2001
From: Yorick Peterse
Date: Fri, 5 Jan 2018 14:08:17 +0100
Subject: Update redis-rack to 2.0.4
Up until version 2.0.3 redis-rack included a "rake" binary that would
overwrite/hijack the one provided by Rake itself. Unfortunately the
binary provided by redis-rack would produce errors in many cases. See
https://github.com/redis-store/redis-rack/pull/34 for more info.
---
Gemfile.lock | 2 +-
changelogs/unreleased/update-redis-rack.yml | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/update-redis-rack.yml
diff --git a/Gemfile.lock b/Gemfile.lock
index c510a6da2d7..2a81c81b0f8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -718,7 +718,7 @@ GEM
redis-store (>= 1.3, < 2)
redis-namespace (1.5.2)
redis (~> 3.0, >= 3.0.4)
- redis-rack (2.0.3)
+ redis-rack (2.0.4)
rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2)
redis-rails (5.0.2)
diff --git a/changelogs/unreleased/update-redis-rack.yml b/changelogs/unreleased/update-redis-rack.yml
new file mode 100644
index 00000000000..6e2e6e203b8
--- /dev/null
+++ b/changelogs/unreleased/update-redis-rack.yml
@@ -0,0 +1,5 @@
+---
+title: Update redis-rack to 2.0.4
+merge_request:
+author:
+type: other
--
cgit v1.2.1
From 55980c7eca8e82e306fb3b8ade1f4a5b68a60e9f Mon Sep 17 00:00:00 2001
From: Felipe Artur
Date: Fri, 5 Jan 2018 11:24:24 -0200
Subject: Remove EE only sections from docs
---
doc/api/boards.md | 85 -------------------------------------------------------
1 file changed, 85 deletions(-)
diff --git a/doc/api/boards.md b/doc/api/boards.md
index a5f455e1c43..246de50323e 100644
--- a/doc/api/boards.md
+++ b/doc/api/boards.md
@@ -141,91 +141,6 @@ Example response:
}
```
-## Create a board (EES-Only)
-
-Creates a board.
-
-```
-POST /projects/:id/boards
-```
-
-| 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 |
-| `name` | string | yes | The name of the new board |
-
-```bash
-curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards?name=newboard
-```
-
-Example response:
-
-```json
- {
- "id": 1,
- "project": {
- "id": 5,
- "name": "Diaspora Project Site",
- "name_with_namespace": "Diaspora / Diaspora Project Site",
- "path": "diaspora-project-site",
- "path_with_namespace": "diaspora/diaspora-project-site",
- "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
- "web_url": "http://example.com/diaspora/diaspora-project-site"
- },
- "name": "newboard",
- "milestone": {
- "id": 12
- "title": "10.0"
- },
- "lists" : [
- {
- "id" : 1,
- "label" : {
- "name" : "Testing",
- "color" : "#F0AD4E",
- "description" : null
- },
- "position" : 1
- },
- {
- "id" : 2,
- "label" : {
- "name" : "Ready",
- "color" : "#FF0000",
- "description" : null
- },
- "position" : 2
- },
- {
- "id" : 3,
- "label" : {
- "name" : "Production",
- "color" : "#FF5F00",
- "description" : null
- },
- "position" : 3
- }
- ]
- }
-```
-
-## Delete a board (EES-Only)
-
-Deletes a board.
-
-```
-DELETE /projects/:id/boards/:board_id
-```
-
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `board_id` | integer | yes | The ID of a board |
-
-```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1
-```
-
## List board lists
Get a list of the board's lists.
--
cgit v1.2.1
From 05ddb259958c27506cb075342fae5a70cf8ce257 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Fri, 5 Jan 2018 14:48:50 +0100
Subject: Assign stage and pipeline to a status when importing
---
app/models/ci/build.rb | 2 +-
lib/gitlab/import_export/import_export.yml | 4 +-
lib/gitlab/import_export/relation_factory.rb | 18 +-
spec/lib/gitlab/import_export/project.json | 758 +++++++++++----------
.../import_export/project_tree_restorer_spec.rb | 12 +-
5 files changed, 426 insertions(+), 368 deletions(-)
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 83fe23606d1..fb5ae83ac7b 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -79,7 +79,7 @@ module Ci
before_save :ensure_token
before_destroy { unscoped_project }
- after_create do |build|
+ after_create unless: :importing? do |build|
run_after_commit { BuildHooksWorker.perform_async(build.id) }
end
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index f2b193c79cb..2daed10f678 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -49,8 +49,8 @@ project_tree:
- :author
- events:
- :push_event_payload
- - :stages
- - :statuses
+ - stages:
+ - :statuses
- :auto_devops
- :triggers
- :pipeline_schedules
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index d7d1b05e8b9..05dbaf6322c 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -62,6 +62,7 @@ module Gitlab
when :notes then setup_note
when :project_label, :project_labels then setup_label
when :milestone, :milestones then setup_milestone
+ when 'Ci::Pipeline' then setup_pipeline
else
@relation_hash['project_id'] = @project.id
end
@@ -112,9 +113,7 @@ module Gitlab
@relation_hash.delete('trace') # old export files have trace
@relation_hash.delete('token')
- imported_object do |object|
- object.commit_id = nil
- end
+ imported_object
elsif @relation_name == :merge_requests
MergeRequestParser.new(@project, @relation_hash.delete('diff_head_sha'), imported_object, @relation_hash).parse!
else
@@ -182,8 +181,9 @@ module Gitlab
end
def imported_object
- yield(existing_or_new_object) if block_given?
- existing_or_new_object.importing = true if existing_or_new_object.respond_to?(:importing)
+ if existing_or_new_object.respond_to?(:importing)
+ existing_or_new_object.importing = true
+ end
existing_or_new_object
rescue ActiveRecord::RecordNotUnique
@@ -211,6 +211,14 @@ module Gitlab
@relation_hash['diff'] = @relation_hash.delete('utf8_diff')
end
+ def setup_pipeline
+ @relation_hash.fetch('stages').each do |stage|
+ stage.statuses.each do |status|
+ status.pipeline = imported_object
+ end
+ end
+ end
+
def existing_or_new_object
# Only find existing records to avoid mapping tables such as milestones
# Otherwise always create the record, skipping the extra SELECT clause.
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 6778b23ee7f..7580b62cfc0 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -6473,7 +6473,83 @@
"name": "test",
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
- "updated_at": "2016-03-29T06:44:44.634Z"
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 71,
+ "project_id": 5,
+ "status": "failed",
+ "finished_at": "2016-03-29T06:28:12.630Z",
+ "trace": null,
+ "created_at": "2016-03-22T15:20:35.772Z",
+ "updated_at": "2016-03-29T06:28:12.634Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 36,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "stage_id": 11,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": null
+ },
+ "artifacts_metadata": {
+ "url": null
+ },
+ "erased_by_id": null,
+ "erased_at": null,
+ "type": "Ci::Build",
+ "token": "abcd"
+ },
+ {
+ "id": 72,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.",
+ "created_at": "2016-03-22T15:20:35.777Z",
+ "updated_at": "2016-03-22T15:20:35.777Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 36,
+ "commands": "$ deploy command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "deploy",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "stage_id": 12,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
},
{
"id": 12,
@@ -6484,82 +6560,6 @@
"created_at": "2016-03-22T15:45:45.772Z",
"updated_at": "2016-03-29T06:45:45.634Z"
}
- ],
- "statuses": [
- {
- "id": 71,
- "project_id": 5,
- "status": "failed",
- "finished_at": "2016-03-29T06:28:12.630Z",
- "trace": null,
- "created_at": "2016-03-22T15:20:35.772Z",
- "updated_at": "2016-03-29T06:28:12.634Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 36,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "stage_id": 11,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
- "erased_by_id": null,
- "erased_at": null,
- "type": "Ci::Build",
- "token": "abcd"
- },
- {
- "id": 72,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.",
- "created_at": "2016-03-22T15:20:35.777Z",
- "updated_at": "2016-03-22T15:20:35.777Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 36,
- "commands": "$ deploy command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "deploy",
- "trigger_request_id": null,
- "stage_idx": 1,
- "stage_id": 12,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
- }
]
},
{
@@ -6578,76 +6578,87 @@
"started_at": null,
"finished_at": null,
"duration": null,
- "statuses": [
- {
- "id": 74,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.",
- "created_at": "2016-03-22T15:20:35.846Z",
- "updated_at": "2016-03-22T15:20:35.846Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 37,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
- },
- {
- "id": 73,
- "project_id": 5,
- "status": "canceled",
- "finished_at": null,
- "trace": null,
- "created_at": "2016-03-22T15:20:35.842Z",
- "updated_at": "2016-03-22T15:20:35.842Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 37,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 21,
+ "project_id": 5,
+ "pipeline_id": 37,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 74,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.",
+ "created_at": "2016-03-22T15:20:35.846Z",
+ "updated_at": "2016-03-22T15:20:35.846Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 37,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ },
+ {
+ "id": 73,
+ "project_id": 5,
+ "status": "canceled",
+ "finished_at": null,
+ "trace": null,
+ "created_at": "2016-03-22T15:20:35.842Z",
+ "updated_at": "2016-03-22T15:20:35.842Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 37,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": null
+ },
+ "artifacts_metadata": {
+ "url": null
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
}
]
},
@@ -6667,76 +6678,87 @@
"started_at": null,
"finished_at": null,
"duration": null,
- "statuses": [
- {
- "id": 76,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.",
- "created_at": "2016-03-22T15:20:35.882Z",
- "updated_at": "2016-03-22T15:20:35.882Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 38,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
- },
- {
- "id": 75,
- "project_id": 5,
- "status": "failed",
- "finished_at": null,
- "trace": "Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.",
- "created_at": "2016-03-22T15:20:35.864Z",
- "updated_at": "2016-03-22T15:20:35.864Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 38,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 22,
+ "project_id": 5,
+ "pipeline_id": 38,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 76,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.",
+ "created_at": "2016-03-22T15:20:35.882Z",
+ "updated_at": "2016-03-22T15:20:35.882Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 38,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ },
+ {
+ "id": 75,
+ "project_id": 5,
+ "status": "failed",
+ "finished_at": null,
+ "trace": "Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.",
+ "created_at": "2016-03-22T15:20:35.864Z",
+ "updated_at": "2016-03-22T15:20:35.864Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 38,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
}
]
},
@@ -6756,76 +6778,87 @@
"started_at": null,
"finished_at": null,
"duration": null,
- "statuses": [
- {
- "id": 78,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.",
- "created_at": "2016-03-22T15:20:35.927Z",
- "updated_at": "2016-03-22T15:20:35.927Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 39,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
- },
- {
- "id": 77,
- "project_id": 5,
- "status": "failed",
- "finished_at": null,
- "trace": "Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.",
- "created_at": "2016-03-22T15:20:35.905Z",
- "updated_at": "2016-03-22T15:20:35.905Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 39,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 23,
+ "project_id": 5,
+ "pipeline_id": 39,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 78,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.",
+ "created_at": "2016-03-22T15:20:35.927Z",
+ "updated_at": "2016-03-22T15:20:35.927Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 39,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ },
+ {
+ "id": 77,
+ "project_id": 5,
+ "status": "failed",
+ "finished_at": null,
+ "trace": "Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.",
+ "created_at": "2016-03-22T15:20:35.905Z",
+ "updated_at": "2016-03-22T15:20:35.905Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 39,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
}
]
},
@@ -6845,76 +6878,87 @@
"started_at": null,
"finished_at": null,
"duration": null,
- "statuses": [
- {
- "id": 79,
- "project_id": 5,
- "status": "failed",
- "finished_at": "2016-03-29T06:28:12.695Z",
- "trace": "Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.",
- "created_at": "2016-03-22T15:20:35.950Z",
- "updated_at": "2016-03-29T06:28:12.696Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 40,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
- "erased_by_id": null,
- "erased_at": null
- },
- {
- "id": 80,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.",
- "created_at": "2016-03-22T15:20:35.966Z",
- "updated_at": "2016-03-22T15:20:35.966Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 40,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 24,
+ "project_id": 5,
+ "pipeline_id": 40,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 79,
+ "project_id": 5,
+ "status": "failed",
+ "finished_at": "2016-03-29T06:28:12.695Z",
+ "trace": "Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.",
+ "created_at": "2016-03-22T15:20:35.950Z",
+ "updated_at": "2016-03-29T06:28:12.696Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 40,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": null
+ },
+ "artifacts_metadata": {
+ "url": null
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ },
+ {
+ "id": 80,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.",
+ "created_at": "2016-03-22T15:20:35.966Z",
+ "updated_at": "2016-03-22T15:20:35.966Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 40,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
}
]
}
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 70a6d1a3c6a..77e57e5ed3e 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -181,14 +181,20 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
context 'when restoring hierarchy of pipeline, stages and jobs' do
- let(:pipeline) { Ci::Pipeline.first }
+ it 'restores statuses' do
+ expect(CommitStatus.all.count).to be 10
+ end
it 'restores pipeline stages' do
- expect(pipeline.stages.count).to be 2
+ expect(Ci::Stage.all.count).to be 6
end
it 'correctly restores association between a stage and a job' do
- expect(pipeline.statuses).to all(have_attributes(stage_id: a_value > 0))
+ expect(CommitStatus.all).to all(have_attributes(stage_id: a_value > 0))
+ end
+
+ it 'correctly restores association between a stage and a pipeline' do
+ expect(CommitStatus.all).to all(have_attributes(pipeline_id: a_value > 0))
end
end
end
--
cgit v1.2.1
From bf8c5643a9cb665467deea0106fa35b91b2fa938 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Fri, 5 Jan 2018 15:18:17 +0100
Subject: Bump import/export version to 2.2.0
We need to bump import/export version because we introduced a new
object's hierarchy that is not backwards compatible.
---
doc/user/project/settings/import_export.md | 3 ++-
lib/gitlab/import_export.rb | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 1b8a84c9599..b8f865679a2 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -30,7 +30,8 @@ with all their related data and be moved into a new GitLab instance.
| GitLab version | Import/Export version |
| ---------------- | --------------------- |
-| 10.3 to current | 0.2.1 |
+| 10.4 to current | 0.2.2 |
+| 10.3 | 0.2.1 |
| 10.0 | 0.2.0 |
| 9.4.0 | 0.1.8 |
| 9.2.0 | 0.1.7 |
diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb
index 2066005dddc..af203ff711d 100644
--- a/lib/gitlab/import_export.rb
+++ b/lib/gitlab/import_export.rb
@@ -3,7 +3,7 @@ module Gitlab
extend self
# For every version update, the version history in import_export.md has to be kept up to date.
- VERSION = '0.2.1'.freeze
+ VERSION = '0.2.2'.freeze
FILENAME_LIMIT = 50
def export_path(relative_path:)
--
cgit v1.2.1
From adc9e13d279cec7f18c47b771bbd5c734ab2731a Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Fri, 5 Jan 2018 15:19:05 +0100
Subject: Fix import/export project tree saver specs
---
.../lib/gitlab/import_export/project_tree_restorer_spec.rb | 14 +++++++++-----
spec/lib/gitlab/import_export/project_tree_saver_spec.rb | 12 ++++++++++--
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 77e57e5ed3e..45e983a8604 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -181,19 +181,23 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
context 'when restoring hierarchy of pipeline, stages and jobs' do
- it 'restores statuses' do
- expect(CommitStatus.all.count).to be 10
- end
-
it 'restores pipeline stages' do
expect(Ci::Stage.all.count).to be 6
end
+ it 'correctly restores association between stage and a pipeline' do
+ expect(Ci::Stage.all).to all(have_attributes(pipeline_id: a_value > 0))
+ end
+
+ it 'restores statuses' do
+ expect(CommitStatus.all.count).to be 10
+ end
+
it 'correctly restores association between a stage and a job' do
expect(CommitStatus.all).to all(have_attributes(stage_id: a_value > 0))
end
- it 'correctly restores association between a stage and a pipeline' do
+ it 'correctly restores association between a pipeline and a job' do
expect(CommitStatus.all).to all(have_attributes(pipeline_id: a_value > 0))
end
end
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index 6faf3d82981..08e5bbbd400 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -109,12 +109,20 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
expect(saved_project_json['merge_requests'].first['notes'].first['author']).not_to be_empty
end
+ it 'has pipeline stages' do
+ expect(saved_project_json.dig('pipelines', 0, 'stages')).not_to be_empty
+ end
+
it 'has pipeline statuses' do
- expect(saved_project_json['pipelines'].first['statuses']).not_to be_empty
+ expect(saved_project_json.dig('pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty
end
it 'has pipeline builds' do
- expect(saved_project_json['pipelines'].first['statuses'].count { |hash| hash['type'] == 'Ci::Build' }).to eq(1)
+ builds_count = saved_project_json
+ .dig('pipelines', 0, 'stages', 0, 'statuses')
+ .count { |hash| hash['type'] == 'Ci::Build' }
+
+ expect(builds_count).to eq(1)
end
it 'has no when YML attributes but only the DB column' do
--
cgit v1.2.1
From a01994bf075ccade4487b398bb59ef7f9ef21522 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Fri, 5 Jan 2018 15:20:41 +0100
Subject: Add changelog entry for import/export associations fix
---
.../unreleased/fix-gb-fix-import-export-restoring-associations.yml | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 changelogs/unreleased/fix-gb-fix-import-export-restoring-associations.yml
diff --git a/changelogs/unreleased/fix-gb-fix-import-export-restoring-associations.yml b/changelogs/unreleased/fix-gb-fix-import-export-restoring-associations.yml
new file mode 100644
index 00000000000..58df0024d61
--- /dev/null
+++ b/changelogs/unreleased/fix-gb-fix-import-export-restoring-associations.yml
@@ -0,0 +1,6 @@
+---
+title: Fix missing references to pipeline objects when restoring project with import/export
+ feature
+merge_request: 16221
+author:
+type: fixed
--
cgit v1.2.1
From 8bdc6c74e82445048d66f6bf4be9dd0db7dc4737 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Fri, 5 Jan 2018 15:32:41 +0100
Subject: Rephrase paragraph about e2e tests in merge requests in docs
---
doc/development/testing_guide/end_to_end_tests.md | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/doc/development/testing_guide/end_to_end_tests.md b/doc/development/testing_guide/end_to_end_tests.md
index 30efe3e3b76..abe5b06e0f0 100644
--- a/doc/development/testing_guide/end_to_end_tests.md
+++ b/doc/development/testing_guide/end_to_end_tests.md
@@ -20,15 +20,13 @@ You can find these nightly pipelines at [GitLab QA pipelines page][gitlab-qa-pip
### Testing code in merge requests
-It is also possible to trigger build of GitLab packages and then pass these
-package to GitLab QA to run tests in a [pipeline][gitlab-qa-pipelines].
+It is possible to run end-to-end tests (eventually being run within a
+[GitLab QA pipeline][gitlab-qa-pipelines]) for a merge request by triggering
+the `package-qa` manual action, that should be present in a merge request
+widget.
-Developers can trigger the `package-qa` manual action, that should be present in
-the merge request widget.
-
-It is also possible to trigger Gitlab QA pipeline from merge requests in
-Omnibus GitLab project. You can find a manual action that is similar to
-`package-qa`, mentioned above, in your Omnibus-related merge requests as well.
+Mmanual action that starts end-to-end tests is also available in merge requests
+in Omnibus GitLab project.
Below you can read more about how to use it and how does it work.
--
cgit v1.2.1
From 7e117b4c9d7fe51215fc2af46c2429db7b71f32c Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Fri, 5 Jan 2018 15:38:56 +0100
Subject: Assert on correctly restoring pipelines after an import
---
spec/lib/gitlab/import_export/project_tree_restorer_spec.rb | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 45e983a8604..9dfd879a1bc 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -181,6 +181,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
context 'when restoring hierarchy of pipeline, stages and jobs' do
+ it 'restores pipelines' do
+ expect(Ci::Pipeline.all.count).to be 5
+ end
+
it 'restores pipeline stages' do
expect(Ci::Stage.all.count).to be 6
end
--
cgit v1.2.1
From 288b276077987bc77f191d2cb93eb2f764c5c1ef Mon Sep 17 00:00:00 2001
From: Douwe Maan
Date: Wed, 20 Dec 2017 14:48:09 +0100
Subject: Copy Mermaid graphs as GFM
---
app/assets/javascripts/behaviors/copy_as_gfm.js | 12 ++++
app/assets/javascripts/render_mermaid.js | 20 +++++-
lib/banzai/filter/mermaid_filter.rb | 11 +--
spec/features/copy_as_gfm_spec.rb | 96 +++++++++++++++++++++++++
spec/features/markdown_spec.rb | 2 +-
spec/lib/banzai/filter/mermaid_filter_spec.rb | 4 +-
6 files changed, 131 insertions(+), 14 deletions(-)
diff --git a/app/assets/javascripts/behaviors/copy_as_gfm.js b/app/assets/javascripts/behaviors/copy_as_gfm.js
index e7dc4ef8304..c6eca72c51b 100644
--- a/app/assets/javascripts/behaviors/copy_as_gfm.js
+++ b/app/assets/javascripts/behaviors/copy_as_gfm.js
@@ -74,6 +74,18 @@ const gfmRules = {
return `})`;
},
},
+ MermaidFilter: {
+ 'svg.mermaid'(el, text) {
+ const sourceEl = el.querySelector('text.source');
+ if (!sourceEl) return false;
+
+ return `\`\`\`mermaid\n${CopyAsGFM.nodeToGFM(sourceEl)}\n\`\`\``;
+ },
+ 'svg.mermaid style, svg.mermaid g'(el, text) {
+ // We don't want to include the content of these elements in the copied text.
+ return '';
+ },
+ },
MathFilter: {
'pre.code.math[data-math-style=display]'(el, text) {
return `\`\`\`math\n${text.trim()}\n\`\`\``;
diff --git a/app/assets/javascripts/render_mermaid.js b/app/assets/javascripts/render_mermaid.js
index 41942c04a4e..b7cde6fb092 100644
--- a/app/assets/javascripts/render_mermaid.js
+++ b/app/assets/javascripts/render_mermaid.js
@@ -24,7 +24,25 @@ export default function renderMermaid($els) {
});
$els.each((i, el) => {
- mermaid.init(undefined, el);
+ const source = el.textContent;
+
+ mermaid.init(undefined, el, (id) => {
+ const svg = document.getElementById(id);
+
+ svg.classList.add('mermaid');
+
+ // pre > code > svg
+ svg.closest('pre').replaceWith(svg);
+
+ // We need to add the original source into the DOM to allow Copy-as-GFM
+ // to access it.
+ const sourceEl = document.createElement('text');
+ sourceEl.classList.add('source');
+ sourceEl.setAttribute('display', 'none');
+ sourceEl.textContent = source;
+
+ svg.appendChild(sourceEl);
+ });
});
}).catch((err) => {
Flash(`Can't load mermaid module: ${err}`);
diff --git a/lib/banzai/filter/mermaid_filter.rb b/lib/banzai/filter/mermaid_filter.rb
index b545b947a2c..65c131e08d9 100644
--- a/lib/banzai/filter/mermaid_filter.rb
+++ b/lib/banzai/filter/mermaid_filter.rb
@@ -2,16 +2,7 @@ module Banzai
module Filter
class MermaidFilter < HTML::Pipeline::Filter
def call
- doc.css('pre[lang="mermaid"]').add_class('mermaid')
- doc.css('pre[lang="mermaid"]').add_class('js-render-mermaid')
-
- # The `` blocks are added in the lib/banzai/filter/syntax_highlight_filter.rb
- # We want to keep context and consistency, so we the blocks are added for all filters.
- # Details: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15107/diffs?diff_id=7962900#note_45495859
- doc.css('pre[lang="mermaid"]').each do |pre|
- document = pre.at('code')
- document.replace(document.content)
- end
+ doc.css('pre[lang="mermaid"] > code').add_class('js-render-mermaid')
doc
end
diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb
index 1fcb8d5bc67..d8f1a919522 100644
--- a/spec/features/copy_as_gfm_spec.rb
+++ b/spec/features/copy_as_gfm_spec.rb
@@ -284,6 +284,102 @@ describe 'Copy as GFM', :js do
expect(output_gfm.strip).to eq(gfm.strip)
end
+ verify(
+ 'MermaidFilter: mermaid as converted from GFM to HTML',
+
+ <<-GFM.strip_heredoc
+ ```mermaid
+ graph TD;
+ A-->B;
+ ```
+ GFM
+ )
+
+ aggregate_failures('MermaidFilter: mermaid as transformed from HTML to SVG') do
+ gfm = <<-GFM.strip_heredoc
+ ```mermaid
+ graph TD;
+ A-->B;
+ ```
+ GFM
+
+ html = <<-HTML.strip_heredoc
+
+ HTML
+
+ output_gfm = html_to_gfm(html)
+ expect(output_gfm.strip).to eq(gfm.strip)
+ end
+
verify(
'SanitizationFilter',
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index e285befc66f..a2b78a5e021 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -71,7 +71,7 @@ describe 'GitLab Markdown' do
it 'parses mermaid code block' do
aggregate_failures do
- expect(doc).to have_selector('pre.code.js-render-mermaid')
+ expect(doc).to have_selector('pre[lang=mermaid] > code.js-render-mermaid')
end
end
diff --git a/spec/lib/banzai/filter/mermaid_filter_spec.rb b/spec/lib/banzai/filter/mermaid_filter_spec.rb
index 532d25e121d..f6474c8936d 100644
--- a/spec/lib/banzai/filter/mermaid_filter_spec.rb
+++ b/spec/lib/banzai/filter/mermaid_filter_spec.rb
@@ -3,9 +3,9 @@ require 'spec_helper'
describe Banzai::Filter::MermaidFilter do
include FilterSpecHelper
- it 'adds `js-render-mermaid` class to the `pre` tag' do
+ it 'adds `js-render-mermaid` class to the `code` tag' do
doc = filter("
graph TD;\n A-->B;\n
")
- result = doc.xpath('descendant-or-self::pre').first
+ result = doc.css('code').first
expect(result[:class]).to include('js-render-mermaid')
end
--
cgit v1.2.1
From 34b9cc9674554155af49c9a7fe60aaeba72bb23d Mon Sep 17 00:00:00 2001
From: Brent Greeff
Date: Fri, 5 Jan 2018 15:21:53 +0000
Subject: API: get participants from merge_requests & issues
---
...s-40986-get-participants-from-issues-mr-api.yml | 5 +++
doc/api/issues.md | 39 ++++++++++++++++++++++
doc/api/merge_requests.md | 35 +++++++++++++++++++
lib/api/issues.rb | 13 ++++++++
lib/api/merge_requests.rb | 10 ++++++
spec/requests/api/issues_spec.rb | 12 +++++++
spec/requests/api/merge_requests_spec.rb | 6 ++++
.../requests/api/issuable_participants_examples.rb | 29 ++++++++++++++++
8 files changed, 149 insertions(+)
create mode 100644 changelogs/unreleased/issues-40986-get-participants-from-issues-mr-api.yml
create mode 100644 spec/support/shared_examples/requests/api/issuable_participants_examples.rb
diff --git a/changelogs/unreleased/issues-40986-get-participants-from-issues-mr-api.yml b/changelogs/unreleased/issues-40986-get-participants-from-issues-mr-api.yml
new file mode 100644
index 00000000000..4cac87b0cdb
--- /dev/null
+++ b/changelogs/unreleased/issues-40986-get-participants-from-issues-mr-api.yml
@@ -0,0 +1,5 @@
+---
+title: 'API: get participants from merge_requests & issues'
+merge_request: 16187
+author: Brent Greeff
+type: added
diff --git a/doc/api/issues.md b/doc/api/issues.md
index d2fefbe68aa..da89db17cd9 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -1124,6 +1124,45 @@ Example response:
```
+## Participants on issues
+
+```
+GET /projects/:id/issues/:issue_iid/participants
+```
+
+| Attribute | Type | Required | Description |
+|-------------|---------|----------|--------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `issue_iid` | integer | yes | The internal ID of a project's issue |
+
+```bash
+curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/participants
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "name": "John Doe1",
+ "username": "user1",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
+ "web_url": "http://localhost/user1"
+ },
+ {
+ "id": 5,
+ "name": "John Doe5",
+ "username": "user5",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/4aea8cf834ed91844a2da4ff7ae6b491?s=80&d=identicon",
+ "web_url": "http://localhost/user5"
+ }
+]
+```
+
+
## Comments on issues
Comments are done via the [notes](notes.md) resource.
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 4d3592e8f71..24afcef9a31 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -308,6 +308,41 @@ Parameters:
}
```
+## Get single MR participants
+
+Get a list of merge request participants.
+
+```
+GET /projects/:id/merge_requests/:merge_request_iid/participants
+```
+
+Parameters:
+
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `merge_request_iid` (required) - The internal ID of the merge request
+
+
+```json
+[
+ {
+ "id": 1,
+ "name": "John Doe1",
+ "username": "user1",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
+ "web_url": "http://localhost/user1"
+ },
+ {
+ "id": 2,
+ "name": "John Doe2",
+ "username": "user2",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon",
+ "web_url": "http://localhost/user2"
+ },
+]
+```
+
## Get single MR commits
Get a list of merge request commits.
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index b29c5848aef..7aa10631d53 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -277,6 +277,19 @@ module API
present paginate(merge_requests), with: Entities::MergeRequestBasic, current_user: current_user, project: user_project
end
+ desc 'List participants for an issue' do
+ success Entities::UserBasic
+ end
+ params do
+ requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
+ end
+ get ':id/issues/:issue_iid/participants' do
+ issue = find_project_issue(params[:issue_iid])
+ participants = ::Kaminari.paginate_array(issue.participants)
+
+ present paginate(participants), with: Entities::UserBasic, current_user: current_user, project: user_project
+ end
+
desc 'Get the user agent details for an issue' do
success Entities::UserAgentDetail
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 02f2b75ab9d..8f665b39fa8 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -185,6 +185,16 @@ module API
present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project
end
+ desc 'Get the participants of a merge request' do
+ success Entities::UserBasic
+ end
+ get ':id/merge_requests/:merge_request_iid/participants' do
+ merge_request = find_merge_request_with_access(params[:merge_request_iid])
+ participants = ::Kaminari.paginate_array(merge_request.participants)
+
+ present paginate(participants), with: Entities::UserBasic
+ end
+
desc 'Get the commits of a merge request' do
success Entities::Commit
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 00d9c795619..320217f2032 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -1582,4 +1582,16 @@ describe API::Issues, :mailer do
expect(json_response).to be_an Array
expect(json_response.length).to eq(size) if size
end
+
+ describe 'GET projects/:id/issues/:issue_iid/participants' do
+ it_behaves_like 'issuable participants endpoint' do
+ let(:entity) { issue }
+ end
+
+ it 'returns 404 if the issue is confidential' do
+ post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/participants", non_member)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index ef3f610740d..0c9fbb1f187 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -500,6 +500,12 @@ describe API::MergeRequests do
end
end
+ describe 'GET /projects/:id/merge_requests/:merge_request_iid/participants' do
+ it_behaves_like 'issuable participants endpoint' do
+ let(:entity) { merge_request }
+ end
+ end
+
describe 'GET /projects/:id/merge_requests/:merge_request_iid/commits' do
it 'returns a 200 when merge request is valid' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/commits", user)
diff --git a/spec/support/shared_examples/requests/api/issuable_participants_examples.rb b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb
new file mode 100644
index 00000000000..96d59e0c472
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb
@@ -0,0 +1,29 @@
+shared_examples 'issuable participants endpoint' do
+ let(:area) { entity.class.name.underscore.pluralize }
+
+ it 'returns participants' do
+ get api("/projects/#{project.id}/#{area}/#{entity.iid}/participants", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(entity.participants.size)
+
+ last_participant = entity.participants.last
+ expect(json_response.last['id']).to eq(last_participant.id)
+ expect(json_response.last['name']).to eq(last_participant.name)
+ expect(json_response.last['username']).to eq(last_participant.username)
+ end
+
+ it 'returns a 404 when iid does not exist' do
+ get api("/projects/#{project.id}/#{area}/999/participants", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 404 when id is used instead of iid' do
+ get api("/projects/#{project.id}/#{area}/#{entity.id}/participants", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+end
--
cgit v1.2.1
From 7f30bb9c29bc1ff0c903a16bbf678db31c7408ec Mon Sep 17 00:00:00 2001
From: Yorick Peterse
Date: Thu, 4 Jan 2018 16:49:15 +0100
Subject: Run background migrations with a minimum interval
This adds a minimum interval to BackgroundMigrationWorker, ensuring
background migrations of the same class only run once every 5 minutes.
This prevents a thundering herd problem where scheduled migrations all
run at once due to their delays having been expired (e.g. as the result
of a queue being paused for a long time).
If a job was recently executed it's rescheduled with a delay that equals
the remaining time of the job's lease. This means that if the lease
expires in two minutes we only need to wait two minutes, instead of
five.
Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/41624
---
app/workers/background_migration_worker.rb | 45 +++++++++++++++++++++-
.../unreleased/delay-background-migrations.yml | 5 +++
lib/gitlab/database/migration_helpers.rb | 6 +++
lib/gitlab/exclusive_lease.rb | 11 ++++++
spec/lib/gitlab/database/migration_helpers_spec.rb | 10 ++---
spec/lib/gitlab/exclusive_lease_spec.rb | 15 ++++++++
spec/migrations/normalize_ldap_extern_uids_spec.rb | 6 +--
spec/workers/background_migration_worker_spec.rb | 23 ++++++++++-
8 files changed, 110 insertions(+), 11 deletions(-)
create mode 100644 changelogs/unreleased/delay-background-migrations.yml
diff --git a/app/workers/background_migration_worker.rb b/app/workers/background_migration_worker.rb
index aeb3bc019b9..376703f6319 100644
--- a/app/workers/background_migration_worker.rb
+++ b/app/workers/background_migration_worker.rb
@@ -1,10 +1,53 @@
class BackgroundMigrationWorker
include ApplicationWorker
+ # The minimum amount of time between processing two jobs of the same migration
+ # class.
+ #
+ # This interval is set to 5 minutes so autovacuuming and other maintenance
+ # related tasks have plenty of time to clean up after a migration has been
+ # performed.
+ MIN_INTERVAL = 5.minutes.to_i
+
# Performs the background migration.
#
# See Gitlab::BackgroundMigration.perform for more information.
+ #
+ # class_name - The class name of the background migration to run.
+ # arguments - The arguments to pass to the migration class.
def perform(class_name, arguments = [])
- Gitlab::BackgroundMigration.perform(class_name, arguments)
+ should_perform, ttl = perform_and_ttl(class_name)
+
+ if should_perform
+ Gitlab::BackgroundMigration.perform(class_name, arguments)
+ else
+ # If the lease could not be obtained this means either another process is
+ # running a migration of this class or we ran one recently. In this case
+ # we'll reschedule the job in such a way that it is picked up again around
+ # the time the lease expires.
+ self.class.perform_in(ttl || MIN_INTERVAL, class_name, arguments)
+ end
+ end
+
+ def perform_and_ttl(class_name)
+ if always_perform?
+ # In test environments `perform_in` will run right away. This can then
+ # lead to stack level errors in the above `#perform`. To work around this
+ # we'll just perform the migration right away in the test environment.
+ [true, nil]
+ else
+ lease = lease_for(class_name)
+
+ [lease.try_obtain, lease.ttl]
+ end
+ end
+
+ def lease_for(class_name)
+ Gitlab::ExclusiveLease
+ .new("#{self.class.name}:#{class_name}", timeout: MIN_INTERVAL)
+ end
+
+ def always_perform?
+ Rails.env.test?
end
end
diff --git a/changelogs/unreleased/delay-background-migrations.yml b/changelogs/unreleased/delay-background-migrations.yml
new file mode 100644
index 00000000000..aa12591e7d2
--- /dev/null
+++ b/changelogs/unreleased/delay-background-migrations.yml
@@ -0,0 +1,5 @@
+---
+title: Run background migrations with a minimum interval
+merge_request:
+author:
+type: changed
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 33171f83692..7b35c24d153 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -842,6 +842,12 @@ into similar problems in the future (e.g. when new tables are created).
def queue_background_migration_jobs_by_range_at_intervals(model_class, job_class_name, delay_interval, batch_size: BACKGROUND_MIGRATION_BATCH_SIZE)
raise "#{model_class} does not have an ID to use for batch ranges" unless model_class.column_names.include?('id')
+ # To not overload the worker too much we enforce a minimum interval both
+ # when scheduling and performing jobs.
+ if delay_interval < BackgroundMigrationWorker::MIN_INTERVAL
+ delay_interval = BackgroundMigrationWorker::MIN_INTERVAL
+ end
+
model_class.each_batch(of: batch_size) do |relation, index|
start_id, end_id = relation.pluck('MIN(id), MAX(id)').first
diff --git a/lib/gitlab/exclusive_lease.rb b/lib/gitlab/exclusive_lease.rb
index 3f7b42456af..dbb8f317afe 100644
--- a/lib/gitlab/exclusive_lease.rb
+++ b/lib/gitlab/exclusive_lease.rb
@@ -71,5 +71,16 @@ module Gitlab
redis.exists(@redis_shared_state_key)
end
end
+
+ # Returns the TTL of the Redis key.
+ #
+ # This method will return `nil` if no TTL could be obtained.
+ def ttl
+ Gitlab::Redis::SharedState.with do |redis|
+ ttl = redis.ttl(@redis_shared_state_key)
+
+ ttl if ttl.positive?
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 7727a1d81b1..43761c2fe0c 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -1006,12 +1006,12 @@ describe Gitlab::Database::MigrationHelpers do
context 'with batch_size option' do
it 'queues jobs correctly' do
Sidekiq::Testing.fake! do
- model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.seconds, batch_size: 2)
+ model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.minutes, batch_size: 2)
expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['FooJob', [id1, id2]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.minutes.from_now.to_f)
expect(BackgroundMigrationWorker.jobs[1]['args']).to eq(['FooJob', [id3, id3]])
- expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.minutes.from_now.to_f)
end
end
end
@@ -1019,10 +1019,10 @@ describe Gitlab::Database::MigrationHelpers do
context 'without batch_size option' do
it 'queues jobs correctly' do
Sidekiq::Testing.fake! do
- model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.seconds)
+ model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.minutes)
expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['FooJob', [id1, id3]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.minutes.from_now.to_f)
end
end
end
diff --git a/spec/lib/gitlab/exclusive_lease_spec.rb b/spec/lib/gitlab/exclusive_lease_spec.rb
index 7322a326b01..6193e177668 100644
--- a/spec/lib/gitlab/exclusive_lease_spec.rb
+++ b/spec/lib/gitlab/exclusive_lease_spec.rb
@@ -73,4 +73,19 @@ describe Gitlab::ExclusiveLease, :clean_gitlab_redis_shared_state do
described_class.new(key, timeout: 3600).try_obtain
end
end
+
+ describe '#ttl' do
+ it 'returns the TTL of the Redis key' do
+ lease = described_class.new('kittens', timeout: 100)
+ lease.try_obtain
+
+ expect(lease.ttl <= 100).to eq(true)
+ end
+
+ it 'returns nil when the lease does not exist' do
+ lease = described_class.new('kittens', timeout: 10)
+
+ expect(lease.ttl).to be_nil
+ end
+ end
end
diff --git a/spec/migrations/normalize_ldap_extern_uids_spec.rb b/spec/migrations/normalize_ldap_extern_uids_spec.rb
index 262d7742aaf..56a78f52802 100644
--- a/spec/migrations/normalize_ldap_extern_uids_spec.rb
+++ b/spec/migrations/normalize_ldap_extern_uids_spec.rb
@@ -27,11 +27,11 @@ describe NormalizeLdapExternUids, :migration, :sidekiq do
migrate!
expect(BackgroundMigrationWorker.jobs[0]['args']).to eq([described_class::MIGRATION, [1, 2]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(5.minutes.from_now.to_f)
expect(BackgroundMigrationWorker.jobs[1]['args']).to eq([described_class::MIGRATION, [3, 4]])
- expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(10.minutes.from_now.to_f)
expect(BackgroundMigrationWorker.jobs[2]['args']).to eq([described_class::MIGRATION, [5, 5]])
- expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(30.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(15.minutes.from_now.to_f)
expect(BackgroundMigrationWorker.jobs.size).to eq 3
end
end
diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb
index 1c54cf55fa0..d67e7698635 100644
--- a/spec/workers/background_migration_worker_spec.rb
+++ b/spec/workers/background_migration_worker_spec.rb
@@ -1,13 +1,32 @@
require 'spec_helper'
-describe BackgroundMigrationWorker, :sidekiq do
+describe BackgroundMigrationWorker, :sidekiq, :clean_gitlab_redis_shared_state do
+ let(:worker) { described_class.new }
+
describe '.perform' do
it 'performs a background migration' do
expect(Gitlab::BackgroundMigration)
.to receive(:perform)
.with('Foo', [10, 20])
- described_class.new.perform('Foo', [10, 20])
+ worker.perform('Foo', [10, 20])
+ end
+
+ it 'reschedules a migration if it was performed recently' do
+ expect(worker)
+ .to receive(:always_perform?)
+ .and_return(false)
+
+ worker.lease_for('Foo').try_obtain
+
+ expect(Gitlab::BackgroundMigration)
+ .not_to receive(:perform)
+
+ expect(described_class)
+ .to receive(:perform_in)
+ .with(a_kind_of(Numeric), 'Foo', [10, 20])
+
+ worker.perform('Foo', [10, 20])
end
end
end
--
cgit v1.2.1
From 06d4f07a041a70fe9462bcae47b1b191908347ab Mon Sep 17 00:00:00 2001
From: Felipe Artur
Date: Tue, 26 Dec 2017 17:16:43 -0200
Subject: Improve filtering issues by label performance
---
app/controllers/concerns/issues_action.rb | 2 -
app/controllers/concerns/merge_requests_action.rb | 1 -
app/finders/issuable_finder.rb | 15 +--
changelogs/unreleased/issue_40500.yml | 5 +
db/fixtures/development/22_labeled_issues_seed.rb | 112 ++++++++++++++++++++++
5 files changed, 122 insertions(+), 13 deletions(-)
create mode 100644 changelogs/unreleased/issue_40500.yml
create mode 100644 db/fixtures/development/22_labeled_issues_seed.rb
diff --git a/app/controllers/concerns/issues_action.rb b/app/controllers/concerns/issues_action.rb
index d4cccbe6442..3ba1235cee0 100644
--- a/app/controllers/concerns/issues_action.rb
+++ b/app/controllers/concerns/issues_action.rb
@@ -5,8 +5,6 @@ module IssuesAction
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def issues
@finder_type = IssuesFinder
- @label = finder.labels.first
-
@issues = issuables_collection
.non_archived
.page(params[:page])
diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb
index 4d44df3bba9..a9cc13038bf 100644
--- a/app/controllers/concerns/merge_requests_action.rb
+++ b/app/controllers/concerns/merge_requests_action.rb
@@ -5,7 +5,6 @@ module MergeRequestsAction
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def merge_requests
@finder_type = MergeRequestsFinder
- @label = finder.labels.first
@merge_requests = issuables_collection.page(params[:page])
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index b46ec5e5350..493e7985d75 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -374,19 +374,14 @@ class IssuableFinder
end
def by_label(items)
- if labels?
+ return items unless labels?
+
+ items =
if filter_by_no_label?
- items = items.without_label
+ items.without_label
else
- items = items.with_label(label_names, params[:sort])
- items_projects = projects(items)
-
- if items_projects
- label_ids = LabelsFinder.new(current_user, project_ids: items_projects).execute(skip_authorization: true).select(:id)
- items = items.where(labels: { id: label_ids })
- end
+ items.with_label(label_names, params[:sort])
end
- end
items
end
diff --git a/changelogs/unreleased/issue_40500.yml b/changelogs/unreleased/issue_40500.yml
new file mode 100644
index 00000000000..35e8938fdad
--- /dev/null
+++ b/changelogs/unreleased/issue_40500.yml
@@ -0,0 +1,5 @@
+---
+title: Fix timeout when filtering issues by label
+merge_request:
+author:
+type: performance
diff --git a/db/fixtures/development/22_labeled_issues_seed.rb b/db/fixtures/development/22_labeled_issues_seed.rb
new file mode 100644
index 00000000000..3e4485c7a73
--- /dev/null
+++ b/db/fixtures/development/22_labeled_issues_seed.rb
@@ -0,0 +1,112 @@
+# Creates a project with labeled issues for a user.
+# Run this single seed file using: rake db:seed_fu FILTER=labeled USER_ID=74.
+# If an USER_ID is not provided it will use the last created user.
+require './spec/support/sidekiq'
+
+class Gitlab::Seeder::LabeledIssues
+ include ::Gitlab::Utils
+
+ def initialize(user)
+ @user = user
+ end
+
+ def seed!
+ Sidekiq::Testing.inline! do
+ group = create_group
+ puts '.'
+
+ create_projects(group)
+ puts '.'
+
+ create_labels(group)
+ puts '.'
+
+ create_issues(group)
+ puts '.'
+ end
+
+ print '.'
+ end
+
+ private
+
+ def create_group
+ group_name = "group_of_#{@user.name}#{SecureRandom.hex(4)}"
+
+ group = Group.new(
+ name: group_name,
+ path: group_name,
+ description: FFaker::Lorem.sentence
+ )
+
+ group.save
+
+ group.add_owner(@user)
+
+ group
+ end
+
+ def create_projects(group)
+ 5.times do
+ project_name = "project_#{SecureRandom.hex(6)}"
+ params = {
+ namespace_id: group.id,
+ name: project_name,
+ description: FFaker::Lorem.sentence,
+ visibility_level: Gitlab::VisibilityLevel.values.sample
+ }
+
+ Projects::CreateService.new(@user, params).execute
+ end
+ end
+
+ def create_labels(group)
+ group.projects.each do |project|
+ 5.times do
+ label_title = FFaker::Vehicle.model
+ Labels::CreateService.new(title: label_title).execute(project: project)
+ end
+ end
+
+ 10.times do
+ label_title = FFaker::Product.brand
+ Labels::CreateService.new(title: label_title).execute(group: group)
+ end
+ end
+
+ def create_issues(group)
+ # Get only group labels
+ group_labels =
+ LabelsFinder.new(@user, group_id: group.id).execute.where.not(group_id: nil)
+
+ group.projects.each do |project|
+ label_ids = project.labels.pluck(:id).sample(5)
+ label_ids.push(*group.labels.sample(4))
+
+ 50.times do
+ issue_params = {
+ title: FFaker::Lorem.sentence(6),
+ description: FFaker::Lorem.sentence,
+ state: 'opened',
+ label_ids: label_ids
+
+ }
+
+ Issues::CreateService.new(project, @user, issue_params).execute if project.project_feature.present?
+ end
+ end
+ end
+end
+
+Gitlab::Seeder.quiet do
+ user_id = ENV['USER_ID']
+
+ user =
+ if user_id.present?
+ User.find(user_id)
+ else
+ User.last
+ end
+
+ Gitlab::Seeder::LabeledIssues.new(user).seed!
+end
--
cgit v1.2.1
From fb2ca26f523f7dd4422b4d82f18e92a234ed4c05 Mon Sep 17 00:00:00 2001
From: Lin Jen-Shin
Date: Fri, 5 Jan 2018 23:45:12 +0800
Subject: Remove unused push_code_to_protected_branches
---
app/assets/javascripts/users_select.js | 2 --
app/helpers/selects_helper.rb | 1 -
app/policies/project_policy.rb | 1 -
3 files changed, 4 deletions(-)
diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js
index 759cc9925f4..f249bd036d6 100644
--- a/app/assets/javascripts/users_select.js
+++ b/app/assets/javascripts/users_select.js
@@ -541,7 +541,6 @@ function UsersSelect(currentUser, els, options = {}) {
options.projectId = $(select).data('project-id');
options.groupId = $(select).data('group-id');
options.showCurrentUser = $(select).data('current-user');
- options.pushCodeToProtectedBranches = $(select).data('push-code-to-protected-branches');
options.authorId = $(select).data('author-id');
options.skipUsers = $(select).data('skip-users');
showNullUser = $(select).data('null-user');
@@ -688,7 +687,6 @@ UsersSelect.prototype.users = function(query, options, callback) {
todo_filter: options.todoFilter || null,
todo_state_filter: options.todoStateFilter || null,
current_user: options.showCurrentUser || null,
- push_code_to_protected_branches: options.pushCodeToProtectedBranches || null,
author_id: options.authorId || null,
skip_users: options.skipUsers || null
},
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
index 1a4f1431bdc..6cefcde558a 100644
--- a/app/helpers/selects_helper.rb
+++ b/app/helpers/selects_helper.rb
@@ -73,7 +73,6 @@ module SelectsHelper
email_user: opts[:email_user] || false,
first_user: opts[:first_user] && current_user ? current_user.username : false,
current_user: opts[:current_user] || false,
- "push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
author_id: opts[:author_id] || '',
skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil
}
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index f599eab42f2..1dd8f0a25a9 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -241,7 +241,6 @@ class ProjectPolicy < BasePolicy
rule { repository_disabled }.policy do
prevent :push_code
- prevent :push_code_to_protected_branches
prevent :download_code
prevent :fork_project
prevent :read_commit_status
--
cgit v1.2.1
From f40373329f34b56647945522fccad3202ceafcde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 16:54:07 +0100
Subject: Add CHANGELOG entry
---
changelogs/unreleased/41249-clearing-the-cache.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 changelogs/unreleased/41249-clearing-the-cache.yml
diff --git a/changelogs/unreleased/41249-clearing-the-cache.yml b/changelogs/unreleased/41249-clearing-the-cache.yml
new file mode 100644
index 00000000000..221589a1239
--- /dev/null
+++ b/changelogs/unreleased/41249-clearing-the-cache.yml
@@ -0,0 +1,5 @@
+---
+title: Implement project jobs cache reset
+merge_request: 16067
+author:
+type: added
--
cgit v1.2.1
From 17b44dce06c2a70639bbad45bee696075fa21598 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 17:44:41 +0100
Subject: Use token hash for redis key
---
app/workers/check_gcp_project_billing_worker.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb
index 8d80f9c9be3..24575f84509 100644
--- a/app/workers/check_gcp_project_billing_worker.rb
+++ b/app/workers/check_gcp_project_billing_worker.rb
@@ -4,7 +4,7 @@ class CheckGcpProjectBillingWorker
LEASE_TIMEOUT = 15.seconds.to_i
def self.redis_shared_state_key_for(token)
- "gitlab:gcp:#{token}:billing_enabled"
+ "gitlab:gcp:#{token.hash}:billing_enabled"
end
def perform(token)
@@ -21,7 +21,7 @@ class CheckGcpProjectBillingWorker
def try_obtain_lease_for(token)
Gitlab::ExclusiveLease
- .new("check_gcp_project_billing_worker:#{token}", timeout: LEASE_TIMEOUT)
+ .new("check_gcp_project_billing_worker:#{token.hash}", timeout: LEASE_TIMEOUT)
.try_obtain
end
end
--
cgit v1.2.1
From 12984a73029408ef4ca10446131613e9ac371eb9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?=
Date: Fri, 5 Jan 2018 17:48:40 +0100
Subject: Move worker to gcp_project namespace
---
app/workers/all_queues.yml | 2 +-
app/workers/check_gcp_project_billing_worker.rb | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 142e33e8325..5da0de89d12 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -22,6 +22,7 @@
- gcp_cluster:cluster_provision
- gcp_cluster:cluster_wait_for_app_installation
- gcp_cluster:wait_for_cluster_creation
+- gcp_cluster:check_gcp_project_billing
- github_import_advance_stage
- github_importer:github_import_import_diff_note
@@ -97,4 +98,3 @@
- update_user_activity
- upload_checksum
- web_hook
-- check_gcp_project_billing
diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb
index 24575f84509..42aa6b39d86 100644
--- a/app/workers/check_gcp_project_billing_worker.rb
+++ b/app/workers/check_gcp_project_billing_worker.rb
@@ -1,5 +1,6 @@
class CheckGcpProjectBillingWorker
include ApplicationWorker
+ include ClusterQueue
LEASE_TIMEOUT = 15.seconds.to_i
--
cgit v1.2.1
From 33c5630b02a783a749cc0bf63474f643652cdeeb Mon Sep 17 00:00:00 2001
From: "Lin Jen-Shin (godfat)"
Date: Fri, 5 Jan 2018 16:52:06 +0000
Subject: Use --left-right and --max-count for counting diverging commits
---
app/helpers/branches_helper.rb | 8 +++
app/models/repository.rb | 12 ++--
app/views/projects/branches/_branch.html.haml | 8 +--
.../40622-use-left-right-and-max-count.yml | 6 ++
lib/gitlab/git/repository.rb | 75 ++++++++++++++++++++--
spec/lib/gitlab/git/repository_spec.rb | 40 +++++++++++-
spec/models/repository_spec.rb | 9 +++
7 files changed, 141 insertions(+), 17 deletions(-)
create mode 100644 changelogs/unreleased/40622-use-left-right-and-max-count.yml
diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb
index 686437fc99a..2641a98e29e 100644
--- a/app/helpers/branches_helper.rb
+++ b/app/helpers/branches_helper.rb
@@ -23,4 +23,12 @@ module BranchesHelper
def protected_branch?(project, branch)
ProtectedBranch.protected?(project, branch.name)
end
+
+ def diverging_count_label(count)
+ if count >= Repository::MAX_DIVERGING_COUNT
+ "#{Repository::MAX_DIVERGING_COUNT - 1}+"
+ else
+ count.to_s
+ end
+ end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 4bedcbfb6a2..7b8f5794a87 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -4,6 +4,7 @@ class Repository
REF_MERGE_REQUEST = 'merge-requests'.freeze
REF_KEEP_AROUND = 'keep-around'.freeze
REF_ENVIRONMENTS = 'environments'.freeze
+ MAX_DIVERGING_COUNT = 1000
RESERVED_REFS_NAMES = %W[
heads
@@ -278,11 +279,12 @@ class Repository
cache.fetch(:"diverging_commit_counts_#{branch.name}") do
# Rugged seems to throw a `ReferenceError` when given branch_names rather
# than SHA-1 hashes
- number_commits_behind = raw_repository
- .count_commits_between(branch.dereferenced_target.sha, root_ref_hash)
-
- number_commits_ahead = raw_repository
- .count_commits_between(root_ref_hash, branch.dereferenced_target.sha)
+ number_commits_behind, number_commits_ahead =
+ raw_repository.count_commits_between(
+ root_ref_hash,
+ branch.dereferenced_target.sha,
+ left_right: true,
+ max_count: MAX_DIVERGING_COUNT)
{ behind: number_commits_behind, ahead: number_commits_ahead }
end
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index acf67b83890..1da0e865a41 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -66,16 +66,16 @@
= icon("trash-o")
- if branch.name != @repository.root_ref
- .divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: number_commits_behind,
+ .divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: diverging_count_label(number_commits_behind),
default_branch: @repository.root_ref,
- number_commits_ahead: number_commits_ahead } }
+ number_commits_ahead: diverging_count_label(number_commits_ahead) } }
.graph-side
.bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" }
- %span.count.count-behind= number_commits_behind
+ %span.count.count-behind= diverging_count_label(number_commits_behind)
.graph-separator
.graph-side
.bar.bar-ahead{ style: "width: #{number_commits_ahead * bar_graph_width_factor}%" }
- %span.count.count-ahead= number_commits_ahead
+ %span.count.count-ahead= diverging_count_label(number_commits_ahead)
- if commit
diff --git a/changelogs/unreleased/40622-use-left-right-and-max-count.yml b/changelogs/unreleased/40622-use-left-right-and-max-count.yml
new file mode 100644
index 00000000000..c4c8f271cbe
--- /dev/null
+++ b/changelogs/unreleased/40622-use-left-right-and-max-count.yml
@@ -0,0 +1,6 @@
+---
+title: Improve the performance for counting diverging commits. Show 999+
+ if it is more than 1000 commits
+merge_request: 15963
+author:
+type: performance
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 17c05c44d7e..e8b1788e140 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -498,11 +498,13 @@ module Gitlab
end
def count_commits(options)
+ count_commits_options = process_count_commits_options(options)
+
gitaly_migrate(:count_commits) do |is_enabled|
if is_enabled
- count_commits_by_gitaly(options)
+ count_commits_by_gitaly(count_commits_options)
else
- count_commits_by_shelling_out(options)
+ count_commits_by_shelling_out(count_commits_options)
end
end
end
@@ -540,8 +542,8 @@ module Gitlab
end
# Counts the amount of commits between `from` and `to`.
- def count_commits_between(from, to)
- count_commits(ref: "#{from}..#{to}")
+ def count_commits_between(from, to, options = {})
+ count_commits(from: from, to: to, **options)
end
# Returns the SHA of the most recent common ancestor of +from+ and +to+
@@ -1468,6 +1470,26 @@ module Gitlab
end
end
+ def process_count_commits_options(options)
+ if options[:from] || options[:to]
+ ref =
+ if options[:left_right] # Compare with merge-base for left-right
+ "#{options[:from]}...#{options[:to]}"
+ else
+ "#{options[:from]}..#{options[:to]}"
+ end
+
+ options.merge(ref: ref)
+
+ elsif options[:ref] && options[:left_right]
+ from, to = options[:ref].match(/\A([^\.]*)\.{2,3}([^\.]*)\z/)[1..2]
+
+ options.merge(from: from, to: to)
+ else
+ options
+ end
+ end
+
def log_using_shell?(options)
options[:path].present? ||
options[:disable_walk] ||
@@ -1690,20 +1712,59 @@ module Gitlab
end
def count_commits_by_gitaly(options)
- gitaly_commit_client.commit_count(options[:ref], options)
+ if options[:left_right]
+ from = options[:from]
+ to = options[:to]
+
+ right_count = gitaly_commit_client
+ .commit_count("#{from}..#{to}", options)
+ left_count = gitaly_commit_client
+ .commit_count("#{to}..#{from}", options)
+
+ [left_count, right_count]
+ else
+ gitaly_commit_client.commit_count(options[:ref], options)
+ end
end
def count_commits_by_shelling_out(options)
+ cmd = count_commits_shelling_command(options)
+
+ raw_output = IO.popen(cmd) { |io| io.read }
+
+ process_count_commits_raw_output(raw_output, options)
+ end
+
+ def count_commits_shelling_command(options)
cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} rev-list]
cmd << "--after=#{options[:after].iso8601}" if options[:after]
cmd << "--before=#{options[:before].iso8601}" if options[:before]
cmd << "--max-count=#{options[:max_count]}" if options[:max_count]
+ cmd << "--left-right" if options[:left_right]
cmd += %W[--count #{options[:ref]}]
cmd += %W[-- #{options[:path]}] if options[:path].present?
+ cmd
+ end
- raw_output = IO.popen(cmd) { |io| io.read }
+ def process_count_commits_raw_output(raw_output, options)
+ if options[:left_right]
+ result = raw_output.scan(/\d+/).map(&:to_i)
+
+ if result.sum != options[:max_count]
+ result
+ else # Reaching max count, right is not accurate
+ right_option =
+ process_count_commits_options(options
+ .except(:left_right, :from, :to)
+ .merge(ref: options[:to]))
+
+ right = count_commits_by_shelling_out(right_option)
- raw_output.to_i
+ [result.first, right] # left should be accurate in the first call
+ end
+ else
+ raw_output.to_i
+ end
end
def gitaly_ls_files(ref)
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index faccc2c8e00..f94234f6010 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1030,12 +1030,50 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ context 'with max_count' do
+ it 'returns the number of commits with path ' do
+ options = { ref: 'master', max_count: 5 }
+
+ expect(repository.count_commits(options)).to eq(5)
+ end
+ end
+
context 'with path' do
it 'returns the number of commits with path ' do
- options = { ref: 'master', path: "encoding" }
+ options = { ref: 'master', path: 'encoding' }
+
+ expect(repository.count_commits(options)).to eq(2)
+ end
+ end
+
+ context 'with option :from and option :to' do
+ it 'returns the number of commits ahead for fix-mode..fix-blob-path' do
+ options = { from: 'fix-mode', to: 'fix-blob-path' }
expect(repository.count_commits(options)).to eq(2)
end
+
+ it 'returns the number of commits ahead for fix-blob-path..fix-mode' do
+ options = { from: 'fix-blob-path', to: 'fix-mode' }
+
+ expect(repository.count_commits(options)).to eq(1)
+ end
+
+ context 'with option :left_right' do
+ it 'returns the number of commits for fix-mode...fix-blob-path' do
+ options = { from: 'fix-mode', to: 'fix-blob-path', left_right: true }
+
+ expect(repository.count_commits(options)).to eq([1, 2])
+ end
+
+ context 'with max_count' do
+ it 'returns the number of commits with path ' do
+ options = { from: 'fix-mode', to: 'fix-blob-path', left_right: true, max_count: 1 }
+
+ expect(repository.count_commits(options)).to eq([1, 1])
+ end
+ end
+ end
end
context 'with max_count' do
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 9a68ae086ea..48a75c9885b 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -2215,6 +2215,15 @@ describe Repository do
end
end
+ describe '#diverging_commit_counts' do
+ it 'returns the commit counts behind and ahead of default branch' do
+ result = repository.diverging_commit_counts(
+ repository.find_branch('fix'))
+
+ expect(result).to eq(behind: 29, ahead: 2)
+ end
+ end
+
describe '#cache_method_output', :use_clean_rails_memory_store_caching do
let(:fallback) { 10 }
--
cgit v1.2.1
From b7053244a7e21da4177c8550a92b0f66affd5cde Mon Sep 17 00:00:00 2001
From: Douwe Maan
Date: Fri, 5 Jan 2018 13:29:05 +0000
Subject: Merge branch 'master-i18n' into 'master'
New Crowdin translations
See merge request gitlab-org/gitlab-ee!3930
---
locale/bg/gitlab.po | 573 +++++++++++++++++++++++++++--
locale/de/gitlab.po | 573 +++++++++++++++++++++++++++--
locale/eo/gitlab.po | 561 ++++++++++++++++++++++++++--
locale/es/gitlab.po | 561 ++++++++++++++++++++++++++--
locale/fr/gitlab.po | 613 +++++++++++++++++++++++++++---
locale/it/gitlab.po | 981 +++++++++++++++++++++++++++++++++++++------------
locale/ja/gitlab.po | 560 ++++++++++++++++++++++++++--
locale/ko/gitlab.po | 560 ++++++++++++++++++++++++++--
locale/nl_NL/gitlab.po | 565 ++++++++++++++++++++++++++--
locale/pl_PL/gitlab.po | 562 ++++++++++++++++++++++++++--
locale/pt_BR/gitlab.po | 685 +++++++++++++++++++++++++++++-----
locale/ru/gitlab.po | 712 +++++++++++++++++++++++++++++------
locale/uk/gitlab.po | 780 ++++++++++++++++++++++++++++++++-------
locale/zh_CN/gitlab.po | 632 +++++++++++++++++++++++++++----
locale/zh_HK/gitlab.po | 560 ++++++++++++++++++++++++++--
locale/zh_TW/gitlab.po | 722 ++++++++++++++++++++++++++++++------
16 files changed, 9141 insertions(+), 1059 deletions(-)
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index 374164cbe65..8432914d6a7 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-03 12:29-0400\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:42-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Bulgarian\n"
"Language: bg_BG\n"
@@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts
msgstr[0] ""
msgstr[1] ""
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr ""
@@ -115,9 +118,6 @@ msgstr ""
msgid "Add License"
msgstr "Добавяне на лиценз"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "Добавете SSH ключ в профила си, за да можете да изтегляте или изпращате промени чрез SSH."
-
msgid "Add new directory"
msgstr "Добавяне на нова папка"
@@ -130,6 +130,15 @@ msgstr ""
msgid "All"
msgstr ""
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -139,6 +148,12 @@ msgstr ""
msgid "Applications"
msgstr ""
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Архивиран проект! Хранилището е само за четене"
@@ -166,6 +181,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Прикачете файл чрез влачене и пускане или %{upload_link}"
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -199,6 +220,9 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -256,7 +280,7 @@ msgstr ""
msgid "Branch"
msgid_plural "Branches"
msgstr[0] "Клон"
-msgstr[1] "Клонове"
+msgstr[1] "Клони"
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "Клонът %{branch_name} беше създаден. За да настроите автоматичното внедряване, изберете Yaml шаблон за GitLab CI и подайте промените си. %{link_to_autodeploy_doc}"
@@ -264,14 +288,20 @@ msgstr "Клонът %{branch_name} беше създаден.
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
-msgstr "Търсете в клоновете"
+msgstr "Търсете в клоните"
msgid "BranchSwitcherTitle|Switch branch"
msgstr "Превключване на клона"
msgid "Branches"
-msgstr "Клонове"
+msgstr "Клони"
msgid "Branches|Cant find HEAD commit for this branch"
msgstr ""
@@ -411,6 +441,12 @@ msgstr "Графики"
msgid "Chat"
msgstr ""
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Подбиране на това подаване"
@@ -486,7 +522,40 @@ msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -510,21 +579,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -534,27 +636,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -567,7 +717,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -582,15 +738,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -606,9 +780,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -623,11 +803,6 @@ msgid_plural "Commits"
msgstr[0] "Подаване"
msgstr[1] "Подавания"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Commit Message"
msgstr ""
@@ -709,6 +884,15 @@ msgstr "Ръководство за сътрудничество"
msgid "Contributors"
msgstr "Сътрудници"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -736,6 +920,9 @@ msgstr "Създаване на папка"
msgid "Create empty bare repository"
msgstr "Създаване на празно хранилище"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -763,6 +950,9 @@ msgstr "Етикет"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "си създадете личен жетон за достъп"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Часова зона за „Cron“"
@@ -808,6 +998,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Задайте потребителски шаблон, използвайки синтаксиса на „Cron“"
@@ -882,6 +1078,72 @@ msgstr "Редактиране на плана %{id} за схема"
msgid "Emails"
msgstr ""
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -921,6 +1183,12 @@ msgstr "Собственикът не може да бъде променен"
msgid "Failed to remove the pipeline schedule"
msgstr "Планът за схема не може да бъде премахнат"
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -968,6 +1236,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1031,9 +1314,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1064,6 +1344,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -1123,9 +1406,6 @@ msgstr "Представяме Ви анализа на циклите"
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr ""
@@ -1138,6 +1418,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Изключено"
@@ -1211,9 +1509,18 @@ msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "Медиана"
@@ -1258,9 +1565,15 @@ msgstr "Нов план за схема"
msgid "New branch"
msgstr "Нов клон"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "Нова папка"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "Нов файл"
@@ -1297,6 +1610,9 @@ msgstr "Няма хранилище"
msgid "No schedules"
msgstr "Няма планове"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1363,18 +1679,33 @@ msgstr "Наблюдение"
msgid "Notifications"
msgstr ""
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Филтър"
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Отворен"
@@ -1507,6 +1838,9 @@ msgstr "с етап"
msgid "Pipeline|with stages"
msgstr "с етапи"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1612,9 +1946,15 @@ msgstr "Графика"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1651,6 +1991,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1673,7 +2046,7 @@ msgid "Readme"
msgstr "ПрочетиМе"
msgid "RefSwitcher|Branches"
-msgstr "Клонове"
+msgstr "Клони"
msgid "RefSwitcher|Tags"
msgstr "Етикети"
@@ -1747,8 +2120,11 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr "Планиране на схемите"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
-msgstr "Търсете в клоновете и етикетите"
+msgstr "Търсете в клоните и етикетите"
msgid "Seconds before reseting failure information"
msgstr ""
@@ -1768,6 +2144,12 @@ msgstr "Изберете часова зона"
msgid "Select target branch"
msgstr "Изберете целеви клон"
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events"
msgstr[0] "Показване на %d събитие"
msgstr[1] "Показване на %d събития"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1914,9 +2311,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr "Изходен код"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1935,6 +2338,9 @@ msgstr "Създайте %{new_merge_request} с тези промени"
msgid "Start the Runner!"
msgstr ""
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1955,6 +2361,75 @@ msgstr[1] "Етикети"
msgid "Tags"
msgstr "Етикети"
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "Целеви клон"
@@ -1995,7 +2470,7 @@ msgid "The phase of the development lifecycle."
msgstr "Етапът от цикъла на разработка"
msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
-msgstr "Планът за схемата ще изпълнява схемите в бъдеще, периодично, за определени клонове или етикети. Тези планирани схеми ще наследят ограниченията на достъпа до проекта на свързания с тях потребител."
+msgstr "Планът за схемата ще изпълнява схемите в бъдеще, периодично, за определени клони или етикети. Тези планирани схеми ще наследят ограниченията на достъпа до проекта на свързания с тях потребител."
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr "Етапът на планиране показва колко е времето от преходната стъпка до изпращането на първото подаване. Това време ще бъде добавено автоматично след като изпратите първото си подаване."
@@ -2036,6 +2511,9 @@ msgstr "Стойността, която се намира в средата н
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2057,6 +2535,9 @@ msgstr "Това означава, че няма да можете да изпр
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Време преди един проблем да бъде планиран за работа"
@@ -2205,15 +2686,27 @@ msgstr[1] "мин"
msgid "Time|s"
msgstr "сек"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "Общо време"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "Общо време за тестване на всички подавания/сливания"
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2250,6 +2743,9 @@ msgstr "Качване на файл"
msgid "UploadLink|click to upload"
msgstr "щракнете за качване"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr ""
@@ -2283,6 +2779,9 @@ msgstr "Искате ли да видите данните? Помолете а
msgid "We don't have enough data to show this stage."
msgstr "Няма достатъчно данни за този етап."
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2412,12 +2911,6 @@ msgstr "На път сте да премахнете връзката на ра
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "На път сте да прехвърлите „%{project_name_with_namespace}“ към друг собственик. НАИСТИНА ли искате това?"
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr "Можете да добавяте файлове само когато се намирате в клон"
@@ -2457,6 +2950,9 @@ msgstr "Няма да можете да изтегляте или изпраща
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "Няма да можете да изтегляте или изпращате код в проекта чрез SSH, докато не %{add_ssh_key_link} в профила си"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2469,6 +2965,12 @@ msgstr "Вашето име"
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2494,6 +2996,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index a79a7d1a353..db7f41c5476 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-28 11:32-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:41-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: German\n"
"Language: de_DE\n"
@@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts
msgstr[0] "%{storage_name}: fehlgeschlagener Speicherzugriff auf Host:"
msgstr[1] "%{storage_name}: %{failed_attempts} fehlgeschlagene Speicherzugriffe:"
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(beachte die Informationen zur Installation auf %{link})."
@@ -115,9 +118,6 @@ msgstr ""
msgid "Add License"
msgstr "Lizenz hinzufügen"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-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 "Erstelle eine neues Verzeichnis"
@@ -130,6 +130,15 @@ msgstr ""
msgid "All"
msgstr "Alle"
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -139,6 +148,12 @@ msgstr ""
msgid "Applications"
msgstr "Anwendungen"
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Archiviertes Projekt! Repository ist nicht änderbar."
@@ -166,6 +181,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Datei mittels Drag & Drop oder %{upload_link} hinzufügen"
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -199,8 +220,11 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
-msgstr "Abrechnung"
+msgstr ""
msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
msgstr ""
@@ -264,6 +288,12 @@ msgstr "Branch %{branch_name} wurde erstellt. Um die automatisc
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Branches durchsuchen"
@@ -411,6 +441,12 @@ msgstr "Diagramme"
msgid "Chat"
msgstr "Chat"
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Diesen Commit herauspicken "
@@ -481,12 +517,45 @@ msgid "Clone repository"
msgstr ""
msgid "Close"
-msgstr "Schließen"
+msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -510,21 +579,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -534,27 +636,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -567,7 +717,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -582,15 +738,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -606,9 +780,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -623,11 +803,6 @@ msgid_plural "Commits"
msgstr[0] "Commit"
msgstr[1] "Commits"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Commit Message"
msgstr ""
@@ -709,6 +884,15 @@ msgstr "Mitarbeitsanleitung"
msgid "Contributors"
msgstr "Mitarbeiter"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -716,7 +900,7 @@ msgid "Control the maximum concurrency of repository backfill for this secondary
msgstr ""
msgid "Copy SSH public key to clipboard"
-msgstr "Öffentlichen SSH-Schlüssel in die Zwischenablage kopieren"
+msgstr ""
msgid "Copy URL to clipboard"
msgstr "Kopiere URL in die Zwischenablage"
@@ -736,6 +920,9 @@ msgstr "Erstelle Verzeichnis"
msgid "Create empty bare repository"
msgstr "Erstelle leeres Repository"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -763,6 +950,9 @@ msgstr "Tag "
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Erstelle einen persönlichen Zugriffstoken"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Cron Zeitzone"
@@ -808,6 +998,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Erstelle ein individuelles Muster mittels Cron Syntax"
@@ -882,6 +1078,72 @@ msgstr "Pipeline Zeitplan bearbeiten %{id}"
msgid "Emails"
msgstr "E-Mails"
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "Filtere alle"
@@ -921,6 +1183,12 @@ msgstr "Wechsel des Besitzers fehlgeschlagen"
msgid "Failed to remove the pipeline schedule"
msgstr "Entfernung der Pipelineplanung fehlgeschlagen"
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -968,6 +1236,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1031,9 +1314,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1064,6 +1344,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr "Systemzustand"
@@ -1123,9 +1406,6 @@ msgstr "Arbeitsablaufsanalysen vorgestellt"
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr "Ticketereignisse"
@@ -1138,6 +1418,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Deaktiviert"
@@ -1192,7 +1490,7 @@ msgid "Leave project"
msgstr "Verlasse das Projekt"
msgid "License"
-msgstr "Lizenz"
+msgstr ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
@@ -1206,14 +1504,23 @@ msgid "Locked"
msgstr ""
msgid "Locked Files"
-msgstr "Gesperrte Dateien"
+msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "Median"
@@ -1258,9 +1565,15 @@ msgstr "Neuer Pipeline Zeitplan"
msgid "New branch"
msgstr "Neuer Branch"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "Neues Verzeichnis"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "Neue Datei"
@@ -1297,6 +1610,9 @@ msgstr "Kein Repository"
msgid "No schedules"
msgstr "Keine Zeitpläne"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1363,18 +1679,33 @@ msgstr "Beobachten"
msgid "Notifications"
msgstr "Benachrichtigungen"
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filter"
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Ungelöst"
@@ -1507,6 +1838,9 @@ msgstr "mit Stage"
msgid "Pipeline|with stages"
msgstr "mit Stages"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1612,9 +1946,15 @@ msgstr "Diagramm"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1651,6 +1991,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1747,6 +2120,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr "Pipelines planen"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "Suche nach Branches und Tags"
@@ -1768,6 +2144,12 @@ msgstr "Zeitzone auswählen"
msgid "Select target branch"
msgstr "Zielbranch auswählen"
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events"
msgstr[0] "Zeige %d Ereignis"
msgstr[1] "Zeige %d Ereignisse"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1914,9 +2311,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr "Quellcode"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr "Spam-Protokolle"
@@ -1935,6 +2338,9 @@ msgstr "Beginne einen %{new_merge_request} mit diesen Änderungen"
msgid "Start the Runner!"
msgstr "Starte den Runner!"
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1955,6 +2361,75 @@ msgstr[1] ""
msgid "Tags"
msgstr ""
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "Zielbranch"
@@ -2036,6 +2511,9 @@ msgstr "Der mittlere aller erfassten Werte. Zum Beispiel ist für 3, 5, 9 der Me
msgid "There are problems accessing Git storage: "
msgstr "Es gibt ein Problem beim Zugriff auf den Gitspeicher:"
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2057,6 +2535,9 @@ msgstr "Dies bedeutet, dass Du keinen Code übertragen kannst, bevor Du kein lee
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Zeit bis ein Ticket geplant wird"
@@ -2205,15 +2686,27 @@ msgstr[1] "Min."
msgid "Time|s"
msgstr "Sek."
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "Gesamtzeit"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "Gesamte Testzeit für alle Commits/Merges"
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2250,6 +2743,9 @@ msgstr "Eine Datei hochladen"
msgid "UploadLink|click to upload"
msgstr "Zum Upload klicken"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr "Benutze den folgenden Registrierungstoken während des Setups:"
@@ -2283,6 +2779,9 @@ msgstr "Du möchtest diese Daten sehen? Bitte frage einen Administrator nach dem
msgid "We don't have enough data to show this stage."
msgstr "Es liegen nicht genügend Daten vor, um diese Phase anzuzeigen."
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2412,12 +2911,6 @@ msgstr "Du bist dabei, die Beziehung des Ablegers zum Ursprungsprojekt %{forked_
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Du bist dabei %{project_name_with_namespace} einem andere Besitzer zu übergeben. Bist Du dir WIRKLICH sicher?"
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr "Du kannst Dateien nur hinzufügen, wenn Du dich auf einem Branch befindest."
@@ -2457,6 +2950,9 @@ msgstr "Du kannst erst mittels '%{protocol}' übertragen (push) oder abrufen (pu
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "Du kannst erst mittels SSH übertragen (push) oder abrufen (pull), nachdem Du Deinem Konto '%{add_ssh_key_link}'."
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2469,8 +2965,14 @@ msgstr "Dein Name"
msgid "Your projects"
msgstr "Deine Projekte"
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
-msgstr "Commit"
+msgstr ""
msgid "day"
msgid_plural "days"
@@ -2494,6 +2996,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index f7be343c4e1..be7cfa6e4b5 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-03 12:30-0400\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:42-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Esperanto\n"
"Language: eo_UY\n"
@@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts
msgstr[0] ""
msgstr[1] ""
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr ""
@@ -115,9 +118,6 @@ msgstr ""
msgid "Add License"
msgstr "Aldoni rajtigilon"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "Aldonu SSH-ŝlosilon al via profilo por ebligi al vi eltiri kaj alpuŝi per SSH."
-
msgid "Add new directory"
msgstr "Aldoni novan dosierujon"
@@ -130,6 +130,15 @@ msgstr ""
msgid "All"
msgstr ""
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -139,6 +148,12 @@ msgstr ""
msgid "Applications"
msgstr ""
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "Arkivita projekto! La deponejo permesas nur legadon"
@@ -166,6 +181,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Alkroĉu dosieron per ŝovmetado aŭ %{upload_link}"
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -199,6 +220,9 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -264,6 +288,12 @@ msgstr "La branĉo %{branch_name} estis kreita. Por agordi aŭt
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Serĉu branĉon"
@@ -411,6 +441,12 @@ msgstr "Diagramoj"
msgid "Chat"
msgstr ""
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Precize elekti ĉi tiun kunmetadon"
@@ -486,7 +522,40 @@ msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -510,21 +579,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -534,27 +636,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -567,7 +717,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -582,15 +738,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -606,9 +780,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -623,11 +803,6 @@ msgid_plural "Commits"
msgstr[0] "Enmetado"
msgstr[1] "Enmetadoj"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Commit Message"
msgstr ""
@@ -709,6 +884,15 @@ msgstr "Gvidlinioj por kontribuado"
msgid "Contributors"
msgstr "Kontribuantoj"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -736,6 +920,9 @@ msgstr "Krei dosierujon"
msgid "Create empty bare repository"
msgstr "Krei malplenan deponejon"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -763,6 +950,9 @@ msgstr "Etikedo"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "kreos propran atingoĵetonon"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Horzono por Cron"
@@ -808,6 +998,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Difini propran ŝablonon, uzante la sintakson de Cron"
@@ -882,6 +1078,72 @@ msgstr "Redakti ĉenstablan planon %{id}"
msgid "Emails"
msgstr ""
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -921,6 +1183,12 @@ msgstr "Ne eblas ŝanĝi la posedanton"
msgid "Failed to remove the pipeline schedule"
msgstr "Ne eblas forigi la ĉenstablan planon"
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -968,6 +1236,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1031,9 +1314,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1064,6 +1344,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -1123,9 +1406,6 @@ msgstr "Ni prezentas al vi la ciklan analizon"
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr ""
@@ -1138,6 +1418,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Malŝaltita"
@@ -1211,9 +1509,18 @@ msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "Mediano"
@@ -1258,9 +1565,15 @@ msgstr "Nova ĉenstabla plano"
msgid "New branch"
msgstr "Nova branĉo"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "Nova dosierujo"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "Nova dosiero"
@@ -1297,6 +1610,9 @@ msgstr "Ne estas deponejo"
msgid "No schedules"
msgstr "Ne estas planoj"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1363,18 +1679,33 @@ msgstr "Rigardado"
msgid "Notifications"
msgstr ""
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtrilo"
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Malfermita"
@@ -1507,6 +1838,9 @@ msgstr "kun etapo"
msgid "Pipeline|with stages"
msgstr "kun etapoj"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1612,9 +1946,15 @@ msgstr "Grafeo"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1651,6 +1991,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1747,6 +2120,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr "Planado de la ĉenstabloj"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "Serĉu branĉon aŭ etikedon"
@@ -1768,6 +2144,12 @@ msgstr "Elektu horzonon"
msgid "Select target branch"
msgstr "Elektu celan branĉon"
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events"
msgstr[0] "Estas montrata %d evento"
msgstr[1] "Estas montrataj %d eventoj"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1914,9 +2311,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr "Kodo"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1935,6 +2338,9 @@ msgstr "Kreu %{new_merge_request} kun ĉi tiuj ŝanĝoj"
msgid "Start the Runner!"
msgstr ""
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1955,6 +2361,75 @@ msgstr[1] "Etikedoj"
msgid "Tags"
msgstr "Etikedoj"
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "Cela branĉo"
@@ -2036,6 +2511,9 @@ msgstr "La valoro, kiu troviĝas en la mezo de aro da rigardataj valoroj. Ekzemp
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2057,6 +2535,9 @@ msgstr "Ĉi tiu signifas, ke vi ne povos alpuŝi kodon, antaŭ ol vi kreos malpl
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Tempo antaŭ problemo estas planita por ellabori"
@@ -2205,15 +2686,27 @@ msgstr[1] "min"
msgid "Time|s"
msgstr "s"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "Totala tempo"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "Totala tempo por la testado de ĉiuj enmetadoj/kunfandoj"
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2250,6 +2743,9 @@ msgstr "Alŝuti dosieron"
msgid "UploadLink|click to upload"
msgstr "alklaku por alŝuti"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr ""
@@ -2283,6 +2779,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 "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2412,12 +2911,6 @@ msgstr "Vi forigos la rilaton de la disbranĉigo al la originala projekto, „%{
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Vi estas transigonta „%{project_name_with_namespace}“ al alia posedanto. Ĉu vi estas ABSOLUTE certa?"
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr "Oni povas aldoni dosierojn nur kiam oni estas en branĉo"
@@ -2457,6 +2950,9 @@ msgstr "Vi ne povos eltiri aŭ alpuŝi kodon per %{protocol} antaŭ ol vi %{set_
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "Vi ne povos eltiri aŭ alpuŝi kodon per SSH antaŭ ol vi %{add_ssh_key_link} al via profilo"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2469,6 +2965,12 @@ msgstr "Via nomo"
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2494,6 +2996,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index c35a3503019..44ad3d4633a 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-03 12:31-0400\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:41-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Spanish\n"
"Language: es_ES\n"
@@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts
msgstr[0] ""
msgstr[1] ""
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr ""
@@ -115,9 +118,6 @@ msgstr ""
msgid "Add License"
msgstr "Agregar Licencia"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "Agregar una clave SSH a tu perfil para actualizar o enviar a través de SSH."
-
msgid "Add new directory"
msgstr "Agregar nuevo directorio"
@@ -130,6 +130,15 @@ msgstr ""
msgid "All"
msgstr ""
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -139,6 +148,12 @@ msgstr ""
msgid "Applications"
msgstr ""
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "¡Proyecto archivado! El repositorio es de solo lectura"
@@ -166,6 +181,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Adjunte un archivo arrastrando & soltando o %{upload_link}"
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -199,6 +220,9 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -264,6 +288,12 @@ msgstr "La rama %{branch_name} fue creada. Para configurar el a
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Buscar ramas"
@@ -411,6 +441,12 @@ msgstr "Gráficos"
msgid "Chat"
msgstr ""
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Escoger este cambio"
@@ -486,7 +522,40 @@ msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -510,21 +579,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -534,27 +636,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -567,7 +717,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -582,15 +738,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -606,9 +780,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -623,11 +803,6 @@ msgid_plural "Commits"
msgstr[0] "Cambio"
msgstr[1] "Cambios"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Commit Message"
msgstr ""
@@ -709,6 +884,15 @@ msgstr "Guía de contribución"
msgid "Contributors"
msgstr "Contribuidores"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -736,6 +920,9 @@ msgstr "Crear directorio"
msgid "Create empty bare repository"
msgstr "Crear repositorio vacío"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -763,6 +950,9 @@ msgstr "Etiqueta"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "crear un token de acceso personal"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Zona horaria del Cron"
@@ -808,6 +998,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Definir un patrón personalizado con la sintaxis de cron"
@@ -882,6 +1078,72 @@ msgstr "Editar Programación del Pipeline %{id}"
msgid "Emails"
msgstr ""
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -921,6 +1183,12 @@ msgstr "Error al cambiar el propietario"
msgid "Failed to remove the pipeline schedule"
msgstr "Error al eliminar la programación del pipeline"
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -968,6 +1236,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1031,9 +1314,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1064,6 +1344,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -1123,9 +1406,6 @@ msgstr "Introducción a Cycle Analytics"
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr ""
@@ -1138,6 +1418,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Deshabilitado"
@@ -1211,9 +1509,18 @@ msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "Mediana"
@@ -1258,9 +1565,15 @@ msgstr "Nueva Programación del Pipeline"
msgid "New branch"
msgstr "Nueva rama"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "Nuevo directorio"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "Nuevo archivo"
@@ -1297,6 +1610,9 @@ msgstr "No hay repositorio"
msgid "No schedules"
msgstr "No hay programaciones"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1363,18 +1679,33 @@ msgstr "Vigilancia"
msgid "Notifications"
msgstr ""
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtrar"
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Abierto"
@@ -1507,6 +1838,9 @@ msgstr "con etapa"
msgid "Pipeline|with stages"
msgstr "con etapas"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1612,9 +1946,15 @@ msgstr "Historial gráfico"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1651,6 +1991,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1747,6 +2120,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr "Programación de Pipelines"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "Buscar ramas y etiquetas"
@@ -1768,6 +2144,12 @@ msgstr "Selecciona una zona horaria"
msgid "Select target branch"
msgstr "Selecciona una rama de destino"
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events"
msgstr[0] "Mostrando %d evento"
msgstr[1] "Mostrando %d eventos"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1914,9 +2311,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr "Código fuente"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1935,6 +2338,9 @@ msgstr "Iniciar una %{new_merge_request} con estos cambios"
msgid "Start the Runner!"
msgstr ""
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1955,6 +2361,75 @@ msgstr[1] "Etiquetas"
msgid "Tags"
msgstr "Etiquetas"
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "Rama de destino"
@@ -2036,6 +2511,9 @@ msgstr "El valor en el punto medio de una serie de valores observados. Por ejemp
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2057,6 +2535,9 @@ msgstr "Esto significa que no puede enviar código hasta que cree un repositorio
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Tiempo antes de que una incidencia sea programada"
@@ -2205,15 +2686,27 @@ msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "Tiempo Total"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "Tiempo total de pruebas para todos los cambios o integraciones"
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2250,6 +2743,9 @@ msgstr "Subir archivo"
msgid "UploadLink|click to upload"
msgstr "Hacer clic para subir"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr ""
@@ -2283,6 +2779,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 "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2412,12 +2911,6 @@ msgstr "Vas a eliminar el enlace de la bifurcación con el proyecto original %{f
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Vas a transferir %{project_name_with_namespace} a otro propietario. ¿Estás TOTALMENTE seguro?"
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr "Solo puedes agregar archivos cuando estás en una rama"
@@ -2457,6 +2950,9 @@ msgstr "No podrás actualizar o enviar código al proyecto a través de %{protoc
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "No podrás actualizar o enviar código al proyecto a través de SSH hasta que %{add_ssh_key_link} en su perfil"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2469,6 +2965,12 @@ msgstr "Tu nombre"
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2494,6 +2996,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index a0e523339db..ace6a5d2f66 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-21 16:43-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:40-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: French\n"
"Language: fr_FR\n"
@@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts
msgstr[0] "%{storage_name} : la tentative d’accès au stockage a échouée sur l’hôte :"
msgstr[1] "%{storage_name} : %{failed_attempts} tentatives d’accès au stockage ont échouées :"
+msgid "%{text} is available"
+msgstr "%{text} est disponible"
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(Lisez %{link} pour savoir comment l'installer)."
@@ -115,9 +118,6 @@ msgstr "Ajouter des Webhooks de groupe et GitLab Enterprise Edition."
msgid "Add License"
msgstr "Ajouter une licence"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "Ajoutez une clef SSH à votre profil pour pouvoir récupérer et pousser par SSH."
-
msgid "Add new directory"
msgstr "Ajouter un nouveau dossier"
@@ -130,6 +130,15 @@ msgstr "Paramètres avancés"
msgid "All"
msgstr "Tous"
+msgid "An error occurred when toggling the notification subscription"
+msgstr "Une erreur s’est produite lors de l’activation/désactivation de l’abonnement aux notifications"
+
+msgid "An error occurred when updating the issue weight"
+msgstr "Une erreur s'est produite lors de la mise à jour du poids du ticket"
+
+msgid "An error occurred while fetching sidebar data"
+msgstr "Une erreur s'est produite lors de la récupération des données de la barre latérale"
+
msgid "An error occurred. Please try again."
msgstr "Une erreur est survenue. Merci de réessayer."
@@ -139,6 +148,12 @@ msgstr "Apparence"
msgid "Applications"
msgstr "Applications"
+msgid "Apr"
+msgstr "Avr."
+
+msgid "April"
+msgstr "Avril"
+
msgid "Archived project! Repository is read-only"
msgstr "Projet archivé ! Le dépôt est en lecture seule"
@@ -166,6 +181,12 @@ msgstr "Artéfacts"
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Attachez un fichier par glisser & déposer ou %{upload_link}"
+msgid "Aug"
+msgstr "Août"
+
+msgid "August"
+msgstr "Août"
+
msgid "Authentication Log"
msgstr "Journal d'authentification"
@@ -199,6 +220,9 @@ msgstr "En savoir plus dans %{link_to_documentation}"
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr "Vous pouvez activer %{link_to_settings} pour ce projet."
+msgid "Available"
+msgstr "Disponible"
+
msgid "Billing"
msgstr "Facturation"
@@ -218,7 +242,7 @@ msgid "BillingPlans|Downgrade"
msgstr "Retour à un forfait inférieur"
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
-msgstr "En savoir plus sur chaque abonnement en lisant nos %{faq_link}."
+msgstr "En savoir plus sur chaque forfait en lisant nos %{faq_link}."
msgid "BillingPlans|Manage plan"
msgstr "Gérer l'abonnement"
@@ -227,13 +251,13 @@ msgid "BillingPlans|Please contact %{customer_support_link} in that case."
msgstr "Merci de contacter %{customer_support_link} à ce sujet."
msgid "BillingPlans|See all %{plan_name} features"
-msgstr "Voir toutes les fonctionnalités de l’abonnement %{plan_name}"
+msgstr "Voir toutes les fonctionnalités du forfait %{plan_name}"
msgid "BillingPlans|This group uses the plan associated with its parent group."
-msgstr "Ce groupe utilise l’abonnement associé à son groupe parent."
+msgstr "Ce groupe utilise le forfait associé à son groupe parent."
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
-msgstr "Pour gérer le plan de ce groupe, visitez la section facturation de %{parent_billing_page_link}."
+msgstr "Pour gérer l‘abonnement de ce groupe, visitez la section facturation de %{parent_billing_page_link}."
msgid "BillingPlans|Upgrade"
msgstr "Mise à niveau"
@@ -242,13 +266,13 @@ msgid "BillingPlans|You are currently on the %{plan_link} plan."
msgstr "Vous êtes actuellement abonné·e au forfait %{plan_link}."
msgid "BillingPlans|frequently asked questions"
-msgstr "Foire aux questions"
+msgstr "foire aux questions"
msgid "BillingPlans|monthly"
-msgstr "Mensuellement"
+msgstr "mensuel"
msgid "BillingPlans|paid annually at %{price_per_year}"
-msgstr "au prix annuel de %{price_per_year}"
+msgstr "payé annuellement pour %{price_per_year}"
msgid "BillingPlans|per user"
msgstr "par utilisateur"
@@ -264,6 +288,12 @@ msgstr "La branche %{branch_name} a été créée. Pour mettre
msgid "Branch has changed"
msgstr "La branche a été modifiée"
+msgid "Branch is already taken"
+msgstr "Ce nom de branche existe déjà"
+
+msgid "Branch name"
+msgstr "Nom de la branche"
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Rechercher la branche"
@@ -411,6 +441,12 @@ msgstr "Statistiques"
msgid "Chat"
msgstr "Chat"
+msgid "Checking %{text} availability…"
+msgstr "Vérification de la disponibilité de %{text}…"
+
+msgid "Checking branch availability..."
+msgstr "Vérification de la disponibilité du nom de branche..."
+
msgid "Cherry-pick this commit"
msgstr "Picorer cette validation"
@@ -486,8 +522,41 @@ msgstr "Fermer"
msgid "Cluster"
msgstr "Cluster"
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
-msgstr "Un %{link_to_container_project} doit avoir été créé pour ce compte"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr "%{appList} a été installé avec succès sur votre cluster"
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr "%{boldNotice} Cela va ajouter des ressources supplémentaires comme un répartiteur de charge, qui engendrent des coûts supplémentaires. Voir %{pricingLink}"
+
+msgid "ClusterIntegration|API URL"
+msgstr "URL de l'API"
+
+msgid "ClusterIntegration|Active"
+msgstr "Actif"
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr "Ajouter un cluster existant"
+
+msgid "ClusterIntegration|Add cluster"
+msgstr "Ajoutez le cluster"
+
+msgid "ClusterIntegration|All"
+msgstr "Tous"
+
+msgid "ClusterIntegration|Applications"
+msgstr "Applications"
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr "Certificat d‘autorité de certification"
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr "Paquet de l‘Autorité de certification (format PEM)"
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr "Choisissez comment configurer l‘intégration de cluster"
+
+msgid "ClusterIntegration|Cluster"
+msgstr ""
msgid "ClusterIntegration|Cluster details"
msgstr "Détails du cluster"
@@ -505,56 +574,137 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab
msgstr "L'intégration de cluster est activée pour ce projet. La désactivation de cette intégration n’affectera pas votre cluster, il coupera temporairement la connexion de GitLab à celui-ci."
msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..."
-msgstr "Le cluster est en cours de création sur Google Kubernetes Engine…"
+msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr "Nom du cluster"
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
-msgstr "Le cluster a été correctement créé sur Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
+msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr "Copier le nom du cluster"
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr "Créer le cluster"
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
-msgstr "Créer un nouveau cluster sur Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr "Activer l’intégration du cluster"
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr "ID de projet Google Cloud Platform"
msgid "ClusterIntegration|Google Kubernetes Engine"
-msgstr "Google Kubernetes Engine"
+msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
-msgstr "Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "En savoir plus sur %{link_to_documentation}"
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr "Type de machine"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr "Assurez-vous que votre compte %{link_to_requirements} pour créer des clusters"
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
-msgstr "Gérer l’intégration du cluster sur votre projet GitLab"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
+msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr "Gérer votre cluster en visitant le lien %{link_gke}"
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Nombre de nœuds"
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr "Veuillez vous assurer que votre compte Google répond aux exigences suivantes : "
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr "Espace de noms du projet (facultatif, unique)"
@@ -567,8 +717,14 @@ msgstr "Retirer l’intégration du cluster"
msgid "ClusterIntegration|Remove integration"
msgstr "Retirer l’intégration"
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
-msgstr "Supprimer l'intégration du cluster supprimera sa configuration que vous avez ajoutée pour ce projet. Cela ne supprimera pas votre projet."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
+msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
msgstr "Voir et modifier les détails de votre cluster"
@@ -582,33 +738,57 @@ msgstr "Voir vos projets"
msgid "ClusterIntegration|See zones"
msgstr "Voir les zones"
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr "Un problème est survenu de notre côté."
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
-msgstr "Un problème est survenu lors de la création de votre cluster sur Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
msgid "ClusterIntegration|Toggle Cluster"
msgstr "Activer/désactiver le cluster"
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Avec un cluster associé à ce projet, vous pouvez utiliser des applications de revue, déployer vos applications, exécuter vos pipelines et bien plus encore, de manière très simple."
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
-msgstr "Votre compte doit disposer de %{link_to_kubernetes_engine}"
+msgstr ""
msgid "ClusterIntegration|Zone"
msgstr "Zone"
msgid "ClusterIntegration|access to Google Kubernetes Engine"
-msgstr "Accéder à Google Kubernetes Engine"
+msgstr ""
msgid "ClusterIntegration|cluster"
msgstr "cluster"
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr "page d’aide"
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr "répond aux exigences"
@@ -623,11 +803,6 @@ msgid_plural "Commits"
msgstr[0] "Validation"
msgstr[1] "Validations"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] "Valider %d fichier"
-msgstr[1] "Valider %d fichiers"
-
msgid "Commit Message"
msgstr "Message de validation"
@@ -709,11 +884,20 @@ msgstr "Guide de contribution"
msgid "Contributors"
msgstr "Contributeurs"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
-msgstr "Contrôler la concurrence maximale des remplacements de fichier-joint LFS pour ce nœud secondaire"
+msgstr ""
msgid "Control the maximum concurrency of repository backfill for this secondary node"
-msgstr "Contrôler la concurrence maximale des remplacements de dépôt pour ce nœud secondaire"
+msgstr ""
msgid "Copy SSH public key to clipboard"
msgstr "Copier la clé publique SSH dans le presse-papier"
@@ -736,6 +920,9 @@ msgstr "Créer un dossier"
msgid "Create empty bare repository"
msgstr "Créer un dépôt vide"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr "Créer un fichier"
@@ -763,6 +950,9 @@ msgstr "Tag"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Créer un jeton d'accès personnel"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Fuseau horaire de Cron"
@@ -808,6 +998,12 @@ msgstr "Tous"
msgid "DashboardProjects|Personal"
msgstr "Personnels"
+msgid "Dec"
+msgstr "Déc."
+
+msgid "December"
+msgstr "Décembre"
+
msgid "Define a custom pattern with cron syntax"
msgstr "Définir un schéma personnalisé avec une syntaxe Cron"
@@ -882,6 +1078,72 @@ msgstr "Éditer le pipeline programmé %{id}"
msgid "Emails"
msgstr "Courriels"
+msgid "Environments|An error occurred while fetching the environments."
+msgstr "Une erreur s‘est produite lors de la récupération des environnements."
+
+msgid "Environments|An error occurred while making the request."
+msgstr "Une erreur s’est produite lors de la requête."
+
+msgid "Environments|Commit"
+msgstr "Validation"
+
+msgid "Environments|Deployment"
+msgstr "Déploiement"
+
+msgid "Environments|Environment"
+msgstr "Environnement"
+
+msgid "Environments|Environments"
+msgstr "Environnements"
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr "Les environnements sont des lieux où le code est déployé, comme staging ou production."
+
+msgid "Environments|Job"
+msgstr "Tâche"
+
+msgid "Environments|New environment"
+msgstr "Nouvel environnement"
+
+msgid "Environments|No deployments yet"
+msgstr "Aucun déploiement pour le moment"
+
+msgid "Environments|Open"
+msgstr "Ouvert"
+
+msgid "Environments|Re-deploy"
+msgstr "Re-déployer"
+
+msgid "Environments|Read more about environments"
+msgstr "En savoir plus sur les environnements"
+
+msgid "Environments|Rollback"
+msgstr "Revenir en arrière"
+
+msgid "Environments|Show all"
+msgstr "Afficher tous"
+
+msgid "Environments|Updated"
+msgstr "Mise à jour"
+
+msgid "Environments|You don't have any environments right now."
+msgstr "Vous n’avez aucun environnement pour le moment."
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr "Une erreur s’est produite lors de l’activation/désactivation de l’abonnement aux notifications"
+
msgid "EventFilterBy|Filter by all"
msgstr "Aucun filtre"
@@ -921,6 +1183,12 @@ msgstr "Échec du changement de propriétaire"
msgid "Failed to remove the pipeline schedule"
msgstr "Échec de la suppression du pipeline programmé"
+msgid "Feb"
+msgstr "Févr."
+
+msgid "February"
+msgstr "Février"
+
msgid "File name"
msgstr "Nom du fichier"
@@ -968,6 +1236,21 @@ msgstr "Clés GPG"
msgid "Geo Nodes"
msgstr "Nœuds Geo"
+msgid "GeoNodeSyncStatus|Failed"
+msgstr "Échec"
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr "Le nœud est défaillant ou cassé."
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr "Le nœud est lent, surchargé, ou il vient juste de récupérer après un problème."
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr "Désynchronisé"
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr "Synchronisé"
+
msgid "Geo|File sync capacity"
msgstr "Capacité de synchronisation de fichier"
@@ -1031,9 +1314,6 @@ msgstr "Aucun groupe trouvé"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr "Vous pouvez gérer les autorisations des membres de votre groupe et accéder à chacun de ses projets."
-msgid "GroupsTreeRole|as"
-msgstr "comme"
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr "Êtes-vous sûr·e de vouloir quitter le groupe « ${this.group.fullName} » ?"
@@ -1064,6 +1344,9 @@ msgstr "Désolé, aucun groupe ne correspond à vos critères de recherche"
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr "Désolé, aucun groupe ni projet ne correspond à vos critères de recherche"
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr "État des services"
@@ -1092,7 +1375,7 @@ msgid "Import repository"
msgstr "Importer un dépôt"
msgid "Improve Issue boards with GitLab Enterprise Edition."
-msgstr "Améliorer le tableau de tickets avec GitLab Entreprise Edition."
+msgstr "Améliorer les tableaux de tickets avec Gitlab Entreprise Edition."
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
msgstr "Améliorer la gestion des tickets avec les poids de ticket et GitLab Entreprise Edition."
@@ -1123,9 +1406,6 @@ msgstr "Introduction à l'analyseur de cycle"
msgid "Issue board focus mode"
msgstr "Mode focus du tableau de tickets"
-msgid "Issue boards with milestones"
-msgstr "Tableaux des tickets avec leurs jalons"
-
msgid "Issue events"
msgstr "Événements du ticket"
@@ -1138,6 +1418,24 @@ msgstr "Tableaux"
msgid "Issues"
msgstr "Tickets"
+msgid "Jan"
+msgstr "Janv."
+
+msgid "January"
+msgstr "Janvier"
+
+msgid "Jul"
+msgstr "Juill."
+
+msgid "July"
+msgstr "Juillet"
+
+msgid "Jun"
+msgstr "Juin"
+
+msgid "June"
+msgstr "Juin"
+
msgid "LFSStatus|Disabled"
msgstr "Désactivé"
@@ -1211,9 +1509,18 @@ msgstr "Fichiers verrouillés"
msgid "Login"
msgstr "Se connecter"
+msgid "Mar"
+msgstr "Mars"
+
+msgid "March"
+msgstr "Mars"
+
msgid "Maximum git storage failures"
msgstr "Nombre maximum d’échecs du stockage git"
+msgid "May"
+msgstr "Mai"
+
msgid "Median"
msgstr "Médian"
@@ -1258,9 +1565,15 @@ msgstr "Nouveau pipeline programmé"
msgid "New branch"
msgstr "Nouvelle branche"
+msgid "New branch unavailable"
+msgstr "Nouvelle branche indisponible"
+
msgid "New directory"
msgstr "Nouveau dossier"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "Nouveau fichier"
@@ -1297,6 +1610,9 @@ msgstr "Pas de dépôt"
msgid "No schedules"
msgstr "Aucun programme"
+msgid "No time spent"
+msgstr "Pas de temps passé"
+
msgid "None"
msgstr "Aucun·e"
@@ -1363,18 +1679,33 @@ msgstr "Surveillé"
msgid "Notifications"
msgstr "Notifications"
+msgid "Nov"
+msgstr "Nov."
+
+msgid "November"
+msgstr "Novembre"
+
msgid "Number of access attempts"
msgstr "Nombre de tentatives d'accès"
msgid "Number of failures before backing off"
msgstr "Nombre d'échecs avant annulation"
+msgid "Oct"
+msgstr "Oct."
+
+msgid "October"
+msgstr "Octobre"
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtre"
msgid "Only project members can comment."
msgstr "Seuls les membres du projet peuvent commenter."
+msgid "Opened"
+msgstr "Ouvert"
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Ouvert"
@@ -1507,6 +1838,9 @@ msgstr "avec l'étape"
msgid "Pipeline|with stages"
msgstr "avec les étapes"
+msgid "Please solve the reCAPTCHA"
+msgstr "Veuillez résoudre le reCAPTCHA"
+
msgid "Preferences"
msgstr "Préférences"
@@ -1612,9 +1946,15 @@ msgstr "Graphes"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr "Contactez un administrateur pour modifier ce paramètre."
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr "Exécuter immédiatement un pipeline sur la branche par défaut"
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "Seules les validations signées peuvent être poussées sur ce dépôt."
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr "Problème lors de la configuration des paramètres CI/CD JavaScript"
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr "Ce paramètre est appliqué au niveau du serveur et peut être modifié par un administrateur."
@@ -1622,7 +1962,7 @@ msgid "ProjectSettings|This setting is applied on the server level but has been
msgstr "Ce paramètre est appliqué au niveau du serveur mais il a été modifié pour ce projet."
msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
-msgstr "Ce paramètre s’appliquera à tous les projets à moins qu’un administrateur ne le modifie."
+msgstr "Ce paramètre s’appliquera à tous les projets à moins qu’un•e administrat•eur•rice ne le modifie."
msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
msgstr "Les utilisateurs peuvent uniquement pousser sur ce dépôt des validations qui ont été validées avec une de leurs adresses courriels vérifiées."
@@ -1651,6 +1991,39 @@ msgstr "Désolé, aucun projet ne correspond à votre recherche"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Cette fonctionnalité requiert le support du localStorage par votre navigateur"
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr "Public - Le groupe ainsi que n’importe quel projet public est accessible sans authentification."
@@ -1747,6 +2120,9 @@ msgstr "Programmes"
msgid "Scheduling Pipelines"
msgstr "Programmer des pipelines"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "Rechercher dans les branches et les étiquettes"
@@ -1768,6 +2144,12 @@ msgstr "Sélectionnez un fuseau horaire"
msgid "Select target branch"
msgstr "Sélectionnez une branche cible"
+msgid "Sep"
+msgstr "Sept."
+
+msgid "September"
+msgstr "Septembre"
+
msgid "Service Templates"
msgstr "Modèles de service"
@@ -1800,14 +2182,29 @@ msgid_plural "Showing %d events"
msgstr[0] "Affichage de %d évènement"
msgstr[1] "Affichage de %d évènements"
+msgid "Sidebar|Change weight"
+msgstr "Changer le poids"
+
+msgid "Sidebar|Edit"
+msgstr "Modifier"
+
+msgid "Sidebar|No"
+msgstr "Non"
+
+msgid "Sidebar|None"
+msgstr "Aucun"
+
+msgid "Sidebar|Weight"
+msgstr "Poids"
+
msgid "Snippets"
msgstr "Extraits de code"
msgid "Something went wrong on our end."
msgstr "Une erreur est survenue de notre côté."
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
-msgstr "Quelque chose ne s'est pas bien passé en essayant de changer l’état de verrouillage de cet ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr "Quelque chose ne s‘est pas bien passé en essayant de changer l’état de verrouillage de cette ${this.issuableDisplayName}"
msgid "Something went wrong while fetching the projects."
msgstr "Une erreur s'est produite lors de la récupération des projets."
@@ -1914,9 +2311,15 @@ msgstr "Commence bientôt"
msgid "SortOptions|Weight"
msgstr "Poids"
+msgid "Source"
+msgstr "Source"
+
msgid "Source code"
msgstr "Code source"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr "Journaux des messages indésirables"
@@ -1935,6 +2338,9 @@ msgstr "Créer une %{new_merge_request} avec ces changements"
msgid "Start the Runner!"
msgstr "Démarrer l'Exécuteur !"
+msgid "Stopped"
+msgstr "Arrêté"
+
msgid "Subgroups"
msgstr "Sous-groupes"
@@ -1955,6 +2361,75 @@ msgstr[1] "Tags"
msgid "Tags"
msgstr "Tags"
+msgid "TagsPage|Browse commits"
+msgstr "Parcourir les validations"
+
+msgid "TagsPage|Browse files"
+msgstr "Parcourir les fichiers"
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr "Impossible de trouver la validation HEAD pour ce tag"
+
+msgid "TagsPage|Cancel"
+msgstr "Annuler"
+
+msgid "TagsPage|Create tag"
+msgstr "Créer le tag"
+
+msgid "TagsPage|Delete tag"
+msgstr "Supprimer le tag"
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr "La suppression du tag %{tag_name} ne peut être annulée. Êtes-vous sûr•e ?"
+
+msgid "TagsPage|Edit release notes"
+msgstr "Modifier les notes de version"
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr "Nom de branche, tag, ou SHA de validation existant"
+
+msgid "TagsPage|Filter by tag name"
+msgstr "Filtrer par nom de tag"
+
+msgid "TagsPage|New Tag"
+msgstr "Nouveau tag"
+
+msgid "TagsPage|New tag"
+msgstr "Nouveau tag"
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr "Éventuellement, ajoutez un message au tag."
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr "Éventuellement, ajouter des notes de version pour le tag. Elles seront stockées dans la base de données de GitLab et affichées sur la page des tags."
+
+msgid "TagsPage|Release notes"
+msgstr "Notes de version"
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr "Le dépôt n‘a pas de tags pour le moment."
+
+msgid "TagsPage|Sort by"
+msgstr "Trier par"
+
+msgid "TagsPage|Tags"
+msgstr "Tags"
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr "Les tags permettent de marquer des validations spécifiques commes importantes dans l‘historique du project"
+
+msgid "TagsPage|This tag has no release notes."
+msgstr "Ce tag n‘a pas de notes de version."
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr "Utilisez la commande git tag pour en ajouter un nouveau :"
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr "Écrivez les notes de version ou faîtes glisser des fichiers ici…"
+
+msgid "TagsPage|protected"
+msgstr "protégé"
+
msgid "Target Branch"
msgstr "Branche cible"
@@ -1962,10 +2437,10 @@ msgid "Team"
msgstr "Équipe"
msgid "Thanks! Don't show me this again"
-msgstr "Merci de ne plus afficher ce message"
+msgstr "Merci ! Ne plus afficher ce message"
msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
-msgstr "La Recherche Globale Avancée de GitLab est un outils qui vous fait gagner du temps. Au lieu de créer du code similaire et perdre du temps, vous pouvez maintenant chercher dans le code d'autres équipes pour vous aider sur votre projet."
+msgstr "La Recherche Globale Avancée de Gitlab est un outils puissant qui vous fait gagner du temps. Au lieu de créer du code similaire et perdre du temps, vous pouvez maintenant chercher dans le code d'autres équipes pour vous aider sur votre projet."
msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold"
msgstr "Le seuil d’interruption du disjoncteur devrait être inférieur au seuil de nombre de défaillance"
@@ -2036,6 +2511,9 @@ msgstr "La valeur située au point médian d’une série de valeur observée. C
msgid "There are problems accessing Git storage: "
msgstr "Il y a des difficultés à accéder aux données Git : "
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr "Cette branche a changé depuis le début de l’édition. Souhaitez-vous créer une nouvelle branche ?"
@@ -2057,6 +2535,9 @@ msgstr "Cela signifie que vous ne pouvez pas pousser du code tant que vous n’a
msgid "This merge request is locked."
msgstr "Cette demande de fusion est verrouillée."
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Temps avant qu’un ticket ne soit planifié"
@@ -2205,15 +2686,27 @@ msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
+msgid "Title"
+msgstr "Titre"
+
msgid "Total Time"
msgstr "Temps total"
+msgid "Total issue time spent"
+msgstr "Temps total passé sur les tickets"
+
msgid "Total test time for all commits/merges"
msgstr "Temps total de test pour toutes les validations/fusions"
msgid "Track activity with Contribution Analytics."
msgstr "Suivre l’activité avec Contribution Analytics."
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr "Déverrouiller"
@@ -2239,7 +2732,7 @@ msgid "Upgrade your plan to activate Issue weight."
msgstr "Mettez à niveau votre abonnement pour activer les poids de ticket."
msgid "Upgrade your plan to improve Issue boards."
-msgstr "Mettez à niveau votre abonnement pour améliorer les tableaux de tickets."
+msgstr "Mettez à niveau votre forfait pour améliorer les tableaux de tickets."
msgid "Upload New File"
msgstr "Téléverser un nouveau fichier"
@@ -2250,6 +2743,9 @@ msgstr "Téléverser un fichier"
msgid "UploadLink|click to upload"
msgstr "Cliquez pour envoyer"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr "Utiliser le jeton d’inscription suivant pendant l’installation :"
@@ -2283,6 +2779,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 "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr "Les webhooks vous permettent d’appeler une URL si, par exemple, du nouveau code est poussé ou un nouveau ticket est créé. Vous pouvez configurer les webhooks pour écouter les événements spécifiques comme des poussées de code, des tickets ou des demandes de fusion. Les webhooks de groupes s’appliqueront à tous les projets dans un groupe, ce qui vous permet de normaliser la fonctionnalité du webhook dans votre groupe entier."
@@ -2412,12 +2911,6 @@ msgstr "Vous allez supprimer la relation de fourche avec le projet source %{fork
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Vous allez transférer %{project_name_with_namespace} à un nouveau propriétaire. Êtes vous ABSOLUMENT sûr·e ?"
-msgid "You are on a read-only GitLab instance."
-msgstr "Vous êtes sur une instance GitLab en lecture seule."
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr "Vous êtes sur une instance GitLab en lecture seule. Si vous souhaitez apporter des modifications, vous devez aller sur %{link_to_primary_node}."
-
msgid "You can only add files when you are on a branch"
msgstr "Vous ne pouvez ajouter de fichier que dans une branche"
@@ -2457,6 +2950,9 @@ msgstr "Vous ne pourrez pas récupérer ou pousser de code par %{protocol} tant
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "Vous ne pourrez pas récupérer ou pousser de code par SSH tant que vous n’aurez pas %{add_ssh_key_link} dans votre profil"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr "Vous ne pourrez pas récupérer ou pousser de code par SSH tant que vous n’aurez pas ajouté de clé SSH à votre profil"
+
msgid "Your comment will not be visible to the public."
msgstr "Votre commentaire ne sera pas visible publiquement."
@@ -2469,6 +2965,12 @@ msgstr "Votre nom"
msgid "Your projects"
msgstr "Vos projets"
+msgid "branch name"
+msgstr "nom de la branche"
+
+msgid "by"
+msgstr "par"
+
msgid "commit"
msgstr "validation"
@@ -2494,6 +2996,9 @@ msgstr "mot de passe"
msgid "personal access token"
msgstr "jeton d’accès personnel"
+msgid "source"
+msgstr "source"
+
msgid "to help your contributors communicate effectively!"
msgstr "pour aider vos contributeurs à communiquer efficacement !"
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index 8a987129452..52bbc28ac10 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-20 03:59-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:42-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@@ -18,13 +18,13 @@ msgstr ""
msgid "%d commit"
msgid_plural "%d commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d commit"
+msgstr[1] "%d commits"
msgid "%d layer"
msgid_plural "%d layers"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d livello"
+msgstr[1] "%d livelli"
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
@@ -36,45 +36,48 @@ msgstr "%{commit_author_link} ha committato %{commit_timeago}"
msgid "%{count} participant"
msgid_plural "%{count} participants"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{count} partecipante"
+msgstr[1] "%{count} partecipanti"
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
-msgstr ""
+msgstr "%{number_commits_behind} commits precedenti %{default_branch}, %{number_commits_ahead} commits avanti"
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt."
-msgstr ""
+msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. GitLab consentirà l'accesso al prossimo tentativo."
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will block access for %{number_of_seconds} seconds."
-msgstr ""
+msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. Gitlab bloccherà l'accesso per %{number_of_seconds} secondi."
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} di %{maximum_failures} fallimenti. Gitlab non ritenterà automaticamente. Ripristina l'informazioni d'archiviazione quando il problema è risolto."
msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{storage_name}: tentativo d'accesso all'archiviazione fallito da parte dell'host:"
+msgstr[1] "%{storage_name}: %{failed_attempts} tentativi d'accesso all'archiviazione falliti:"
+
+msgid "%{text} is available"
+msgstr "%{text} è disponibile"
msgid "(checkout the %{link} for information on how to install it)."
-msgstr ""
+msgstr "(vedi il %{link} su come installarlo)."
msgid "+ %{moreCount} more"
-msgstr ""
+msgstr "+ %{moreCount} più"
msgid "- show less"
-msgstr ""
+msgstr "- riduci"
msgid "1 pipeline"
msgid_plural "%d pipelines"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 pipeline"
+msgstr[1] "%d pipeline"
msgid "1st contribution!"
-msgstr ""
+msgstr "Primo contributo!"
msgid "2FA enabled"
-msgstr ""
+msgstr "2FA abilitata"
msgid "A collection of graphs regarding Continuous Integration"
msgstr "Un insieme di grafici riguardo la Continuous Integration"
@@ -83,16 +86,16 @@ msgid "About auto deploy"
msgstr "Riguardo il rilascio automatico"
msgid "Abuse Reports"
-msgstr ""
+msgstr "Segnalazioni di abuso"
msgid "Access Tokens"
-msgstr ""
+msgstr "Token di accesso"
msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again."
-msgstr ""
+msgstr "L'accesso agli storages è stato temporaneamente disabilitato per consentire il mount di ripristino. Resetta le info d'archiviazione dopo che l'issue è stato risolto per consentire nuovamente l'accesso."
msgid "Account"
-msgstr ""
+msgstr "Account"
msgid "Active"
msgstr "Attivo"
@@ -115,29 +118,41 @@ msgstr ""
msgid "Add License"
msgstr "Aggiungi Licenza"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "Aggiungi una chiave SSH al tuo profilo per eseguire pull o push tramite SSH"
-
msgid "Add new directory"
msgstr "Aggiungi una directory (cartella)"
msgid "AdminHealthPageLink|health page"
-msgstr ""
+msgstr "Pagina di stato"
msgid "Advanced settings"
-msgstr ""
+msgstr "Impostazioni Avanzate"
msgid "All"
+msgstr "Tutto"
+
+msgid "An error occurred when toggling the notification subscription"
+msgstr "Errore durante l'attivazione/disattivazione della sottoscrizione per l'iscrizione"
+
+msgid "An error occurred when updating the issue weight"
msgstr ""
+msgid "An error occurred while fetching sidebar data"
+msgstr "Errore durante il recupero dei dati della barra laterale"
+
msgid "An error occurred. Please try again."
-msgstr ""
+msgstr "Si è verificato un errore. Riprova."
msgid "Appearance"
-msgstr ""
+msgstr "Aspetto"
msgid "Applications"
-msgstr ""
+msgstr "Applicazioni"
+
+msgid "Apr"
+msgstr "Apr"
+
+msgid "April"
+msgstr "Aprile"
msgid "Archived project! Repository is read-only"
msgstr "Progetto archiviato! La Repository è sola-lettura"
@@ -146,58 +161,67 @@ msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Sei sicuro di voler cancellare questa pipeline programmata?"
msgid "Are you sure you want to discard your changes?"
-msgstr ""
+msgstr "Vuoi davvero ignorare le modifiche?"
msgid "Are you sure you want to leave this group?"
-msgstr ""
+msgstr "Vuoi davvero lasciare questo gruppo?"
msgid "Are you sure you want to reset registration token?"
-msgstr ""
+msgstr "Sei sicuro di voler ripristinare il token di registrazione?"
msgid "Are you sure you want to reset the health check token?"
-msgstr ""
+msgstr "Confermi di voler resettare il token di controllo di stato?"
msgid "Are you sure?"
-msgstr ""
+msgstr "Sei sicuro?"
msgid "Artifacts"
-msgstr ""
+msgstr "Artefatti"
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Aggiungi un file tramite trascina & rilascia ( drag & drop) o %{upload_link}"
+msgid "Aug"
+msgstr "Ago"
+
+msgid "August"
+msgstr "Agosto"
+
msgid "Authentication Log"
-msgstr ""
+msgstr "Log di autenticazione"
msgid "Author"
-msgstr ""
+msgstr "Autore"
msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly."
-msgstr ""
+msgstr "Le app d'auto-review e l'Auto Deploy (rilascio automatico) necessita di un nome dominio e il servizio %{kubernetes} per funzionare correttamente."
msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly."
-msgstr ""
+msgstr "Le app d'auto-review e l'Auto Deploy (rilascio automatico) necessita di un nome dominio per funzionare correttamente."
msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly."
-msgstr ""
+msgstr "Le app d'auto-review e l'Auto Deploy (rilascio automatico) necessita del servizio %{kubernetes} per funzionare correttamente."
msgid "AutoDevOps|Auto DevOps (Beta)"
-msgstr ""
+msgstr "Auto DevOps (Béta)"
msgid "AutoDevOps|Auto DevOps documentation"
-msgstr ""
+msgstr "Documentazione Auto DevOps"
msgid "AutoDevOps|Enable in settings"
-msgstr ""
+msgstr "Attiva in impostazioni"
msgid "AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
-msgstr ""
+msgstr "Farà automaticamente le build, i test e i rilasci della tua applicazione basato sulla tua configurazione CI/CD."
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
-msgstr ""
+msgstr "Approfondisci: %{link_to_documentation}"
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
-msgstr ""
+msgstr "Puoi attivare %{link_to_settings} per questo progetto."
+
+msgid "Available"
+msgstr "Disponibile"
msgid "Billing"
msgstr ""
@@ -262,7 +286,13 @@ msgid "Branch %{branch_name} was created. To set up auto deploy
msgstr "La branch %{branch_name} è stata creata. Per impostare un rilascio automatico scegli un template CI di Gitlab e committa le tue modifiche %{link_to_autodeploy_doc}"
msgid "Branch has changed"
-msgstr ""
+msgstr "La branche è cambiata"
+
+msgid "Branch is already taken"
+msgstr "La Branch esiste già"
+
+msgid "Branch name"
+msgstr "Nome Branch"
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Cerca branches"
@@ -271,91 +301,91 @@ msgid "BranchSwitcherTitle|Switch branch"
msgstr "Cambia branch"
msgid "Branches"
-msgstr ""
+msgstr "Branch"
msgid "Branches|Cant find HEAD commit for this branch"
-msgstr ""
+msgstr "Impossibile trovare l'HEAD commit per questa branch"
msgid "Branches|Compare"
-msgstr ""
+msgstr "Confronta"
msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
-msgstr ""
+msgstr "Elimina tutte le branches che sono state mergiate in '%{default_branch}'"
msgid "Branches|Delete branch"
-msgstr ""
+msgstr "Elimina Branch"
msgid "Branches|Delete merged branches"
-msgstr ""
+msgstr "Elimina branch mergiate"
msgid "Branches|Delete protected branch"
-msgstr ""
+msgstr "Elimina la branch protetta"
msgid "Branches|Delete protected branch '%{branch_name}'?"
-msgstr ""
+msgstr "Eliminare la branch protetta %{branch_name}?"
msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?"
-msgstr ""
+msgstr "Eliminando la branch %{branch_name} è un'operazione irreversibile. Sicuro di voler procedere?"
msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
-msgstr ""
+msgstr "Eliminare le branch mergiate è un'operazione irreversibile. Sicuro di voler procedere?"
msgid "Branches|Filter by branch name"
-msgstr ""
+msgstr "Filtra per nome branch"
msgid "Branches|Merged into %{default_branch}"
-msgstr ""
+msgstr "Mergiata in %{default_branch}"
msgid "Branches|New branch"
-msgstr ""
+msgstr "Nuova branch"
msgid "Branches|No branches to show"
-msgstr ""
+msgstr "Nessuna branch da mostrare"
msgid "Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered."
-msgstr ""
+msgstr "Una volta confermato e premuto %{delete_protected_branch} non sarà possibile ripristinare allo stato precedente."
msgid "Branches|Only a project master or owner can delete a protected branch"
-msgstr ""
+msgstr "Solo gli Owner e i Master possono eliminare una branch protetta"
msgid "Branches|Protected branches can be managed in %{project_settings_link}"
-msgstr ""
+msgstr "Le branch protette possono esser gestite in %{project_settings_link}"
msgid "Branches|Sort by"
-msgstr ""
+msgstr "Ordina per"
msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart."
msgstr ""
msgid "Branches|The default branch cannot be deleted"
-msgstr ""
+msgstr "La branch predefinita non può esser eliminata"
msgid "Branches|This branch hasn’t been merged into %{default_branch}."
-msgstr ""
+msgstr "Questa branch non è stata mergiata in %{default_branch}."
msgid "Branches|To avoid data loss, consider merging this branch before deleting it."
-msgstr ""
+msgstr "Per evitare perdita di dati considera di mergiare questa branch prima di eliminarla."
msgid "Branches|To confirm, type %{branch_name_confirmation}:"
-msgstr ""
+msgstr "Per confermare, scrivi %{branch_name_confirmation}:"
msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
msgstr ""
msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
-msgstr ""
+msgstr "Stai per eliminare la branch protetta (%{branch_name}) in maniera permanente."
msgid "Branches|diverged from upstream"
msgstr ""
msgid "Branches|merged"
-msgstr ""
+msgstr "mergiata"
msgid "Branches|project settings"
-msgstr ""
+msgstr "Impostazioni"
msgid "Branches|protected"
-msgstr ""
+msgstr "Protetta"
msgid "Browse Directory"
msgstr "Naviga direttori"
@@ -373,19 +403,19 @@ msgid "ByAuthor|by"
msgstr "per"
msgid "CI / CD"
-msgstr ""
+msgstr "CI / CD"
msgid "CI configuration"
msgstr "Configurazione CI (Integrazione Continua)"
msgid "CICD|Jobs"
-msgstr ""
+msgstr "Jobs"
msgid "Cancel"
msgstr "Cancella"
msgid "Cancel edit"
-msgstr ""
+msgstr "Annulla modifica"
msgid "Change Weight"
msgstr ""
@@ -403,16 +433,22 @@ msgid "ChangeTypeAction|Revert"
msgstr "Ripristina"
msgid "Changelog"
-msgstr ""
+msgstr "Changelog"
msgid "Charts"
msgstr "Grafici"
msgid "Chat"
-msgstr ""
+msgstr "Chat"
+
+msgid "Checking %{text} availability…"
+msgstr "Controllo disponibilità per %{text}…"
+
+msgid "Checking branch availability..."
+msgstr "Controllo disponibilità branch..."
msgid "Cherry-pick this commit"
-msgstr ""
+msgstr "Cherry-pick di questo commit"
msgid "Cherry-pick this merge request"
msgstr "Cherry-pick questa richiesta di merge"
@@ -475,58 +511,124 @@ msgid "CiStatus|running"
msgstr "in corso"
msgid "CircuitBreakerApiLink|circuitbreaker api"
-msgstr ""
+msgstr "api circuitbreaker"
msgid "Clone repository"
-msgstr ""
+msgstr "Clona repository"
msgid "Close"
msgstr ""
msgid "Cluster"
-msgstr ""
+msgstr "Cluster"
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
-msgstr ""
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr "%{appList} è stata installata con successo nel tuo cluster"
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr "%{boldNotice} Ciò richiederà delle risorse extra come un load balancer, dove si applicheranno costi aggiuntivi. Consulta %{pricingLink}"
+
+msgid "ClusterIntegration|API URL"
+msgstr "API URL"
+
+msgid "ClusterIntegration|Active"
+msgstr "Attivo"
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr "Aggiungi un cluster esistente"
+
+msgid "ClusterIntegration|Add cluster"
+msgstr "Aggiungi cluster"
+
+msgid "ClusterIntegration|All"
+msgstr "Tutti"
+
+msgid "ClusterIntegration|Applications"
+msgstr "Applicazioni"
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr "Certificato CA"
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr "Certificate Authority bundle (formato PEM)"
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr "Scegli come impostare l'integrazione cluster"
+
+msgid "ClusterIntegration|Cluster"
+msgstr "Cluster"
msgid "ClusterIntegration|Cluster details"
-msgstr ""
+msgstr "Dettagli Cluster"
msgid "ClusterIntegration|Cluster integration"
-msgstr ""
+msgstr "Integrazione Cluster"
msgid "ClusterIntegration|Cluster integration is disabled for this project."
-msgstr ""
+msgstr "L'integrazione dei cluster è disabilitata per questo progetto."
msgid "ClusterIntegration|Cluster integration is enabled for this project."
-msgstr ""
+msgstr "L'integrazione dei cluster è abilitata per questo progetto."
msgid "ClusterIntegration|Cluster integration is enabled for this project. Disabling this integration will not affect your cluster, it will only temporarily turn off GitLab's connection to it."
-msgstr ""
+msgstr "L'integrazione dei cluster è abilitata per questo progetto. Se la disabiliti il tuo cluster non sarà modificato, sarà solo spenta la connessione a Gitlab."
msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..."
msgstr ""
msgid "ClusterIntegration|Cluster name"
-msgstr ""
+msgstr "Nome Cluster"
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
msgstr ""
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr "I cluster di consentono di revisionare le app, effettuare rilasci, eseguire pipelines, e molto altro in modo semplice. %{link_to_help_page}"
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr "Copia URL API"
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr "Copia Certificato CA"
+
+msgid "ClusterIntegration|Copy Token"
+msgstr "Copia Token"
+
msgid "ClusterIntegration|Copy cluster name"
-msgstr ""
+msgstr "Copia nome del cluster"
+
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr "Crea un nuovo cluster su Google Engine direttamente da Gitlab"
msgid "ClusterIntegration|Create cluster"
-msgstr ""
+msgstr "Crea cluster"
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Create on GKE"
+msgstr "Crea su GKE"
+
msgid "ClusterIntegration|Enable cluster integration"
-msgstr ""
+msgstr "Abilita integrazione cluster"
+
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr "Inserisci i dettagli per un cluster Kubernetes esistente"
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr "Inserisci i dettagli per il tuo cluster"
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr "Environment pattern"
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr "Prezzi GKE"
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr "Gitlab Runner"
msgid "ClusterIntegration|Google Cloud Platform project ID"
-msgstr ""
+msgstr "ID Progetto di Google Cloud Platform"
msgid "ClusterIntegration|Google Kubernetes Engine"
msgstr ""
@@ -534,27 +636,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr "Helm Tiller"
+
+msgid "ClusterIntegration|Inactive"
+msgstr "Inattivo"
+
+msgid "ClusterIntegration|Ingress"
+msgstr "Ingresso"
+
+msgid "ClusterIntegration|Install"
+msgstr "Installa"
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr "Installa applicazioni sul tuo cluster. Leggi di più a riguardo %{helpLink}"
+
+msgid "ClusterIntegration|Installed"
+msgstr "Installato"
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr "Approfondisci riguardo i Clusters"
+
msgid "ClusterIntegration|Machine type"
-msgstr ""
+msgstr "Tipo di macchina"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
-msgstr ""
+msgstr "Assicurati che il tuo account %{link_to_requirements} per creare i cluster"
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
-msgstr ""
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
+msgstr "Gestisci l'integrazione dei cluster nel tuo progetto GitLab"
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
-msgstr ""
+msgstr "Gestisci i tuoi cluster visitando %{link_gke}"
+
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr "I cluster multipli sono disponibili nell'edizione Enterprise di Gitlab (Premium e Ultimate)"
+
+msgid "ClusterIntegration|Note:"
+msgstr "Nota:"
msgid "ClusterIntegration|Number of nodes"
+msgstr "Numero di nodi"
+
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
msgstr ""
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -567,7 +717,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -582,15 +738,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -606,9 +780,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -616,20 +796,15 @@ msgid "ClusterIntegration|properly configured"
msgstr ""
msgid "Comments"
-msgstr ""
+msgstr "Commenti"
msgid "Commit"
msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Commit Message"
-msgstr ""
+msgstr "Messaggio di commit"
msgid "Commit duration in minutes for last 30 commits"
msgstr "Durata del commit (in minuti) per gli ultimi 30 commit"
@@ -644,7 +819,7 @@ msgid "CommitMessage|Add %{file_name}"
msgstr "Aggiungi %{file_name}"
msgid "Commits"
-msgstr ""
+msgstr "Commits"
msgid "Commits feed"
msgstr "Feed dei Commits"
@@ -689,19 +864,19 @@ msgid "ContainerRegistry|Remove tag"
msgstr ""
msgid "ContainerRegistry|Size"
-msgstr ""
+msgstr "Dimensione"
msgid "ContainerRegistry|Tag"
-msgstr ""
+msgstr "Tag"
msgid "ContainerRegistry|Tag ID"
-msgstr ""
+msgstr "Tag ID"
msgid "ContainerRegistry|Use different image names"
-msgstr ""
+msgstr "Utilizza nomi d'immagine differenti"
msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
-msgstr ""
+msgstr "Con il Docker Container Registry integrato in Gitlab, ogni progetto può avere il suo spazio d'archiviazione sulle immagini Docker."
msgid "Contribution guide"
msgstr "Guida per contribuire"
@@ -709,6 +884,15 @@ msgstr "Guida per contribuire"
msgid "Contributors"
msgstr "Collaboratori"
+msgid "ContributorsPage|Building repository graph."
+msgstr "Genero grafico della repository."
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr "Esegui i commit su %{branch_name}, escludendo i commit di merge. Limitati a 6000 commits."
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr "Attendere prego, questa pagina si ricaricherà automaticamente appena pronta."
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -736,20 +920,23 @@ msgstr "Crea cartella"
msgid "Create empty bare repository"
msgstr "Crea una repository vuota"
-msgid "Create file"
+msgid "Create epic"
msgstr ""
+msgid "Create file"
+msgstr "Crea file"
+
msgid "Create merge request"
msgstr "Crea una richiesta di merge"
msgid "Create new branch"
-msgstr ""
+msgstr "Crea un nuova branch"
msgid "Create new directory"
-msgstr ""
+msgstr "Crea una nuova cartella"
msgid "Create new file"
-msgstr ""
+msgstr "Crea un nuovo File"
msgid "Create new..."
msgstr "Crea nuovo..."
@@ -763,9 +950,12 @@ msgstr "Tag"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Crea token d'accesso personale"
-msgid "Cron Timezone"
+msgid "Creating epic"
msgstr ""
+msgid "Cron Timezone"
+msgstr "Timezone del Cron"
+
msgid "Cron syntax"
msgstr "Sintassi Cron"
@@ -803,10 +993,16 @@ msgid "CycleAnalyticsStage|Test"
msgstr "Test"
msgid "DashboardProjects|All"
-msgstr ""
+msgstr "Tutti"
msgid "DashboardProjects|Personal"
-msgstr ""
+msgstr "Personale"
+
+msgid "Dec"
+msgstr "Dic"
+
+msgid "December"
+msgstr "Dicembre"
msgid "Define a custom pattern with cron syntax"
msgstr "Definisci un patter personalizzato mediante la sintassi cron"
@@ -820,7 +1016,7 @@ msgstr[0] "Rilascio"
msgstr[1] "Rilasci"
msgid "Deploy Keys"
-msgstr ""
+msgstr "Chiavi di Deploy (rilascio)"
msgid "Description"
msgstr "Descrizione"
@@ -829,16 +1025,16 @@ msgid "Description templates allow you to define context-specific templates for
msgstr ""
msgid "Details"
-msgstr ""
+msgstr "Dettagli"
msgid "Directory name"
msgstr "Nome cartella"
msgid "Discard changes"
-msgstr ""
+msgstr "Annulla modifiche"
msgid "Dismiss Cycle Analytics introduction box"
-msgstr ""
+msgstr "Chiudi l'introduzione alle Analisi Cicliche"
msgid "Dismiss Merge Request promotion"
msgstr ""
@@ -880,25 +1076,91 @@ msgid "Edit Pipeline Schedule %{id}"
msgstr "Cambia programmazione della pipeline %{id}"
msgid "Emails"
+msgstr "E-mail"
+
+msgid "Environments|An error occurred while fetching the environments."
+msgstr "Errore durante il fetch degli ambienti."
+
+msgid "Environments|An error occurred while making the request."
+msgstr "Errore durante l'esecuzione della richiesta."
+
+msgid "Environments|Commit"
+msgstr "Commit"
+
+msgid "Environments|Deployment"
+msgstr "Rilascio"
+
+msgid "Environments|Environment"
+msgstr "Ambiente"
+
+msgid "Environments|Environments"
+msgstr "Ambienti"
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr "Gli ambienti sono gli spazi dove il codice viene rilasciato, come staging o produzione."
+
+msgid "Environments|Job"
+msgstr "Job"
+
+msgid "Environments|New environment"
+msgstr "Nuovo ambiente"
+
+msgid "Environments|No deployments yet"
+msgstr "Ancora nessuna chiave di rilascio"
+
+msgid "Environments|Open"
+msgstr "Apri"
+
+msgid "Environments|Re-deploy"
+msgstr "Rilascia di nuovo"
+
+msgid "Environments|Read more about environments"
+msgstr "Leggi di più sugli ambienti"
+
+msgid "Environments|Rollback"
+msgstr "Rollback (ripristina)"
+
+msgid "Environments|Show all"
+msgstr "Mostra tutti"
+
+msgid "Environments|Updated"
+msgstr "Aggiornato"
+
+msgid "Environments|You don't have any environments right now."
+msgstr "Attualmente non hai alcun ambiente."
+
+msgid "Epic will be removed! Are you sure?"
msgstr ""
-msgid "EventFilterBy|Filter by all"
+msgid "Epics"
msgstr ""
-msgid "EventFilterBy|Filter by comments"
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
-msgid "EventFilterBy|Filter by issue events"
+msgid "Error creating epic"
msgstr ""
+msgid "Error occurred when toggling the notification subscription"
+msgstr "Errore durante l'attivazione/disattivazione della sottoscrizione per l'iscrizione"
+
+msgid "EventFilterBy|Filter by all"
+msgstr "Filtra per tutti"
+
+msgid "EventFilterBy|Filter by comments"
+msgstr "Filtra per commenti"
+
+msgid "EventFilterBy|Filter by issue events"
+msgstr "Filtra per eventi di issue"
+
msgid "EventFilterBy|Filter by merge events"
-msgstr ""
+msgstr "Filtra per eventi di merge"
msgid "EventFilterBy|Filter by push events"
-msgstr ""
+msgstr "Filtra per eventi di push"
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "Filtra per team"
msgid "Every day (at 4:00am)"
msgstr "Ogni giorno (alle 4 del mattino)"
@@ -910,10 +1172,10 @@ msgid "Every week (Sundays at 4:00am)"
msgstr "Ogni settimana (Di domenica alle 4 del mattino)"
msgid "Explore projects"
-msgstr ""
+msgstr "Esplora progetti"
msgid "Explore public groups"
-msgstr ""
+msgstr "Esplora gruppi pubblici"
msgid "Failed to change the owner"
msgstr "Impossibile cambiare owner"
@@ -921,11 +1183,17 @@ msgstr "Impossibile cambiare owner"
msgid "Failed to remove the pipeline schedule"
msgstr "Impossibile rimuovere la pipeline pianificata"
+msgid "Feb"
+msgstr "Feb"
+
+msgid "February"
+msgstr "Febbraio"
+
msgid "File name"
-msgstr ""
+msgstr "Nome file"
msgid "Files"
-msgstr ""
+msgstr "Files"
msgid "Filter by commit message"
msgstr "Filtra per messaggio di commit"
@@ -944,17 +1212,17 @@ msgstr "Push di"
msgid "Fork"
msgid_plural "Forks"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Fork"
+msgstr[1] "Forks"
msgid "ForkedFromProjectPath|Forked from"
msgstr "Fork da"
msgid "ForkedFromProjectPath|Forked from %{project_name} (deleted)"
-msgstr ""
+msgstr "Fork da %{project_name} (eliminato)"
msgid "Format"
-msgstr ""
+msgstr "Formato"
msgid "From issue creation until deploy to production"
msgstr "Dalla creazione di un issue fino al rilascio in produzione"
@@ -963,11 +1231,26 @@ 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 ""
+msgstr "Chiavi GPG"
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -981,10 +1264,10 @@ msgid "Geo|Select groups to replicate."
msgstr ""
msgid "Git storage health information has been reset"
-msgstr ""
+msgstr "Le informazioni sullo stato dell'archiviazione Git è stata ripristinata"
msgid "GitLab Runner section"
-msgstr ""
+msgstr "Sezione Gitlab Runner"
msgid "Go to your fork"
msgstr "Vai il tuo fork"
@@ -993,22 +1276,22 @@ msgid "GoToYourFork|Fork"
msgstr "Fork"
msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
-msgstr ""
+msgstr "L'autenticazione Google non è %{link_to_documentation}. Richiedi al tuo amministratore Gitlab se desideri utilizzare il servizio."
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
-msgstr ""
+msgstr "Blocca la condivisione di un progetto di %{group} con altri gruppi"
msgid "GroupSettings|Share with group lock"
-msgstr ""
+msgstr "Condividi con il gruppo chiuso"
msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
-msgstr ""
+msgstr "Questa modifica è stata applicata su %{ancestor_group} ed è stata ignorata nel sottogruppo."
msgid "GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}."
-msgstr ""
+msgstr "Questa impostazione è stata applicata a %{ancestor_group}. Per condividere i progetti con altri gruppi chiedi all'owner di eseguire l'override delle impostazioni oppure %{remove_ancestor_share_with_group_lock}."
msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
-msgstr ""
+msgstr "Questa impostazione è stata applicata a %{ancestor_group}. Puoi eseguire l'override delle impostazioni o %{remove_ancestor_share_with_group_lock}."
msgid "GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner. Groups that already have access to the project will continue to have access unless removed manually."
msgstr ""
@@ -1031,9 +1314,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1064,9 +1344,12 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
-msgid "Health Check"
+msgid "Have your users email"
msgstr ""
+msgid "Health Check"
+msgstr "Verifica stato"
+
msgid "Health information can be retrieved from the following endpoints. More information is available"
msgstr ""
@@ -1083,7 +1366,7 @@ msgid "HealthCheck|Unhealthy"
msgstr ""
msgid "History"
-msgstr ""
+msgstr "Cronologia"
msgid "Housekeeping successfully started"
msgstr "Housekeeping iniziato con successo"
@@ -1123,9 +1406,6 @@ msgstr "Introduzione delle Analisi Cicliche"
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr ""
@@ -1138,6 +1418,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr "Gen"
+
+msgid "January"
+msgstr "Gennaio"
+
+msgid "Jul"
+msgstr "Lug"
+
+msgid "July"
+msgstr "Luglio"
+
+msgid "Jun"
+msgstr "Giu"
+
+msgid "June"
+msgstr "Giugno"
+
msgid "LFSStatus|Disabled"
msgstr "Disabilitato"
@@ -1159,16 +1457,16 @@ msgid "Last commit"
msgstr "Ultimo Commit"
msgid "Last edited %{date}"
-msgstr ""
+msgstr "Ultima modifica %{date}"
msgid "Last edited by %{name}"
-msgstr ""
+msgstr "Modificato da %{name}"
msgid "Last update"
-msgstr ""
+msgstr "Ultimo aggiornamento"
msgid "Last updated"
-msgstr ""
+msgstr "Ultimo aggiornamento"
msgid "LastPushEvent|You pushed to"
msgstr ""
@@ -1203,49 +1501,58 @@ msgid "Lock"
msgstr ""
msgid "Locked"
-msgstr ""
+msgstr "Bloccato"
msgid "Locked Files"
msgstr ""
msgid "Login"
-msgstr ""
+msgstr "Login"
+
+msgid "Mar"
+msgstr "Mar"
+
+msgid "March"
+msgstr "Marzo"
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "Mediano"
msgid "Members"
-msgstr ""
+msgstr "Membri"
msgid "Merge Requests"
-msgstr ""
+msgstr "Richieste di merge"
msgid "Merge events"
msgstr ""
msgid "Merge request"
-msgstr ""
+msgstr "Richiesta di merge"
msgid "Messages"
-msgstr ""
+msgstr "Messaggi"
msgid "MissingSSHKeyWarningLink|add an SSH key"
msgstr "aggiungi una chiave SSH"
msgid "Monitoring"
-msgstr ""
+msgstr "Monitoraggio"
msgid "More information is available|here"
-msgstr ""
+msgstr "Ulteriori informazioni sono disponibili | qui"
msgid "Multiple issue boards"
msgstr ""
msgid "New Cluster"
-msgstr ""
+msgstr "Nuovo Cluster"
msgid "New Issue"
msgid_plural "New Issues"
@@ -1258,14 +1565,20 @@ msgstr "Nuova pianificazione Pipeline"
msgid "New branch"
msgstr "Nuova Branch"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "Nuova directory"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "Nuovo file"
msgid "New group"
-msgstr ""
+msgstr "Nuovo gruppo"
msgid "New issue"
msgstr "Nuovo Issue"
@@ -1274,7 +1587,7 @@ msgid "New merge request"
msgstr "Nuova richiesta di merge"
msgid "New project"
-msgstr ""
+msgstr "Nuovo progetto"
msgid "New schedule"
msgstr "Nuova pianficazione"
@@ -1283,7 +1596,7 @@ msgid "New snippet"
msgstr "Nuovo snippet"
msgid "New subgroup"
-msgstr ""
+msgstr "Nuovo sottogruppo"
msgid "New tag"
msgstr "Nuovo tag"
@@ -1297,9 +1610,12 @@ msgstr "Nessuna Repository"
msgid "No schedules"
msgstr "Nessuna pianificazione"
-msgid "None"
+msgid "No time spent"
msgstr ""
+msgid "None"
+msgstr "Nessuno"
+
msgid "Not available"
msgstr "Non disponibile"
@@ -1361,55 +1677,70 @@ msgid "NotificationLevel|Watch"
msgstr "Osserva"
msgid "Notifications"
-msgstr ""
+msgstr "Notifiche"
+
+msgid "Nov"
+msgstr "Nov"
+
+msgid "November"
+msgstr "Novembre"
msgid "Number of access attempts"
-msgstr ""
+msgstr "Numero di tentativi di accesso raggiunto"
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr "Ott"
+
+msgid "October"
+msgstr "Ottobre"
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtra"
msgid "Only project members can comment."
+msgstr "Solo i membri del progetto possono commentare."
+
+msgid "Opened"
msgstr ""
msgid "OpenedNDaysAgo|Opened"
msgstr "Aperto"
msgid "Opens in a new window"
-msgstr ""
+msgstr "Si apre in una nuova finestra"
msgid "Options"
msgstr "Opzioni"
msgid "Overview"
-msgstr ""
+msgstr "Panoramica"
msgid "Owner"
-msgstr ""
+msgstr "Proprietario"
msgid "Pagination|Last »"
-msgstr ""
+msgstr "Ultima »"
msgid "Pagination|Next"
-msgstr ""
+msgstr "Successiva"
msgid "Pagination|Prev"
-msgstr ""
+msgstr "Precedente"
msgid "Pagination|« First"
-msgstr ""
+msgstr "« Prima"
msgid "Password"
-msgstr ""
+msgstr "Password"
msgid "People without permission will never get a notification and won\\'t be able to comment."
-msgstr ""
+msgstr "Le persone che non hanno il permesso non saranno notificate e non potranno commentare."
msgid "Pipeline"
-msgstr ""
+msgstr "Pipeline"
msgid "Pipeline Health"
msgstr "Stato della Pipeline"
@@ -1487,13 +1818,13 @@ msgid "Pipelines charts"
msgstr "Grafici pipeline"
msgid "Pipelines for last month"
-msgstr ""
+msgstr "Pipeline per il mese scorso"
msgid "Pipelines for last week"
-msgstr ""
+msgstr "Pipeline per la settimana scorsa"
msgid "Pipelines for last year"
-msgstr ""
+msgstr "Pipeline per l'ultimo anno"
msgid "Pipeline|all"
msgstr "tutto"
@@ -1507,56 +1838,59 @@ msgstr "con stadio"
msgid "Pipeline|with stages"
msgstr "con più stadi"
-msgid "Preferences"
+msgid "Please solve the reCAPTCHA"
msgstr ""
+msgid "Preferences"
+msgstr "Preferenze"
+
msgid "Private - Project access must be granted explicitly to each user."
-msgstr ""
+msgstr "Privato - L'accesso al progetto deve essere fornito esplicitamente ad ogni utente."
msgid "Private - The group and its projects can only be viewed by members."
-msgstr ""
+msgstr "Privato - Il gruppo e i suoi progetti possono essere visualizzati solo dai membri."
msgid "Profile"
-msgstr ""
+msgstr "Profilo"
msgid "Profiles|Account scheduled for removal."
-msgstr ""
+msgstr "Account pianificato per la rimozione."
msgid "Profiles|Delete Account"
-msgstr ""
+msgstr "Elimina account"
msgid "Profiles|Delete account"
-msgstr ""
+msgstr "Elimina account"
msgid "Profiles|Delete your account?"
-msgstr ""
+msgstr "Eliminare il tuo account?"
msgid "Profiles|Deleting an account has the following effects:"
msgstr ""
msgid "Profiles|Invalid password"
-msgstr ""
+msgstr "Password non valida"
msgid "Profiles|Invalid username"
-msgstr ""
+msgstr "Username non valido"
msgid "Profiles|Type your %{confirmationValue} to confirm:"
-msgstr ""
+msgstr "Inserisci il tuo %{confirmationValue} per confermare:"
msgid "Profiles|You don't have access to delete this user."
-msgstr ""
+msgstr "Non hai i permessi per eliminare questo utente."
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
-msgstr ""
+msgstr "Devi trasferire la proprietà o eliminare questi gruppi prima che tu possa eliminare l'account."
msgid "Profiles|Your account is currently an owner in these groups:"
-msgstr ""
+msgstr "Il tuo account è attualmente proprietario in questi gruppi:"
msgid "Profiles|your account"
-msgstr ""
+msgstr "il tuo account"
msgid "Project '%{project_name}' is in the process of being deleted."
-msgstr ""
+msgstr "Il progetto '%{project_name}' è in fase di eliminazione."
msgid "Project '%{project_name}' queued for deletion."
msgstr "Il Progetto '%{project_name}' in coda di eliminazione."
@@ -1571,7 +1905,7 @@ msgid "Project access must be granted explicitly to each user."
msgstr "L'accesso al progetto dev'esser fornito esplicitamente ad ogni utente"
msgid "Project details"
-msgstr ""
+msgstr "Dettagli del progetto"
msgid "Project export could not be deleted."
msgstr "L'esportazione del progetto non può essere eliminata."
@@ -1586,7 +1920,7 @@ msgid "Project export started. A download link will be sent by email."
msgstr "Esportazione del progetto iniziata. Un link di download sarà inviato via email."
msgid "ProjectActivityRSS|Subscribe"
-msgstr ""
+msgstr "Iscriviti"
msgid "ProjectFeature|Disabled"
msgstr "Disabilitato"
@@ -1612,9 +1946,15 @@ msgstr "Grafico"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr "Esegui subito una pipeline sulla branch di default"
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr "Problemi durante l'impostazione delle CI/CD JavaScript settings"
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1628,35 +1968,68 @@ msgid "ProjectSettings|Users can only push commits to this repository that were
msgstr ""
msgid "Projects"
-msgstr ""
+msgstr "Progetti"
msgid "ProjectsDropdown|Frequently visited"
-msgstr ""
+msgstr "Visitati di frequente"
msgid "ProjectsDropdown|Loading projects"
-msgstr ""
+msgstr "Caricamento progetti"
msgid "ProjectsDropdown|Projects you visit often will appear here"
-msgstr ""
+msgstr "I progetti che visiti spesso appariranno qui"
msgid "ProjectsDropdown|Search your projects"
-msgstr ""
+msgstr "Cerca tra i tuoi progetti"
msgid "ProjectsDropdown|Something went wrong on our end."
-msgstr ""
+msgstr "Qualcosa è andato storto dalla nostra parte."
msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr ""
+msgstr "Siamo spiacenti, non ci sono progetti che corrispondono alla tua ricerca"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
+msgstr "Questa feature richiede il supporto del localStorage del browser"
+
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr "Di default, Prometheus è in ascolto su ‘http://localhost:9090‘. Non è consigliabile cambiare l'indirizzo e la porta di default in quanto ciò potrebbe influenzare o causare conflitto con altri servizi in esecuzione sul server GitLab."
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr "Ricerco e configuro le metriche..."
+
+msgid "PrometheusService|Metrics"
+msgstr "Metriche"
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr "Le metriche sono configurate automaticamente e monitorate sulla base di una libreria di metriche di esportatori popolari."
+
+msgid "PrometheusService|Missing environment variable"
+msgstr "Variabile d'ambiente mancante"
+
+msgid "PrometheusService|Monitored"
+msgstr "Monitorato"
+
+msgid "PrometheusService|More information"
+msgstr "Ulteriori informazioni"
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr "Nessuna metrica è stata monitorata. Per iniziare a monitorare, rilascia su un ambiente."
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
msgstr ""
-msgid "Public - The group and any public projects can be viewed without any authentication."
+msgid "PrometheusService|Prometheus monitoring"
msgstr ""
-msgid "Public - The project can be accessed without any authentication."
+msgid "PrometheusService|View environments"
msgstr ""
+msgid "Public - The group and any public projects can be viewed without any authentication."
+msgstr "Pubblico - il gruppo e tutti i progetti pubblici possono essere visualizzati senza alcuna autenticazione."
+
+msgid "Public - The project can be accessed without any authentication."
+msgstr "Public - Chiunque può accedere a questo progetto senza alcuna autenticazione."
+
msgid "Push Rules"
msgstr ""
@@ -1727,13 +2100,13 @@ msgid "Revert this merge request"
msgstr "Ripristina questa richiesta di merge"
msgid "SSH Keys"
-msgstr ""
+msgstr "Chiavi SSH"
msgid "Save"
-msgstr ""
+msgstr "Salva"
msgid "Save changes"
-msgstr ""
+msgstr "Salva modifiche"
msgid "Save pipeline schedule"
msgstr "Salva pianificazione pipeline"
@@ -1747,6 +2120,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr "Pianificazione pipelines"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "Ricerca branches e tags"
@@ -1768,6 +2144,12 @@ msgstr "Seleziona una timezone"
msgid "Select target branch"
msgstr "Seleziona una branch di destinazione"
+msgid "Sep"
+msgstr "Set"
+
+msgid "September"
+msgstr "Settembre"
+
msgid "Service Templates"
msgstr ""
@@ -1787,7 +2169,7 @@ msgid "SetPasswordToCloneLink|set a password"
msgstr "imposta una password"
msgid "Settings"
-msgstr ""
+msgstr "Impostazioni"
msgid "Show parent pages"
msgstr ""
@@ -1800,24 +2182,39 @@ msgid_plural "Showing %d events"
msgstr[0] "Visualizza %d evento"
msgstr[1] "Visualizza %d eventi"
-msgid "Snippets"
+msgid "Sidebar|Change weight"
msgstr ""
-msgid "Something went wrong on our end."
+msgid "Sidebar|Edit"
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Sidebar|No"
msgstr ""
-msgid "Something went wrong while fetching the projects."
+msgid "Sidebar|None"
msgstr ""
-msgid "Something went wrong while fetching the registry list."
+msgid "Sidebar|Weight"
msgstr ""
-msgid "Sort by"
+msgid "Snippets"
+msgstr "Snippet"
+
+msgid "Something went wrong on our end."
+msgstr "Si è verificato un problema con il nostro server."
+
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
+msgid "Something went wrong while fetching the projects."
+msgstr "Qualcosa è andato storto durante il fetch dei progetti."
+
+msgid "Something went wrong while fetching the registry list."
+msgstr "Qualcosa è andato storto durante il recupero dell'elenco dei registri."
+
+msgid "Sort by"
+msgstr "Ordina per"
+
msgid "SortOptions|Access level, ascending"
msgstr ""
@@ -1849,7 +2246,7 @@ msgid "SortOptions|Last created"
msgstr ""
msgid "SortOptions|Last joined"
-msgstr ""
+msgstr "Ultimo che ha Joinato"
msgid "SortOptions|Last updated"
msgstr ""
@@ -1888,7 +2285,7 @@ msgid "SortOptions|Oldest created"
msgstr ""
msgid "SortOptions|Oldest joined"
-msgstr ""
+msgstr "Dal primo Joinato"
msgid "SortOptions|Oldest sign in"
msgstr ""
@@ -1914,9 +2311,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr "Codice Sorgente"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1935,6 +2338,9 @@ msgstr "inizia una %{new_merge_request} con queste modifiche"
msgid "Start the Runner!"
msgstr ""
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1955,6 +2361,75 @@ msgstr[1] ""
msgid "Tags"
msgstr ""
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "Branch di destinazione"
@@ -2036,6 +2511,9 @@ msgstr "Il valore falsato nel mezzo di una serie di dati osservati. ES: tra 3,5,
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2057,6 +2535,9 @@ msgstr "Questo significa che non è possibile effettuare push di codice fino a c
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Il tempo che impiega un issue per esser pianificato"
@@ -2205,15 +2686,27 @@ msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "Tempo Totale"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "Tempo totale di test per tutti i commits/merges"
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2250,6 +2743,9 @@ msgstr "Carica file"
msgid "UploadLink|click to upload"
msgstr "clicca per caricare"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr ""
@@ -2283,6 +2779,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 "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2412,12 +2911,6 @@ msgstr "Stai per rimuovere la relazione con il progetto sorgente %{forked_from_p
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Stai per trasferire %{project_name_with_namespace} ad un altro owner. Sei ASSOLUTAMENTE sicuro?"
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr "Puoi aggiungere files solo quando sei in una branch"
@@ -2457,6 +2950,9 @@ msgstr "Non sarai in grado di eseguire pull o push di codice tramite %{protocol}
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "Non sarai in grado di effettuare push o pull tramite SSH fino a che %{add_ssh_key_link} al tuo profilo"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2469,6 +2965,12 @@ msgstr "Il tuo nome"
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2494,6 +2996,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index 8d93a936be9..1314bad87fe 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-03 12:31-0400\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:40-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Japanese\n"
"Language: ja_JP\n"
@@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] ""
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr ""
@@ -109,9 +112,6 @@ msgstr ""
msgid "Add License"
msgstr "ライセンスを追加"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "SSHでプルやプッシュする場合は、プロフィールにSSH鍵を追加してください。"
-
msgid "Add new directory"
msgstr "新規ディレクトリを追加"
@@ -124,6 +124,15 @@ msgstr ""
msgid "All"
msgstr ""
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -133,6 +142,12 @@ msgstr ""
msgid "Applications"
msgstr ""
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "アーカイブ済みプロジェクト!(レポジトリーは読み取り専用です)"
@@ -160,6 +175,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "ドラッグ&ドロップまたは %{upload_link} でファイルを添付"
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -193,6 +214,9 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -257,6 +281,12 @@ msgstr "%{branch_name} ブランチが作成されました。
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "ブランチを検索"
@@ -404,6 +434,12 @@ msgstr "チャート"
msgid "Chat"
msgstr ""
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "このコミットをチェリーピック"
@@ -479,7 +515,40 @@ msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -503,21 +572,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -527,27 +629,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -560,7 +710,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -575,15 +731,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -599,9 +773,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -615,10 +795,6 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "コミット"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-
msgid "Commit Message"
msgstr ""
@@ -700,6 +876,15 @@ msgstr "貢献者向けガイド"
msgid "Contributors"
msgstr "貢献者"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -727,6 +912,9 @@ msgstr "ディレクトリを作成"
msgid "Create empty bare repository"
msgstr "空のbareレポジトリーを作成"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -754,6 +942,9 @@ msgstr "タグ"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "個人用アクセストークンを作成"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Cron のタイムゾーン"
@@ -799,6 +990,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "Cron 構文でカスタムなパターンを指定する"
@@ -872,6 +1069,72 @@ msgstr "パイプラインスケジュール %{id} を編集"
msgid "Emails"
msgstr ""
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -911,6 +1174,12 @@ msgstr "オーナーを変更できませんでした"
msgid "Failed to remove the pipeline schedule"
msgstr "パイプラインスケジュールを削除できませんでした"
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -957,6 +1226,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1020,9 +1304,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1053,6 +1334,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -1111,9 +1395,6 @@ msgstr "サイクル分析のご紹介"
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr ""
@@ -1126,6 +1407,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "無効"
@@ -1197,9 +1496,18 @@ msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "中央値"
@@ -1243,9 +1551,15 @@ msgstr "新規パイプラインスケジュール"
msgid "New branch"
msgstr "新規ブランチ"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "新規ディレクトリ"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "新規ファイル"
@@ -1282,6 +1596,9 @@ msgstr "レポジトリーはありません"
msgid "No schedules"
msgstr "スケジュールなし"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1348,18 +1665,33 @@ msgstr "すべて通知"
msgid "Notifications"
msgstr ""
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "フィルター"
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "オープンされたのは"
@@ -1492,6 +1824,9 @@ msgstr "ステージあり"
msgid "Pipeline|with stages"
msgstr "ステージあり"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1597,9 +1932,15 @@ msgstr "ネットワークグラフ"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1636,6 +1977,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1732,6 +2106,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr "パイプラインスケジューリング"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "ブランチまたはタグを検索"
@@ -1753,6 +2130,12 @@ msgstr "タイムゾーンを選択"
msgid "Select target branch"
msgstr "ターゲットブランチを選択"
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1784,13 +2167,28 @@ msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "%d のイベントを表示中"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1898,9 +2296,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr "ソースコード"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1919,6 +2323,9 @@ msgstr "この変更で %{new_merge_request} を作成する"
msgid "Start the Runner!"
msgstr ""
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1938,6 +2345,75 @@ msgstr[0] "タグ"
msgid "Tags"
msgstr "タグ"
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "ターゲットブランチ"
@@ -2019,6 +2495,9 @@ msgstr "得られた一連のデータを小さい順に並べたときに中央
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2040,6 +2519,9 @@ msgstr "空レポジトリーを作成または既存レポジトリーをイン
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "課題が計画されるまでの時間"
@@ -2186,15 +2668,27 @@ msgstr[0] "分"
msgid "Time|s"
msgstr "秒"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "合計時間"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "すべてのコミット/マージの合計テスト時間"
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2231,6 +2725,9 @@ msgstr "ファイルをアップロード"
msgid "UploadLink|click to upload"
msgstr "クリックしてアップロード"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr ""
@@ -2264,6 +2761,9 @@ msgstr "このデータを参照したいですか?アクセスするには管
msgid "We don't have enough data to show this stage."
msgstr "データ不足のため、このステージの表示はできません。"
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2393,12 +2893,6 @@ msgstr "元のプロジェクト (%{forked_from_project}) とのリレーショ
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "%{project_name_with_namespace} プロジェクトを別のオーナーに移譲しようとしています。本当によろしいですか?"
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr "ファイルを追加するには、どこかのブランチにいなければいけません"
@@ -2438,6 +2932,9 @@ msgstr "%{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 "%{add_ssh_key_link} をプロファイルに追加していないので、プロジェクトにソースコードをプッシュ、プルできません"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2450,6 +2947,12 @@ msgstr "名前"
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2473,6 +2976,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index d6c1ff2deeb..9ec3d395c15 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-03 12:31-0400\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:41-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Korean\n"
"Language: ko_KR\n"
@@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] ""
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "설치 방법에 대한 정보를 얻기 위해 %{link} 를 체크아웃하세요."
@@ -109,9 +112,6 @@ msgstr ""
msgid "Add License"
msgstr "라이선스 추가"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "프로필에 SSH 키를 추가하여 SSH를 통해 Pull 하거나 Push합니다."
-
msgid "Add new directory"
msgstr "새 디렉토리 추가"
@@ -124,6 +124,15 @@ msgstr ""
msgid "All"
msgstr "전체"
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -133,6 +142,12 @@ msgstr ""
msgid "Applications"
msgstr ""
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "프로젝트가 보관되었습니다! 저장소는 읽기만 가능합니다."
@@ -160,6 +175,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "드래그 & 드롭 또는 %{upload_link}"
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -193,6 +214,9 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -257,6 +281,12 @@ msgstr "%{branch_name} 브랜치가 생성되었습니다. 자
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "브랜치 검색"
@@ -404,6 +434,12 @@ msgstr "차트"
msgid "Chat"
msgstr ""
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "이 커밋을 Cherry-pick"
@@ -479,7 +515,40 @@ msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -503,21 +572,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -527,27 +629,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -560,7 +710,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -575,15 +731,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -599,9 +773,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -615,10 +795,6 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "커밋"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-
msgid "Commit Message"
msgstr ""
@@ -700,6 +876,15 @@ msgstr "기여에 대한 안내"
msgid "Contributors"
msgstr "기여해 주신 분들"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -727,6 +912,9 @@ msgstr "디렉토리 만들기"
msgid "Create empty bare repository"
msgstr "빈 bare 저장소 만들기"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -754,6 +942,9 @@ msgstr "태그"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "개인 액세스 토큰 만들기"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Cron 시간대"
@@ -799,6 +990,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "cron 구문을 사용하여 사용자 정의 패턴 정의"
@@ -872,6 +1069,72 @@ msgstr "파이프라인 스케줄 편집 %{id}"
msgid "Emails"
msgstr ""
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "모든 값을 기준으로 필터"
@@ -911,6 +1174,12 @@ msgstr "소유자를 변경하지 못했습니다"
msgid "Failed to remove the pipeline schedule"
msgstr "파이프라인 스케줄을 제거하지 못했습니다."
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -957,6 +1226,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1020,9 +1304,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1053,6 +1334,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr "헬스 체크"
@@ -1111,9 +1395,6 @@ msgstr "Cycle Analytics 소개"
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr "이슈 이벤트"
@@ -1126,6 +1407,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "Disabled"
@@ -1197,9 +1496,18 @@ msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "중앙값"
@@ -1243,9 +1551,15 @@ msgstr "새로운 파이프라인 일정"
msgid "New branch"
msgstr "새 브랜치"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "새 디렉토리"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "새 파일"
@@ -1282,6 +1596,9 @@ msgstr "저장소 없음"
msgid "No schedules"
msgstr "일정 없음"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1348,18 +1665,33 @@ msgstr "Watch"
msgid "Notifications"
msgstr ""
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "필터"
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "열린"
@@ -1492,6 +1824,9 @@ msgstr "스테이징"
msgid "Pipeline|with stages"
msgstr "스테이징"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1597,9 +1932,15 @@ msgstr "그래프"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1636,6 +1977,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1732,6 +2106,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr "파이프라인 스케줄링"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "브랜치 및 태그 검색"
@@ -1753,6 +2130,12 @@ msgstr "시간대 선택"
msgid "Select target branch"
msgstr "대상 브랜치 선택"
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1784,13 +2167,28 @@ msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "%d 개의 이벤트 표시 중"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1898,9 +2296,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr "소스 코드"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1919,6 +2323,9 @@ msgstr "이 변경 사항으로 %{new_merge_request} 을 시작하십시오."
msgid "Start the Runner!"
msgstr "Runner 시작!"
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1938,6 +2345,75 @@ msgstr[0] "태그"
msgid "Tags"
msgstr "태그 "
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "대상 브랜치"
@@ -2019,6 +2495,9 @@ msgstr "값은 일련의 관측 값 중점에 있습니다. 예를 들어, 3, 5,
msgid "There are problems accessing Git storage: "
msgstr "git storage에 접근하는데 문제가 발생했습니다. "
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2040,6 +2519,9 @@ msgstr "즉, 빈 저장소를 만들거나 기존 저장소를 가져올 때까
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "이슈가 스케줄되기 전의 시간"
@@ -2186,15 +2668,27 @@ msgstr[0] "분"
msgid "Time|s"
msgstr "초"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "시간 합계:"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "모든 커밋 / 머지의 총 테스트 시간"
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2231,6 +2725,9 @@ msgstr "파일 업로드"
msgid "UploadLink|click to upload"
msgstr "업로드하려면 클릭하십시오."
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr "설정 중에 다음 등록 토큰 이용 : "
@@ -2264,6 +2761,9 @@ msgstr "이 데이터를 보고 싶은가요? 관리자에게 액세스 권한
msgid "We don't have enough data to show this stage."
msgstr "이 단계를 보여주기에 충분한 데이터가 없습니다."
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2393,12 +2893,6 @@ msgstr "포크 관계를 소스 프로젝트 %{forked_from_project}에 대해
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "%{project_name_with_namespace}을 다른 소유자에게 이전하려고합니다. \"정말로\" 확실합니까?"
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr "브랜치에 있을 때에만 파일을 추가 할 수 있습니다."
@@ -2438,6 +2932,9 @@ msgstr "당신의 계정에 %{set_password_link} 을 하기 전에는 %{protocol
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "당신의 프로필에 %{add_ssh_key_link} 를 하기 전에는 SSH를 통해 프로젝트 코드를 Pull 하거나 Push 할 수 없습니다"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2450,6 +2947,12 @@ msgstr "귀하의 이름"
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2473,6 +2976,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index 68d1f809bb4..0abb727037c 100644
--- a/locale/nl_NL/gitlab.po
+++ b/locale/nl_NL/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-03 12:31-0400\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:42-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
@@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts
msgstr[0] ""
msgstr[1] ""
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(bekijk de %{link} voor meer info over hoe je het kan installeren)."
@@ -101,7 +104,7 @@ msgid "Activity"
msgstr "Activiteit"
msgid "Add"
-msgstr "Voeg toe"
+msgstr ""
msgid "Add Changelog"
msgstr "Changelog toevoegen"
@@ -115,9 +118,6 @@ msgstr ""
msgid "Add License"
msgstr "Licentie toevoegen"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr ""
-
msgid "Add new directory"
msgstr "Nieuwe map toevoegen"
@@ -130,6 +130,15 @@ msgstr ""
msgid "All"
msgstr "Alles"
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -139,6 +148,12 @@ msgstr "Uiterlijk"
msgid "Applications"
msgstr "Applicaties"
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr ""
@@ -166,6 +181,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr ""
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -199,8 +220,11 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
-msgstr "Facturatie"
+msgstr ""
msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
msgstr ""
@@ -264,6 +288,12 @@ msgstr ""
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "BranchSwitcherPlaceholder|Zoek branches"
@@ -411,6 +441,12 @@ msgstr "Grafieken"
msgid "Chat"
msgstr "Chat"
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Cherry-pick deze commit"
@@ -486,7 +522,40 @@ msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -510,21 +579,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -534,27 +636,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -567,7 +717,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -582,15 +738,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -606,9 +780,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -623,11 +803,6 @@ msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Commit Message"
msgstr ""
@@ -709,6 +884,15 @@ msgstr ""
msgid "Contributors"
msgstr ""
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -736,6 +920,9 @@ msgstr "Maak map aan"
msgid "Create empty bare repository"
msgstr ""
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -763,6 +950,9 @@ msgstr ""
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr ""
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr ""
@@ -808,6 +998,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr ""
@@ -882,6 +1078,72 @@ msgstr ""
msgid "Emails"
msgstr ""
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -921,6 +1183,12 @@ msgstr ""
msgid "Failed to remove the pipeline schedule"
msgstr ""
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -968,6 +1236,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1031,9 +1314,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1064,6 +1344,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -1123,9 +1406,6 @@ msgstr ""
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr ""
@@ -1138,6 +1418,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr ""
@@ -1211,9 +1509,18 @@ msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr ""
@@ -1258,9 +1565,15 @@ msgstr ""
msgid "New branch"
msgstr ""
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr ""
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr ""
@@ -1297,6 +1610,9 @@ msgstr ""
msgid "No schedules"
msgstr ""
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1363,18 +1679,33 @@ msgstr ""
msgid "Notifications"
msgstr ""
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr ""
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Geopend"
@@ -1507,6 +1838,9 @@ msgstr ""
msgid "Pipeline|with stages"
msgstr ""
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1612,9 +1946,15 @@ msgstr ""
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1651,6 +1991,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1747,6 +2120,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr ""
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr ""
@@ -1768,6 +2144,12 @@ msgstr ""
msgid "Select target branch"
msgstr ""
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1914,9 +2311,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr ""
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1935,6 +2338,9 @@ msgstr ""
msgid "Start the Runner!"
msgstr ""
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1955,6 +2361,75 @@ msgstr[1] ""
msgid "Tags"
msgstr ""
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -2036,6 +2511,9 @@ msgstr ""
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2057,6 +2535,9 @@ msgstr ""
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr ""
@@ -2205,15 +2686,27 @@ msgstr[1] ""
msgid "Time|s"
msgstr "s"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr ""
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr ""
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2250,6 +2743,9 @@ msgstr ""
msgid "UploadLink|click to upload"
msgstr ""
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr ""
@@ -2283,6 +2779,9 @@ msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2412,12 +2911,6 @@ msgstr ""
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr ""
@@ -2457,6 +2950,9 @@ msgstr ""
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr ""
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2469,6 +2965,12 @@ msgstr ""
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2494,6 +2996,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index c48909540b1..5b65c42097e 100644
--- a/locale/pl_PL/gitlab.po
+++ b/locale/pl_PL/gitlab.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab-ee\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-20 11:16-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:41-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Polish\n"
"Language: pl_PL\n"
@@ -61,6 +61,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr ""
@@ -121,9 +124,6 @@ msgstr ""
msgid "Add License"
msgstr ""
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr ""
-
msgid "Add new directory"
msgstr ""
@@ -136,6 +136,15 @@ msgstr ""
msgid "All"
msgstr ""
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -145,6 +154,12 @@ msgstr ""
msgid "Applications"
msgstr ""
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr ""
@@ -172,6 +187,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr ""
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -205,6 +226,9 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -271,6 +295,12 @@ msgstr ""
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr ""
@@ -418,6 +448,12 @@ msgstr ""
msgid "Chat"
msgstr ""
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr ""
@@ -493,7 +529,40 @@ msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -517,21 +586,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -541,27 +643,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -574,7 +724,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -589,15 +745,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -613,9 +787,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -631,12 +811,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Commit Message"
msgstr ""
@@ -718,6 +892,15 @@ msgstr ""
msgid "Contributors"
msgstr ""
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -745,6 +928,9 @@ msgstr ""
msgid "Create empty bare repository"
msgstr ""
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -772,6 +958,9 @@ msgstr ""
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr ""
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr ""
@@ -817,6 +1006,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr ""
@@ -892,6 +1087,72 @@ msgstr ""
msgid "Emails"
msgstr ""
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr ""
@@ -931,6 +1192,12 @@ msgstr ""
msgid "Failed to remove the pipeline schedule"
msgstr ""
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -979,6 +1246,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1042,9 +1324,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1075,6 +1354,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr ""
@@ -1135,9 +1417,6 @@ msgstr ""
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr ""
@@ -1150,6 +1429,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr ""
@@ -1225,9 +1522,18 @@ msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr ""
@@ -1273,9 +1579,15 @@ msgstr ""
msgid "New branch"
msgstr ""
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr ""
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr ""
@@ -1312,6 +1624,9 @@ msgstr ""
msgid "No schedules"
msgstr ""
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1378,18 +1693,33 @@ msgstr ""
msgid "Notifications"
msgstr ""
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr ""
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr ""
@@ -1522,6 +1852,9 @@ msgstr ""
msgid "Pipeline|with stages"
msgstr ""
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1627,9 +1960,15 @@ msgstr ""
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1666,6 +2005,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1762,6 +2134,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr ""
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr ""
@@ -1783,6 +2158,12 @@ msgstr ""
msgid "Select target branch"
msgstr ""
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1816,13 +2197,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1930,9 +2326,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr ""
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1951,6 +2353,9 @@ msgstr ""
msgid "Start the Runner!"
msgstr ""
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1972,6 +2377,75 @@ msgstr[2] ""
msgid "Tags"
msgstr ""
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -2053,6 +2527,9 @@ msgstr ""
msgid "There are problems accessing Git storage: "
msgstr ""
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2074,6 +2551,9 @@ msgstr ""
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr ""
@@ -2224,15 +2704,27 @@ msgstr[2] ""
msgid "Time|s"
msgstr ""
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr ""
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr ""
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2269,6 +2761,9 @@ msgstr ""
msgid "UploadLink|click to upload"
msgstr ""
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr ""
@@ -2302,6 +2797,9 @@ msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2431,12 +2929,6 @@ msgstr ""
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr ""
@@ -2476,6 +2968,9 @@ msgstr ""
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr ""
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2488,6 +2983,12 @@ msgstr ""
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2515,6 +3016,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 78e0967c3bc..9fe1cc3c11a 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-18 12:51-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:41-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Portuguese, Brazilian\n"
"Language: pt_BR\n"
@@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts
msgstr[0] "%{storage_name}: falha na tentativa de acesso ao storage no host:"
msgstr[1] "%{storage_name}: %{failed_attempts} falhas de acesso ao storage:"
+msgid "%{text} is available"
+msgstr "%{text} está disponível"
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(veja o %{link} para informações de como instalar)."
@@ -110,14 +113,11 @@ msgid "Add Contribution guide"
msgstr "Adicionar Guia de contribuição"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
-msgstr "Adicione o grupo de Webhooks e GitLab Enterprise Edition."
+msgstr "Adicione o Webhooks de Grupos e GitLab Enterprise Edition."
msgid "Add License"
msgstr "Adicionar Licença"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "Adicionar chave SSH ao seu perfil para fazer pull ou push via SSH."
-
msgid "Add new directory"
msgstr "Adicionar novo diretório"
@@ -130,6 +130,15 @@ msgstr "Configurações avançadas"
msgid "All"
msgstr "Todos"
+msgid "An error occurred when toggling the notification subscription"
+msgstr "Erro ao modificar notificação de assinatura"
+
+msgid "An error occurred when updating the issue weight"
+msgstr "Um erro aconteceu ao atualizar o peso da issue"
+
+msgid "An error occurred while fetching sidebar data"
+msgstr "Erro ao recuperar informações da barra lateral"
+
msgid "An error occurred. Please try again."
msgstr "Ocorreu um erro. Tente novamente."
@@ -139,6 +148,12 @@ msgstr "Aparência"
msgid "Applications"
msgstr "Aplicações"
+msgid "Apr"
+msgstr "Abr"
+
+msgid "April"
+msgstr "Abril"
+
msgid "Archived project! Repository is read-only"
msgstr "Projeto arquivado! O repositório é somente leitura"
@@ -166,6 +181,12 @@ msgstr "Artefatos"
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Para anexar arquivo, arraste e solte ou %{upload_link}"
+msgid "Aug"
+msgstr "Ago"
+
+msgid "August"
+msgstr "Agosto"
+
msgid "Authentication Log"
msgstr "Log de autenticação"
@@ -199,6 +220,9 @@ msgstr "Saiba mais em %{link_to_documentation}"
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr "Você pode ativar %{link_to_settings} para esse projeto."
+msgid "Available"
+msgstr "Disponível"
+
msgid "Billing"
msgstr "Cobrança"
@@ -218,28 +242,28 @@ msgid "BillingPlans|Downgrade"
msgstr "Downgrade"
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
-msgstr "Aprenda mais sobre cada plano lendo nossa %{faq_link}."
+msgstr "Saiba mais sobre cada plano lendo nossa %{faq_link}."
msgid "BillingPlans|Manage plan"
msgstr "Gerenciar plano"
msgid "BillingPlans|Please contact %{customer_support_link} in that case."
-msgstr "Por favor contacte o %{customer_support_link} para resolver seu caso."
+msgstr "Por favor, entre em contato com %{customer_support_link} para resolver seu caso."
msgid "BillingPlans|See all %{plan_name} features"
-msgstr "Veja todas as funcionalidades do seu plano %{plan_name}"
+msgstr "Veja todas as funcionalidades de %{plan_name}"
msgid "BillingPlans|This group uses the plan associated with its parent group."
msgstr "Esse grupo utiliza o plano associado ao seu grupo pai."
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
-msgstr "Para gerenciar o plano para esse grupo, visite a sessão de cobrança de %{parent_billing_page_link}."
+msgstr "Para gerenciar o plano desse grupo, visite a sessão de cobrança de %{parent_billing_page_link}."
msgid "BillingPlans|Upgrade"
-msgstr "Atualizar"
+msgstr "Upgrade"
msgid "BillingPlans|You are currently on the %{plan_link} plan."
-msgstr "Vocês está utilizando o plano %{plan_link}."
+msgstr "Você está atualmente no plano %{plan_link}."
msgid "BillingPlans|frequently asked questions"
msgstr "perguntas frequentes"
@@ -264,6 +288,12 @@ msgstr "O branch %{branch_name} foi criado. Para configurar o d
msgid "Branch has changed"
msgstr "Branch foi alterado"
+msgid "Branch is already taken"
+msgstr "Branch já utilizada"
+
+msgid "Branch name"
+msgstr "Nome da branch"
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Procurar por branches"
@@ -325,7 +355,7 @@ msgid "Branches|Sort by"
msgstr "Ordernar por"
msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart."
-msgstr "A branch não pode ser atualizada automaticamente porque diverge do seu upstream."
+msgstr "O branch não pode ser atualizado automaticamente porque diverge do seu upstream."
msgid "Branches|The default branch cannot be deleted"
msgstr "A branch padrão não pode ser apagada"
@@ -340,13 +370,13 @@ msgid "Branches|To confirm, type %{branch_name_confirmation}:"
msgstr "Para confirmar, digite %{branch_name_confirmation}:"
msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
-msgstr "Para descartar as mudanças locais e sobrescrever a branch com a versão de upstream, apague-o aqui e escolha 'Atualizar agora', acima."
+msgstr ""
msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
msgstr "Você irá apagar irreparavelmente a branch protegida '%{branch_name}'."
msgid "Branches|diverged from upstream"
-msgstr "divergiu do upstream"
+msgstr ""
msgid "Branches|merged"
msgstr "merge realizado"
@@ -388,7 +418,7 @@ msgid "Cancel edit"
msgstr "Cancelar edição"
msgid "Change Weight"
-msgstr "Mudar peso"
+msgstr "Alterar peso"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Pick para um branch"
@@ -411,6 +441,12 @@ msgstr "Gráficos"
msgid "Chat"
msgstr "Bate-papo"
+msgid "Checking %{text} availability…"
+msgstr "Verificando disponibilidade de %{text}…"
+
+msgid "Checking branch availability..."
+msgstr "Verificando disponibilidade de branch..."
+
msgid "Cherry-pick this commit"
msgstr "Cherry-pick esse commit"
@@ -418,7 +454,7 @@ msgid "Cherry-pick this merge request"
msgstr "Cherry-pick esse merge request"
msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all."
-msgstr "Escolha quais os grupos que você deseja replicar para este nó secundário. Deixe em branco para replicar todos."
+msgstr "Escolha quais grupos você deseja replicar para este nó secundário. Deixe em branco para replicar tudo."
msgid "CiStatusLabel|canceled"
msgstr "cancelado"
@@ -486,8 +522,41 @@ msgstr "Fechar"
msgid "Cluster"
msgstr "Cluster"
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
-msgstr "Um %{link_to_container_project} deve ter sido criado com essa conta"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr "%{appList} foi instalado no seu cluster"
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr "%{boldNotice} isso irá adicionar recursos extras como balanceamento de carga, que acarretará em custos adicionais. Veja %{pricingLink}"
+
+msgid "ClusterIntegration|API URL"
+msgstr "API URL"
+
+msgid "ClusterIntegration|Active"
+msgstr "Ativo"
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr "Adicionar um cluster existente"
+
+msgid "ClusterIntegration|Add cluster"
+msgstr "Adicionar cluster"
+
+msgid "ClusterIntegration|All"
+msgstr "Tudo"
+
+msgid "ClusterIntegration|Applications"
+msgstr "Aplicações"
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr "Certificado CA"
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr "Pacote de autoridade certificadora (Formato PEM)"
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr "Escolher como configurar a integração de cluster"
+
+msgid "ClusterIntegration|Cluster"
+msgstr "Cluster"
msgid "ClusterIntegration|Cluster details"
msgstr "Detalhes do cluster"
@@ -505,56 +574,137 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab
msgstr "Integração do cluster está ativada para esse projeto. Desabilitar a integração não afetará seu cluster, mas desligará temporariamente a conexão do Gitlab com ele."
msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..."
-msgstr "O cluster está sendo criado no Google Kubernetes Engine..."
+msgstr "O Cluster está sendo criado no Google Kubernetes Engine..."
msgid "ClusterIntegration|Cluster name"
msgstr "Nome do cluster"
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
-msgstr "O cluster foi criado com sucesso no Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr "Clusters permitem que você utilize review apps, faça deploy de suas aplicações, rode pipelines, e muito mais de um jeito simples. %{link_to_help_page}"
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr "Copiar URL da API"
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr "Copiar certificado CA"
+
+msgid "ClusterIntegration|Copy Token"
+msgstr "Copiar token"
msgid "ClusterIntegration|Copy cluster name"
msgstr "Copiar nome do cluster"
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr "Criar um novo cluster do Google Engine pelo GitLab"
+
msgid "ClusterIntegration|Create cluster"
msgstr "Criar cluster"
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
-msgstr "Criar novo cluster no Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr "Criar no GKE"
msgid "ClusterIntegration|Enable cluster integration"
msgstr "Ativar integração com o cluster"
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr "Insira os detalhes para o cluster Kubernetes existente"
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr "Insira os detalhes para seu cluster"
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr "Padrão de ambiente"
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr "Preços do GKE"
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr "Gitlab Runner"
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr "ID do projeto no Google Cloud Platform"
msgid "ClusterIntegration|Google Kubernetes Engine"
-msgstr "Google Kubernetes Engine"
+msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
-msgstr "Projeto no Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Helm Tiller"
+msgstr "Helm Tiller"
+
+msgid "ClusterIntegration|Inactive"
+msgstr "Inativo"
+
+msgid "ClusterIntegration|Ingress"
+msgstr "Ingressar"
+
+msgid "ClusterIntegration|Install"
+msgstr "Instalar"
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr "Instalar aplicações no seu cluster. Leia mais em %{helpLink}"
+
+msgid "ClusterIntegration|Installed"
+msgstr "Instalado"
+
+msgid "ClusterIntegration|Installing"
+msgstr "Instalando"
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr "Integrar cluster de automação"
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "Leia mais sobre %{link_to_documentation}"
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr "Ler mais sobre clusters"
+
msgid "ClusterIntegration|Machine type"
msgstr "Tipo de máquina"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr "Confira se sua conta %{link_to_requirements} para criar clusters"
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
-msgstr "Gerenciar integração de cluster com o projeto no GitLab"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
+msgstr "Gerenciar cluster de integração no projeto do GitLab"
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr "Gerencie seu cluster visitando %{link_gke}"
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr "Múltiplos clusters estão disponíveis no GitLab Enterprise Premium e Ultimate"
+
+msgid "ClusterIntegration|Note:"
+msgstr "Nota:"
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Número de nós"
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr "Por favor, insira informações de acesso para seu cluster. Se precisar de ajuda, você pode ler %{link_to_help_page} em cluster"
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr "Por favor, tenha certeza que sua conta no Google cumpre com os requisitos:"
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr "Problema ao configurar o cluster"
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr "Problema ao configurar a lista de cluster"
+
+msgid "ClusterIntegration|Project ID"
+msgstr "ID do projeto"
+
+msgid "ClusterIntegration|Project namespace"
+msgstr "Namespace do projeto"
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr "Namespace do projeto (opcional, único)"
@@ -567,8 +717,14 @@ msgstr "Remover integração com cluster"
msgid "ClusterIntegration|Remove integration"
msgstr "Remover integração"
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
-msgstr "Remover integração com o cluster irá apagar a configuração de cluster que você adicionou à esse projeto. Não excluirá seu projeto."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr "Solicitação para início de instalação falhou"
+
+msgid "ClusterIntegration|Save changes"
+msgstr "Salvar alterações"
msgid "ClusterIntegration|See and edit the details for your cluster"
msgstr "Ver e editar os detalhes para seu cluster"
@@ -582,33 +738,57 @@ msgstr "Ver seus projetos"
msgid "ClusterIntegration|See zones"
msgstr "Ver zonas"
+msgid "ClusterIntegration|Service token"
+msgstr "Token de serviço"
+
+msgid "ClusterIntegration|Show"
+msgstr "Mostrar"
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr "Alguma coisa deu errado do nosso lado."
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
-msgstr "Algo deu errado ao criar seu cluster no Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr "Algo deu errado ao instalar %{title}"
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr "Não há clusters para mostrar"
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr "Essa conta precisa de permissão para criar um cluster no %{link_to_container_project} especificado."
msgid "ClusterIntegration|Toggle Cluster"
msgstr "Alternar cluster"
+msgid "ClusterIntegration|Token"
+msgstr "Token"
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Com um cluster associado à esse projeto, você pode usar revisão de apps, fazer deploy de suas aplicações, rodar suas pipelines e muito mais de um jeito simples."
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
-msgstr "Sua conta precisa ter %{link_to_kubernetes_engine}"
+msgstr ""
msgid "ClusterIntegration|Zone"
msgstr "Zona"
msgid "ClusterIntegration|access to Google Kubernetes Engine"
-msgstr "Acesso ao Google Kubernetes Engine"
+msgstr ""
msgid "ClusterIntegration|cluster"
msgstr "cluster"
+msgid "ClusterIntegration|documentation"
+msgstr "documentação"
+
msgid "ClusterIntegration|help page"
msgstr "ajuda"
+msgid "ClusterIntegration|installing applications"
+msgstr "Instalando aplicações"
+
msgid "ClusterIntegration|meets the requirements"
msgstr "atende aos requisitos"
@@ -623,11 +803,6 @@ msgid_plural "Commits"
msgstr[0] "Commit"
msgstr[1] "Commits"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] "Commit %d arquivo"
-msgstr[1] "Commit %d arquivos"
-
msgid "Commit Message"
msgstr "Mensagem de Commit"
@@ -709,14 +884,23 @@ msgstr "Guia de contribuição"
msgid "Contributors"
msgstr "Contribuidores"
+msgid "ContributorsPage|Building repository graph."
+msgstr "Gerando gráfico do repositório."
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr "Commits à %{branch_name}, excluindo commits de merge. Limitado à 6000 commits."
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr "Por favor, espere um momento, essa página será atualizada automaticamente."
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
-msgstr "Controle a concorrência máxima de LFS/preenchimento de anexos para o nó secundário"
+msgstr ""
msgid "Control the maximum concurrency of repository backfill for this secondary node"
-msgstr "Controle a concorrência máxima de preenchimento de repositórios para o nó secundário"
+msgstr ""
msgid "Copy SSH public key to clipboard"
-msgstr "Copiar chave SSH pública para área de transferência"
+msgstr ""
msgid "Copy URL to clipboard"
msgstr "Copiar URL para área de transferência"
@@ -736,6 +920,9 @@ msgstr "Criar diretório"
msgid "Create empty bare repository"
msgstr "Criar repositório bruto vazio"
+msgid "Create epic"
+msgstr "Criar épico"
+
msgid "Create file"
msgstr "Criar arquivo"
@@ -763,6 +950,9 @@ msgstr "Tag"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "criar um token de acesso pessoal"
+msgid "Creating epic"
+msgstr "Criando épico"
+
msgid "Cron Timezone"
msgstr "Fuso horário do cron"
@@ -808,6 +998,12 @@ msgstr "Todos"
msgid "DashboardProjects|Personal"
msgstr "Pessoal"
+msgid "Dec"
+msgstr "Dez"
+
+msgid "December"
+msgstr "Dezembro"
+
msgid "Define a custom pattern with cron syntax"
msgstr "Defina um padrão personalizado utilizando a sintaxe do cron"
@@ -826,7 +1022,7 @@ msgid "Description"
msgstr "Descrição"
msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "Modelos de descrição permitem que você defina modelos de contextos específicos para issue e descrição de merge requests para seu projeto."
+msgstr "Modelos de descrição permitem que você defina modelos de contextos específicos para issue e campos de descrição de merge requests para seu projeto."
msgid "Details"
msgstr "Detalhes"
@@ -882,6 +1078,72 @@ msgstr "Alterar Agendamento do Pipeline %{id}"
msgid "Emails"
msgstr "Emails"
+msgid "Environments|An error occurred while fetching the environments."
+msgstr "Um erro ocorreu ao recuperar ambientes."
+
+msgid "Environments|An error occurred while making the request."
+msgstr "Um erro ocorreu ao fazer a requisição."
+
+msgid "Environments|Commit"
+msgstr "Commit"
+
+msgid "Environments|Deployment"
+msgstr "Deploy"
+
+msgid "Environments|Environment"
+msgstr "Ambiente"
+
+msgid "Environments|Environments"
+msgstr "Ambientes"
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr "Ambientes são lugares onde códigos são implantados (deploy), como homologação ou produção."
+
+msgid "Environments|Job"
+msgstr "Job"
+
+msgid "Environments|New environment"
+msgstr "Novo ambiente"
+
+msgid "Environments|No deployments yet"
+msgstr "Nenhum deploy"
+
+msgid "Environments|Open"
+msgstr "Abrir"
+
+msgid "Environments|Re-deploy"
+msgstr "Refazer"
+
+msgid "Environments|Read more about environments"
+msgstr "Ler mais sobre ambiente"
+
+msgid "Environments|Rollback"
+msgstr "Rollback"
+
+msgid "Environments|Show all"
+msgstr "Mostrar tudo"
+
+msgid "Environments|Updated"
+msgstr "Atualizado"
+
+msgid "Environments|You don't have any environments right now."
+msgstr "Você não tem nenhum ambiente."
+
+msgid "Epic will be removed! Are you sure?"
+msgstr "Épico será removido! Tem certeza?"
+
+msgid "Epics"
+msgstr "Épicos"
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr "Epics permite que você gerencie seu portfólio de projetos de forma mais eficiente e com menos esforço"
+
+msgid "Error creating epic"
+msgstr "Erro ao criar épico"
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr "Erro ao alterar configuração de notificação de assinatura"
+
msgid "EventFilterBy|Filter by all"
msgstr "EventFilterBy|Filtrar por tudo"
@@ -921,6 +1183,12 @@ msgstr "Erro ao alterar o proprietário"
msgid "Failed to remove the pipeline schedule"
msgstr "Erro ao excluir o agendamento do pipeline"
+msgid "Feb"
+msgstr "Fev"
+
+msgid "February"
+msgstr "Fevereiro"
+
msgid "File name"
msgstr "Nome do arquivo"
@@ -968,17 +1236,32 @@ msgstr "Chaves GPG"
msgid "Geo Nodes"
msgstr "Nós de geo"
+msgid "GeoNodeSyncStatus|Failed"
+msgstr "Falhou"
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr "Nó está falhando ou quebrado."
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr "Nó está lento, sobrecarregado, ou acabou de recuperar após uma interrupção."
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr "Sem sincronia"
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr "Sincronizado"
+
msgid "Geo|File sync capacity"
-msgstr "Capacidade de sincronização de arquivo"
+msgstr "Capacidade de sincronização de arquivos"
msgid "Geo|Groups to replicate"
-msgstr "Grupos para replicar"
+msgstr "Grupos para replicação"
msgid "Geo|Repository sync capacity"
-msgstr "Capacidade de sincronização de repositório"
+msgstr "Capacidade de sincronização do repositório"
msgid "Geo|Select groups to replicate."
-msgstr "Selecione grupos para replicar."
+msgstr ""
msgid "Git storage health information has been reset"
msgstr "Informações sobre o status de saúde do storage Git foram reiniciadas"
@@ -1031,9 +1314,6 @@ msgstr "Nenhum grupo encontrado"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr "Você pode gerenciar permissões de membros e acesso do seu grupo para cada projeto no grupo."
-msgid "GroupsTreeRole|as"
-msgstr "como"
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr "Você tem certeza que deseja sair do grupo \"${this.group.fullName}\"?"
@@ -1064,6 +1344,9 @@ msgstr "Desculpe, nenhum grupo corresponde à sua pesquisa"
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr "Desculpe, nenhum grupo ou projeto correspondem à sua pesquisa"
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr "Status de Saúde"
@@ -1092,21 +1375,21 @@ msgid "Import repository"
msgstr "Importar repositório"
msgid "Improve Issue boards with GitLab Enterprise Edition."
-msgstr "Melhorar issue boards com o GitLab Enterprise Edition."
+msgstr ""
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
-msgstr "Melhore gestão das issues com os pesos no GitLab Enterprise Edition."
+msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
-msgstr "Encontre o que precisa mais facilmente com a pesquisa global avançada com GitLab Enterprise Edition."
+msgstr ""
msgid "Install a Runner compatible with GitLab CI"
msgstr "Instalar um Runner compatível com o GitLab CI"
msgid "Instance"
msgid_plural "Instances"
-msgstr[0] "Instância"
-msgstr[1] "Instâncias"
+msgstr[0] ""
+msgstr[1] ""
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
msgstr "Interno - O grupo e projetos internos podem ser visualizados por qualquer usuário autenticado."
@@ -1121,10 +1404,7 @@ msgid "Introducing Cycle Analytics"
msgstr "Apresentando a Análise de Ciclo"
msgid "Issue board focus mode"
-msgstr "Modo de foco no issue board"
-
-msgid "Issue boards with milestones"
-msgstr "Issue board com milestone"
+msgstr ""
msgid "Issue events"
msgstr "Eventos de issue"
@@ -1133,11 +1413,29 @@ msgid "IssueBoards|Board"
msgstr "Board"
msgid "IssueBoards|Boards"
-msgstr "Boards"
+msgstr ""
msgid "Issues"
msgstr "Issues"
+msgid "Jan"
+msgstr "Jan"
+
+msgid "January"
+msgstr "Janeiro"
+
+msgid "Jul"
+msgstr "Jul"
+
+msgid "July"
+msgstr "Julho"
+
+msgid "Jun"
+msgstr "Jun"
+
+msgid "June"
+msgstr "Junho"
+
msgid "LFSStatus|Disabled"
msgstr "Desabilitado"
@@ -1192,7 +1490,7 @@ msgid "Leave project"
msgstr "Sair do projeto"
msgid "License"
-msgstr "Licença"
+msgstr ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
@@ -1206,14 +1504,23 @@ msgid "Locked"
msgstr "Bloqueado"
msgid "Locked Files"
-msgstr "Arquivos bloqueados"
+msgstr ""
msgid "Login"
msgstr "Entrar"
+msgid "Mar"
+msgstr "Mar"
+
+msgid "March"
+msgstr "Março"
+
msgid "Maximum git storage failures"
msgstr "Máximo de falhas do git storage"
+msgid "May"
+msgstr "Mai"
+
msgid "Median"
msgstr "Mediana"
@@ -1242,7 +1549,7 @@ msgid "More information is available|here"
msgstr "Mais informações estão disponíveis|aqui"
msgid "Multiple issue boards"
-msgstr "Múltiplos issue boards"
+msgstr ""
msgid "New Cluster"
msgstr "Novo cluster"
@@ -1258,9 +1565,15 @@ msgstr "Novo Agendamento de Pipeline"
msgid "New branch"
msgstr "Novo branch"
+msgid "New branch unavailable"
+msgstr "Novo branch indisponível"
+
msgid "New directory"
msgstr "Novo diretório"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "Novo arquivo"
@@ -1297,6 +1610,9 @@ msgstr "Nenhum repositório"
msgid "No schedules"
msgstr "Nenhum agendamento"
+msgid "No time spent"
+msgstr "Nenhum tempo gasto"
+
msgid "None"
msgstr "Nenhum"
@@ -1363,18 +1679,33 @@ msgstr "Observar"
msgid "Notifications"
msgstr "Notificações"
+msgid "Nov"
+msgstr "Nov"
+
+msgid "November"
+msgstr "Novembro"
+
msgid "Number of access attempts"
msgstr "Número de tentativas de acesso"
msgid "Number of failures before backing off"
msgstr "Número de falhas antes de reverter"
+msgid "Oct"
+msgstr "Out"
+
+msgid "October"
+msgstr "Outubro"
+
msgid "OfSearchInADropdown|Filter"
msgstr "Filtrar"
msgid "Only project members can comment."
msgstr "Somente membros do projeto podem comentar."
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Aberto"
@@ -1421,7 +1752,7 @@ msgid "Pipeline Schedules"
msgstr "Agendamentos da Pipeline"
msgid "Pipeline quota"
-msgstr "Cota de pipeline"
+msgstr ""
msgid "PipelineCharts|Failed:"
msgstr "Falhou:"
@@ -1507,6 +1838,9 @@ msgstr "com etapa"
msgid "Pipeline|with stages"
msgstr "com etapas"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr "Preferências"
@@ -1610,22 +1944,28 @@ msgid "ProjectNetworkGraph|Graph"
msgstr "Árvore"
msgid "ProjectSettings|Contact an admin to change this setting."
-msgstr "Fale com um administrador para mudar essa configuração."
+msgstr ""
+
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr "Rodar pipeline na branch default imediatamente"
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
-msgstr "Esse repositório só aceita push de commits assinados."
+msgstr ""
+
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr "Problema ao definir configurações de CI/CD Javascript"
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
-msgstr "Essa configuração está aplicada à nivel de servidor e pode ser sobrescrita por um adminstrador."
+msgstr ""
msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
-msgstr "Essa configuração está aplicada à nivel de servidor mas pode ser sobrescrita para esse projeto."
+msgstr ""
msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
-msgstr "Essa configuração será aplicada à todos os projetos, a não ser que sejam sobrescritos pelo administrador."
+msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
-msgstr "Nesse repositório, usuários só podem fazer push de commits verificados pelos seus e-mails."
+msgstr ""
msgid "Projects"
msgstr "Projetos"
@@ -1651,6 +1991,39 @@ msgstr "Desculpe, nenhum projeto corresponde a sua pesquisa"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Esta funcionalidade necessita de suporte à localStorage do navegador"
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr "Por padrão, Prometheus escuta em 'http://localhost:9090'. Não é recomendado mudar o endereço padrão e sua porta, porque pode conflitar com outros serviços que estão executando no sevidor do Gitlab."
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr "Encontrando e configurando métricas..."
+
+msgid "PrometheusService|Metrics"
+msgstr "Métricas"
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr "Métricas são automaticamente configuradas e monitoradas baseadas na biblioteca de métricas de exportadores populares."
+
+msgid "PrometheusService|Missing environment variable"
+msgstr "Variável de ambiente ausente"
+
+msgid "PrometheusService|Monitored"
+msgstr "Monitorado"
+
+msgid "PrometheusService|More information"
+msgstr "Mais informações"
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr "Nenhuma métrica está sendo monitorada. Para inicar o monitoramento, faça deploy em um ambiente."
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr "URL da API base do Prometheus. como http://prometheus.example.com/"
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr "Monitoramento com Prometheus"
+
+msgid "PrometheusService|View environments"
+msgstr "Ver ambientes"
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr "Público - O grupo e seus projetos podem ser visualizados por todos sem autenticação."
@@ -1658,13 +2031,13 @@ msgid "Public - The project can be accessed without any authentication."
msgstr "Público - O projeto pode ser acessado sem nenhuma autenticação."
msgid "Push Rules"
-msgstr "Regras de push"
+msgstr ""
msgid "Push events"
msgstr "Eventos de push"
msgid "PushRule|Committer restriction"
-msgstr "Restrição de commit"
+msgstr ""
msgid "Read more"
msgstr "Leia mais"
@@ -1679,7 +2052,7 @@ msgid "RefSwitcher|Tags"
msgstr "Tags"
msgid "Registry"
-msgstr "Registry"
+msgstr "Registro"
msgid "Related Commits"
msgstr "Commits Relacionados"
@@ -1747,6 +2120,9 @@ msgstr "Agendamentos"
msgid "Scheduling Pipelines"
msgstr "Agendando pipelines"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "Procurar branch e tags"
@@ -1768,6 +2144,12 @@ msgstr "Selecionar fuso horário"
msgid "Select target branch"
msgstr "Selecionar branch de destino"
+msgid "Sep"
+msgstr "Set"
+
+msgid "September"
+msgstr "Setembro"
+
msgid "Service Templates"
msgstr "Modelos de serviço"
@@ -1800,14 +2182,29 @@ msgid_plural "Showing %d events"
msgstr[0] "Mostrando %d evento"
msgstr[1] "Mostrando %d eventos"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr "Snippets"
msgid "Something went wrong on our end."
msgstr "Algo deu errado do nosso lado."
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
-msgstr "Algo deu errado ao tentar mudar o estado de bloqueio de ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr "Algo deu errado ao tentar mudar o estado de ${this.issuableDisplayName}"
msgid "Something went wrong while fetching the projects."
msgstr "Algo deu errado ao recuperar os projetos."
@@ -1858,7 +2255,7 @@ msgid "SortOptions|Least popular"
msgstr "Menos populares"
msgid "SortOptions|Less weight"
-msgstr "Menor peso"
+msgstr ""
msgid "SortOptions|Milestone"
msgstr "Milestone"
@@ -1870,7 +2267,7 @@ msgid "SortOptions|Milestone due soon"
msgstr "Milestone de fim mais próximo"
msgid "SortOptions|More weight"
-msgstr "Mais peso"
+msgstr ""
msgid "SortOptions|Most popular"
msgstr "Mais populares"
@@ -1912,11 +2309,17 @@ msgid "SortOptions|Start soon"
msgstr "Iniciar mais próximo"
msgid "SortOptions|Weight"
-msgstr "Peso"
+msgstr ""
+
+msgid "Source"
+msgstr "Origem"
msgid "Source code"
msgstr "Código-fonte"
+msgid "Source is not available"
+msgstr "Origem não está disponível"
+
msgid "Spam Logs"
msgstr "Logs de spam"
@@ -1935,6 +2338,9 @@ msgstr "Iniciar um %{new_merge_request} a partir dessas alterações"
msgid "Start the Runner!"
msgstr "Inicie o Runner!"
+msgid "Stopped"
+msgstr "Parado"
+
msgid "Subgroups"
msgstr "Subgrupos"
@@ -1955,6 +2361,75 @@ msgstr[1] "Tags"
msgid "Tags"
msgstr "Tags"
+msgid "TagsPage|Browse commits"
+msgstr "Navegar nos commits"
+
+msgid "TagsPage|Browse files"
+msgstr "Navegar nos arquivos"
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr "Não foi possível encontrar o commit HEAD para esse tag"
+
+msgid "TagsPage|Cancel"
+msgstr "Cancelar"
+
+msgid "TagsPage|Create tag"
+msgstr "Criar tag"
+
+msgid "TagsPage|Delete tag"
+msgstr "Apagar tag"
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr "Apagar a tag %{tag_name} é uma ação destrutiva e irreversível. Tem certeza?"
+
+msgid "TagsPage|Edit release notes"
+msgstr "Editar o release notes"
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr "Nome de branch, tag ou SHA do commit existente"
+
+msgid "TagsPage|Filter by tag name"
+msgstr "Filtrar tag por nome"
+
+msgid "TagsPage|New Tag"
+msgstr "Novo tag"
+
+msgid "TagsPage|New tag"
+msgstr "Novo tag"
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr "Opcionalmente, adicionar a mensagem à essa tag."
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr "Opcionalmente, adicionar release notes à tag. Eles serão armazenados no banco de dados do GitLab e mostrado na página de tags."
+
+msgid "TagsPage|Release notes"
+msgstr "Release notes"
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr "Repositório ainda não tem tags."
+
+msgid "TagsPage|Sort by"
+msgstr "Ordenar por"
+
+msgid "TagsPage|Tags"
+msgstr "Tags"
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr "Tags dão capacidade de marcar pontos específicos na história como sendo importantes"
+
+msgid "TagsPage|This tag has no release notes."
+msgstr "Essa tag não tem release notes."
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr "Use o comando \"git tag\" para adiciona uma nova tag:"
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr "Escreve seu release notes ou arraste o arquivo aqui..."
+
+msgid "TagsPage|protected"
+msgstr "protegido"
+
msgid "Target Branch"
msgstr "Branch de destino"
@@ -1962,10 +2437,10 @@ msgid "Team"
msgstr "Equipe"
msgid "Thanks! Don't show me this again"
-msgstr "Obrigado! Não mostrar novamente"
+msgstr ""
msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
-msgstr "A pesquisa global avançado no GitLab é um serviço poderoso de pesquisa que poupa seu tempo. Ao invés de criar código duplicado e perder seu tempo, você pode agora pesquisar por código de outros times que podem ajudar no seu próprio projeto."
+msgstr ""
msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold"
msgstr "O limite do recuso do circuitbreaker deve ser inferior ao limite de contagem de falhas"
@@ -2036,6 +2511,9 @@ msgstr "O valor situado no ponto médio de uma série de valores observados. Ex.
msgid "There are problems accessing Git storage: "
msgstr "Há problemas para acessar o storage Git: "
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr "Esse branch mudou desde quando você começou sua edição. Você quer criar um novo branch?"
@@ -2057,6 +2535,9 @@ msgstr "Isto significa que você não pode entregar código até que crie um rep
msgid "This merge request is locked."
msgstr "Esse merge request está bloqueado."
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Tempo até que uma issue seja agendada"
@@ -2205,14 +2686,26 @@ msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
+msgid "Title"
+msgstr "Título"
+
msgid "Total Time"
msgstr "Tempo Total"
+msgid "Total issue time spent"
+msgstr "Tempo total gasto"
+
msgid "Total test time for all commits/merges"
msgstr "Tempo de teste total para todos os commits/merges"
msgid "Track activity with Contribution Analytics."
-msgstr "Acompanhar atividade com o Contribution Analytics."
+msgstr "Acompanhe a atividade com o Contribution Analytics."
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr "Acompanhe grupos de questões que compartilhem um tema, em projetos e milestones"
+
+msgid "Turn on Service Desk"
+msgstr "Ativar Service Desk"
msgid "Unlock"
msgstr "Desbloquear"
@@ -2227,13 +2720,13 @@ msgid "Unsubscribe"
msgstr "Desassinar"
msgid "Upgrade your plan to activate Advanced Global Search."
-msgstr "Atualize seu plano para ativar a pesquisa global avançada."
+msgstr "Atualize seu plano para ativar a Pesquisa Global Avançada."
msgid "Upgrade your plan to activate Contribution Analytics."
msgstr "Atualize seu plano para ativar o Contribution Analytics."
msgid "Upgrade your plan to activate Group Webhooks."
-msgstr "Atualize seu plano para ativar Webhooks de grupo."
+msgstr "Atualize seu plano para ativar Webhooks do grupo."
msgid "Upgrade your plan to activate Issue weight."
msgstr "Atualize seu plano para ativar peso nas issues."
@@ -2250,6 +2743,9 @@ msgstr "Enviar arquivo"
msgid "UploadLink|click to upload"
msgstr "clique para fazer upload"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr "Use o Service Desk para se conectar com seus usuários (por exemplo, para oferecer suporte ao cliente) por email dentro do GitLab"
+
msgid "Use the following registration token during setup:"
msgstr "Use o seguinte token de registro durante a configuração:"
@@ -2283,8 +2779,11 @@ 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 "We want to be sure it is you, please confirm you are not a robot."
+msgstr "Queremos ter certeza de que é você, confirme que você não é um robô."
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
-msgstr "Webhooks permitem que você acione uma URL se, por exemplo, um novo código for feito push ou uma nova issue criada. Você pode configurar os webhooks para escutar eventos específicos como push, issue ou merge request. Webhooks de grupo aplicarão para todos os projetos no grupo, permitindo você padronizar o funcionamento em todo o grupo."
+msgstr "Webhooks permitem que você acione uma URL se, por exemplo, quando um novo código for feito push ou uma nova issue criada. Você pode configurar os webhooks para escutar eventos específicos como push, issue ou merge request. Webhooks de grupo aplicarão para todos os projetos no grupo, permitindo você padronizar o funcionamento em todo o grupo."
msgid "Weight"
msgstr "Peso"
@@ -2395,7 +2894,7 @@ msgid "Wiki|Wiki Pages"
msgstr "Páginas Wiki"
msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members."
-msgstr "Com o contribution analytics você pode ter uma visão geral da atividade em issue, merge request e evento de push para sua organização e seus membros."
+msgstr "Com a análise de contribuição, você pode ter uma visão geral da atividade de issues, merge requests e eventos push de sua organização e seus membros."
msgid "Withdraw Access Request"
msgstr "Remover Requisição de Acesso"
@@ -2412,12 +2911,6 @@ msgstr "Você está prestes a remover a relação de fork do projeto original %{
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Você irá transferir %{project_name_with_namespace} para outro proprietário. Tem certeza ABSOLUTA?"
-msgid "You are on a read-only GitLab instance."
-msgstr "Você está em uma instância somente-leitura do GitLab."
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr "Você está em uma instância somente-leitura do GitLab. Se você quiser fazer qualquer alteração visite %{link_to_primary_node}."
-
msgid "You can only add files when you are on a branch"
msgstr "Você somente pode adicionar arquivos quando estiver em um branch"
@@ -2457,6 +2950,9 @@ msgstr "Você não poderá fazer pull ou push via %{protocol} até que %{set_pas
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "Você não conseguirá fazer pull ou push no projeto via SSH até que adicione %{add_ssh_key_link} ao seu perfil"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr "Você não poderá fazer push ou pull do código via SSH enquanto não adicionar sua chave SSH no seu perfil"
+
msgid "Your comment will not be visible to the public."
msgstr "Seu comentário não estará visível ao público."
@@ -2469,6 +2965,12 @@ msgstr "Seu nome"
msgid "Your projects"
msgstr "Seus projetos"
+msgid "branch name"
+msgstr "nome da branch"
+
+msgid "by"
+msgstr "por"
+
msgid "commit"
msgstr "commit"
@@ -2494,6 +2996,9 @@ msgstr "senha"
msgid "personal access token"
msgstr "token de acesso pessoal"
+msgid "source"
+msgstr "origem"
+
msgid "to help your contributors communicate effectively!"
msgstr "para ajudar seus contribuintes à se comunicar de maneira eficaz!"
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index b25a5d1e75b..898d55e7d4e 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-17 07:55-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:40-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Russian\n"
"Language: ru_RU\n"
@@ -61,6 +61,9 @@ msgstr[0] "%{storage_name}: неудачная попытка доступа к
msgstr[1] "%{storage_name}: %{failed_attempts} - неудачные попытки доступа к хранилищу:"
msgstr[2] "%{storage_name}: %{failed_attempts} - неудачные попытки доступа к хранилищу:"
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(перейдите по ссылке %{link} для получения информации об установке)."
@@ -107,7 +110,7 @@ msgid "Activity"
msgstr "Активность"
msgid "Add"
-msgstr "Добавить"
+msgstr ""
msgid "Add Changelog"
msgstr "Добавить Журнал Изменений"
@@ -116,14 +119,11 @@ msgid "Add Contribution guide"
msgstr "Добавить Руководство участника"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
-msgstr "Добавить групповые веб-обработчики и GitLab Enterprise Edition."
+msgstr ""
msgid "Add License"
msgstr "Добавить Лицензию"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "Добавьте ключ SSH в свой профиль, чтобы отправлять или получать код через SSH."
-
msgid "Add new directory"
msgstr "Добавить новый каталог"
@@ -136,6 +136,15 @@ msgstr "Расширенные настройки"
msgid "All"
msgstr "Все"
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr "Произошла ошибка. Пожалуйста, попробуйте снова."
@@ -145,6 +154,12 @@ msgstr "Оформление"
msgid "Applications"
msgstr "Приложения"
+msgid "Apr"
+msgstr "Апр."
+
+msgid "April"
+msgstr "Апрель"
+
msgid "Archived project! Repository is read-only"
msgstr "Архивный проект! Репозиторий доступен только для чтения"
@@ -172,6 +187,12 @@ msgstr "Артефакты"
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Приложить файл через drag & drop или %{upload_link}"
+msgid "Aug"
+msgstr "Авг."
+
+msgid "August"
+msgstr "Август"
+
msgid "Authentication Log"
msgstr "Журнал аутентификации"
@@ -191,7 +212,7 @@ msgid "AutoDevOps|Auto DevOps (Beta)"
msgstr "Auto DevOps (бета)"
msgid "AutoDevOps|Auto DevOps documentation"
-msgstr ""
+msgstr "Документация по Auto DevOps"
msgid "AutoDevOps|Enable in settings"
msgstr "Включить в настройках"
@@ -205,14 +226,17 @@ msgstr "Подробнее по ссылке %{link_to_documentation}"
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr "Вы можете активировать %{link_to_settings} для этого проекта."
+msgid "Available"
+msgstr ""
+
msgid "Billing"
-msgstr "Тариф"
+msgstr ""
msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
msgstr "%{group_name} использует тарифный план %{plan_link}."
msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
-msgstr "Автоматическое повышение или понижение недоступно для некоторых тарифных планов в настоящее время."
+msgstr "В настоящее время автоматическое повышение или понижение недоступно для некоторых тарифных планов."
msgid "BillingPlans|Current plan"
msgstr "Текущий тарифный план"
@@ -221,10 +245,10 @@ msgid "BillingPlans|Customer Support"
msgstr "Поддержка Клиентов"
msgid "BillingPlans|Downgrade"
-msgstr "Понижение"
+msgstr "Понизить"
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
-msgstr "Узнайте больше о каждом тарифном плане прочитав наш %{faq_link}."
+msgstr "Узнайте больше о каждом тарифном плане, прочитав нашу страницу %{faq_link}."
msgid "BillingPlans|Manage plan"
msgstr "Управление тарифным планом"
@@ -236,19 +260,19 @@ msgid "BillingPlans|See all %{plan_name} features"
msgstr "Посмотреть возможности %{plan_name} полностью"
msgid "BillingPlans|This group uses the plan associated with its parent group."
-msgstr "Эта группа использует тарифный план связанный с родительской группой."
+msgstr "Эта группа использует тарифный план, связанный с родительской группой."
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
msgstr "Для управления тарифным планом этой группы посетите раздел тарификации %{parent_billing_page_link}."
msgid "BillingPlans|Upgrade"
-msgstr "Повышение"
+msgstr "Повысить"
msgid "BillingPlans|You are currently on the %{plan_link} plan."
msgstr "В настоящее время вы используете тарифный план %{plan_link}."
msgid "BillingPlans|frequently asked questions"
-msgstr "Часто задаваемые вопросы"
+msgstr "часто задаваемых вопросов"
msgid "BillingPlans|monthly"
msgstr "ежемесячно"
@@ -271,6 +295,12 @@ msgstr "Ветка %{branch_name} создана. Для нас
msgid "Branch has changed"
msgstr "Ветка была изменена"
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Поиск веток"
@@ -332,7 +362,7 @@ msgid "Branches|Sort by"
msgstr "Сортировать по"
msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart."
-msgstr "Ветка не может быть обновлена автоматически, потому что она имеет расхождения с её двойником в родительском репозитории."
+msgstr ""
msgid "Branches|The default branch cannot be deleted"
msgstr "Ветка \"по умолчанию\" не может быть удалена"
@@ -347,13 +377,13 @@ msgid "Branches|To confirm, type %{branch_name_confirmation}:"
msgstr "Для подтверждения, введите %{branch_name_confirmation}:"
msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
-msgstr "Чтобы отменить локальные изменения и перезаписать ветку версией из родительского репозитория, удалите её здесь и выберите \"Обновить сейчас\" выше."
+msgstr ""
msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
msgstr "Вы собираетесь безвозвратно удалить защищённую ветку %{branch_name}."
msgid "Branches|diverged from upstream"
-msgstr "расходятся с родительским репозиторием"
+msgstr ""
msgid "Branches|merged"
msgstr "влита"
@@ -395,7 +425,7 @@ msgid "Cancel edit"
msgstr "Отменить редактирование"
msgid "Change Weight"
-msgstr "Изменить Вес"
+msgstr ""
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Выбрать в ветке"
@@ -418,6 +448,12 @@ msgstr "Диаграммы"
msgid "Chat"
msgstr "Чат"
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "Подобрать в этом коммите"
@@ -425,7 +461,7 @@ msgid "Cherry-pick this merge request"
msgstr "Подобрать этот запрос на слияние"
msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all."
-msgstr "Выберите группы, которые хотите скопировать на вторичный узел. Оставьте пустым для копирование всего."
+msgstr ""
msgid "CiStatusLabel|canceled"
msgstr "отменено"
@@ -488,13 +524,46 @@ msgid "Clone repository"
msgstr "Клонировать репозиторий"
msgid "Close"
-msgstr "Закрыть"
+msgstr ""
msgid "Cluster"
msgstr "Кластер"
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
-msgstr "%{link_to_container_project} должен быть создан под этой учетной записью"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
+msgstr ""
msgid "ClusterIntegration|Cluster details"
msgstr "Параметры кластера"
@@ -512,56 +581,137 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab
msgstr "Для этого проекта включена интеграция кластеров. Отключение интеграции не повлияет на кластер, но соединение с GitLab будет временно отключено."
msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..."
-msgstr "Создается кластер в Google Kubernetes Engine..."
+msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr "Название кластера"
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
-msgstr "Кластер был успешно создан в Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
+msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr "Копировать название кластера"
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr "Создать кластер"
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
-msgstr "Создать новый кластер в Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr "Включить интеграцию с кластерами"
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr "Идентификатор проекта в Google Cloud Platform"
msgid "ClusterIntegration|Google Kubernetes Engine"
-msgstr "Google Kubernetes Engine"
+msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
-msgstr "Проект Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "Узнайте больше на %{link_to_documentation}"
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr "Тип машины"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr "Убедитесь, что ваша учетная запись %{link_to_requirements} для создания кластеров"
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
-msgstr "Управление интеграцией кластера на вашем проекте Gitlab"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
+msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr "Управляйте кластером, перейдя по ссылке %{link_gke}"
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr "Примечание:"
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Количество узлов"
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr "Пожалуйста, убедитесь, что ваш аккаунт Google отвечает следующим требованиям:"
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr "Пространство имен проекта (необязательное, уникальное)"
@@ -574,8 +724,14 @@ msgstr "Удалить интеграцию с кластером"
msgid "ClusterIntegration|Remove integration"
msgstr "Удалить интеграцию"
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
-msgstr "При удалении интеграции с кластером будет удалена конфигурация кластера, которую вы добавили в этот проект. Данное действие не удалит сам проект."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
+msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
msgstr "Просмотреть и отредактировать параметры для вашего кластера"
@@ -589,33 +745,57 @@ msgstr "См. ваши проекты"
msgid "ClusterIntegration|See zones"
msgstr "См. зоны"
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr " У нас что-то пошло не так."
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
-msgstr "Что-то пошло не так во время создания кластера в Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
msgid "ClusterIntegration|Toggle Cluster"
msgstr "Переключить Кластер"
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Если привязать кластер к этому проекту, вы с лёгкостью сможете использовать приложения для ревью, развертывать ваши приложения, запускать сборочные линии и многое другое."
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
-msgstr "Ваша учетная запись должна иметь %{link_to_kubernetes_engine}"
+msgstr ""
msgid "ClusterIntegration|Zone"
msgstr "Зона"
msgid "ClusterIntegration|access to Google Kubernetes Engine"
-msgstr "доступ к Google Kubernetes Engine"
+msgstr ""
msgid "ClusterIntegration|cluster"
msgstr "кластер"
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr "страница справки"
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr "отвечает требованиям"
@@ -631,12 +811,6 @@ msgstr[0] "Коммит"
msgstr[1] "Коммиты"
msgstr[2] "Коммиты"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] "Зафиксировать %d файл"
-msgstr[1] "Зафиксировать %d файла"
-msgstr[2] "Зафиксировать %d файлов"
-
msgid "Commit Message"
msgstr "Описание Коммита"
@@ -718,14 +892,23 @@ msgstr "Руководство участника"
msgid "Contributors"
msgstr "Участники"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
-msgstr "Контролировать максимальное количество потоков фоновой загрузки LFS/вложений для этого вторичного узла"
+msgstr ""
msgid "Control the maximum concurrency of repository backfill for this secondary node"
-msgstr "Контролировать максимальное количество потоков фоновой загрузки хранилища для этого вторичного узла"
+msgstr ""
msgid "Copy SSH public key to clipboard"
-msgstr "Скопировать публичный ключ SSH в буфер обмена"
+msgstr ""
msgid "Copy URL to clipboard"
msgstr "Копировать URL в буфер обмена"
@@ -745,6 +928,9 @@ msgstr "Создать каталог"
msgid "Create empty bare repository"
msgstr "Создать пустой репозиторий"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr "Создать файл"
@@ -772,6 +958,9 @@ msgstr "Тег"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "создать персональный токен доступа"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Временная зона Cron"
@@ -817,6 +1006,12 @@ msgstr "Все"
msgid "DashboardProjects|Personal"
msgstr "Личные"
+msgid "Dec"
+msgstr "Дек."
+
+msgid "December"
+msgstr "Декабрь"
+
msgid "Define a custom pattern with cron syntax"
msgstr "Определить настраиваемый шаблон с синтаксисом cron"
@@ -836,7 +1031,7 @@ msgid "Description"
msgstr "Описание"
msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "Шаблоны описаний позволяют вам определить специфичные шаблоны заполнения обсуждений и запросов на слияние в вашем проекте."
+msgstr ""
msgid "Details"
msgstr "Подробная информация"
@@ -851,7 +1046,7 @@ msgid "Dismiss Cycle Analytics introduction box"
msgstr "Отключить блок введения в Аналитику Цикла"
msgid "Dismiss Merge Request promotion"
-msgstr "Отключить анонсы для Запросов на Слияние"
+msgstr ""
msgid "Don't show again"
msgstr "Не показывать снова"
@@ -892,6 +1087,72 @@ msgstr "Изменить расписание сборочной линии %{id
msgid "Emails"
msgstr "Email-адреса"
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr "Показать все"
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "Фильтр по всему"
@@ -931,6 +1192,12 @@ msgstr "Не удалось изменить владельца"
msgid "Failed to remove the pipeline schedule"
msgstr "Не удалось удалить расписание сборочной линии"
+msgid "Feb"
+msgstr "Фев."
+
+msgid "February"
+msgstr "Февраль"
+
msgid "File name"
msgstr "Имя файла"
@@ -977,19 +1244,34 @@ msgid "GPG Keys"
msgstr "GPG Ключи"
msgid "Geo Nodes"
-msgstr "Географические Узлы"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
msgid "Geo|File sync capacity"
-msgstr "Объем хранилища для синхронизации файлов"
+msgstr ""
msgid "Geo|Groups to replicate"
-msgstr "Группы для репликации"
+msgstr ""
msgid "Geo|Repository sync capacity"
-msgstr "Объем хранилища для синхронизации репозитория"
+msgstr ""
msgid "Geo|Select groups to replicate."
-msgstr "Выберите группы для репликации."
+msgstr ""
msgid "Git storage health information has been reset"
msgstr "Информация о стабильности Git хранилища была сброшена"
@@ -1042,9 +1324,6 @@ msgstr "Группы не найдены"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr "Вы можете управлять правами и доступом участников вашей группы к каждому проекту в группе."
-msgid "GroupsTreeRole|as"
-msgstr "как"
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr "Вы уверены, что вы хотите покинуть группу \"${this.group.fullName}\"?"
@@ -1075,6 +1354,9 @@ msgstr "К сожалению, по вашему запросу групп не
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr "К сожалению, по вашему запросу групп или проектов не найдено"
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr "Проверка работоспособности"
@@ -1103,22 +1385,22 @@ msgid "Import repository"
msgstr "Импорт репозитория"
msgid "Improve Issue boards with GitLab Enterprise Edition."
-msgstr "Улучшить доски обсуждений с помощью версии GitLab Enterprise Edition."
+msgstr ""
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
-msgstr "Улучшить управление обсуждениями с возможностью определения веса обсуждения при помощи GitLab Enterprise Edition."
+msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
-msgstr "Улучшить поиск при помощи Расширенного Глобального Поиска в версии GitLab Enterprise Edition."
+msgstr ""
msgid "Install a Runner compatible with GitLab CI"
msgstr "Установите Gitlab Runner совместимый с Gitlab CI"
msgid "Instance"
msgid_plural "Instances"
-msgstr[0] "Экземпляр"
-msgstr[1] "Экземпляры"
-msgstr[2] "Экземпляры"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
msgstr "Внутренний - Группу и включённые в неё проекты может видеть любой зарегистрированный пользователь."
@@ -1133,10 +1415,7 @@ msgid "Introducing Cycle Analytics"
msgstr "Внедрение Цикла Аналитик"
msgid "Issue board focus mode"
-msgstr "Режим фокусировки над доской обсуждений"
-
-msgid "Issue boards with milestones"
-msgstr "Доски обсуждений с вехами"
+msgstr ""
msgid "Issue events"
msgstr "События обсуждений"
@@ -1145,11 +1424,29 @@ msgid "IssueBoards|Board"
msgstr "Доска"
msgid "IssueBoards|Boards"
-msgstr "Доски"
+msgstr ""
msgid "Issues"
msgstr "Обсуждения"
+msgid "Jan"
+msgstr "Янв."
+
+msgid "January"
+msgstr "Январь"
+
+msgid "Jul"
+msgstr "Июл."
+
+msgid "July"
+msgstr "Июль"
+
+msgid "Jun"
+msgstr "Июн."
+
+msgid "June"
+msgstr "Июнь"
+
msgid "LFSStatus|Disabled"
msgstr "Отключено"
@@ -1205,7 +1502,7 @@ msgid "Leave project"
msgstr "Покинуть проект"
msgid "License"
-msgstr "Лицензия"
+msgstr ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
@@ -1220,14 +1517,23 @@ msgid "Locked"
msgstr "Заблокировано"
msgid "Locked Files"
-msgstr "Заблокированные Файлы"
+msgstr ""
msgid "Login"
msgstr "Войти"
+msgid "Mar"
+msgstr "Мар."
+
+msgid "March"
+msgstr "Март"
+
msgid "Maximum git storage failures"
msgstr "Максимальное количество сбоев хранилища git"
+msgid "May"
+msgstr "Май"
+
msgid "Median"
msgstr "Среднее"
@@ -1256,7 +1562,7 @@ msgid "More information is available|here"
msgstr "Больше информации доступно|тут"
msgid "Multiple issue boards"
-msgstr "Сводные доски задач"
+msgstr ""
msgid "New Cluster"
msgstr "Новый Кластер"
@@ -1273,9 +1579,15 @@ msgstr "Новое Расписание Сборочной Линии"
msgid "New branch"
msgstr "Новая ветка"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "Новый каталог"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "Новый файл"
@@ -1312,6 +1624,9 @@ msgstr "Нет репозитория"
msgid "No schedules"
msgstr "Нет расписаний"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr "Пусто"
@@ -1378,11 +1693,23 @@ msgstr "Отслеживать"
msgid "Notifications"
msgstr "Уведомления"
+msgid "Nov"
+msgstr "Нояб."
+
+msgid "November"
+msgstr "Ноябрь"
+
msgid "Number of access attempts"
msgstr "Количество попыток доступа"
msgid "Number of failures before backing off"
-msgstr ""
+msgstr "Количество ошибок перед откатом"
+
+msgid "Oct"
+msgstr "Окт."
+
+msgid "October"
+msgstr "Октябрь"
msgid "OfSearchInADropdown|Filter"
msgstr "Фильтр"
@@ -1390,6 +1717,9 @@ msgstr "Фильтр"
msgid "Only project members can comment."
msgstr "Только участники проекта могут оставлять комментарии."
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Открыто"
@@ -1436,7 +1766,7 @@ msgid "Pipeline Schedules"
msgstr "Расписания Сборочных Линий"
msgid "Pipeline quota"
-msgstr "Квота сборочной линии"
+msgstr ""
msgid "PipelineCharts|Failed:"
msgstr "Неудача:"
@@ -1522,6 +1852,9 @@ msgstr "со стадией"
msgid "Pipeline|with stages"
msgstr "со стадиями"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr "Предпочтения"
@@ -1625,19 +1958,25 @@ msgid "ProjectNetworkGraph|Graph"
msgstr "Граф"
msgid "ProjectSettings|Contact an admin to change this setting."
-msgstr "Обратитесь к администратору для изменения этой настройки."
+msgstr ""
+
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
-msgstr "Только подписанные коммиты могут быть помещены в этот репозиторий."
+msgstr ""
+
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
-msgstr "Эта настройка применяется на уровне сервера и может быть переопределена администратором."
+msgstr ""
msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
-msgstr "Эта настройка применяется на уровне сервера, но была переопределена для этого проекта."
+msgstr ""
msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
-msgstr "Эта настройка будет применена для всех проектов, если иное поведение не переопределено администратором."
+msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
msgstr ""
@@ -1666,6 +2005,39 @@ msgstr "К сожалению, по вашему запросу проекты
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Эта функциональность требует поддержки localStorage в вашем браузере"
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr "Публичный - Группу и включённые в неё проекты могут видеть все, без какой-либо проверки подлинности."
@@ -1673,7 +2045,7 @@ msgid "Public - The project can be accessed without any authentication."
msgstr "Публичный - Доступ к проекту возможен без какой-либо проверки подлинности."
msgid "Push Rules"
-msgstr "Правила Отправки"
+msgstr ""
msgid "Push events"
msgstr "События отправки"
@@ -1694,7 +2066,7 @@ msgid "RefSwitcher|Tags"
msgstr "Теги"
msgid "Registry"
-msgstr "Реестр"
+msgstr ""
msgid "Related Commits"
msgstr "Связанные коммиты"
@@ -1762,6 +2134,9 @@ msgstr "Расписания"
msgid "Scheduling Pipelines"
msgstr "Планирование Сборочных Линий"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "Найти ветки и теги"
@@ -1783,6 +2158,12 @@ msgstr "Выбор временной зоны"
msgid "Select target branch"
msgstr "Выбор целевой ветки"
+msgid "Sep"
+msgstr "Сент."
+
+msgid "September"
+msgstr "Сентябрь"
+
msgid "Service Templates"
msgstr "Шаблоны Служб"
@@ -1816,14 +2197,29 @@ msgstr[0] "Показано %d событие"
msgstr[1] "Показано %d событий"
msgstr[2] "Показано %d событий"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr "Сниппеты"
msgid "Something went wrong on our end."
msgstr "У нас что-то пошло не так."
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
-msgstr "Что-то пошло не так при попытке изменения заблокированного состояния этого ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr ""
msgid "Something went wrong while fetching the projects."
msgstr "Что-то пошло не так при получении проектов."
@@ -1874,7 +2270,7 @@ msgid "SortOptions|Least popular"
msgstr "Наименее популярный"
msgid "SortOptions|Less weight"
-msgstr "Меньший вес"
+msgstr ""
msgid "SortOptions|Milestone"
msgstr "Веха"
@@ -1886,7 +2282,7 @@ msgid "SortOptions|Milestone due soon"
msgstr "Веха, наступающая раньше"
msgid "SortOptions|More weight"
-msgstr "Больший вес"
+msgstr ""
msgid "SortOptions|Most popular"
msgstr "Наиболее популярный"
@@ -1928,11 +2324,17 @@ msgid "SortOptions|Start soon"
msgstr "Начатые недавно"
msgid "SortOptions|Weight"
-msgstr "Вес"
+msgstr ""
+
+msgid "Source"
+msgstr "Источник"
msgid "Source code"
msgstr "Исходный код"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr "Спам Логи"
@@ -1951,6 +2353,9 @@ msgstr "Начать %{new_merge_request} с этих изменений"
msgid "Start the Runner!"
msgstr "Запустить GitLab Runner!"
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr "Подгруппы"
@@ -1972,6 +2377,75 @@ msgstr[2] "Теги"
msgid "Tags"
msgstr "Теги"
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr "Сортировать по"
+
+msgid "TagsPage|Tags"
+msgstr "Теги"
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "Ветка"
@@ -1979,10 +2453,10 @@ msgid "Team"
msgstr "Команда"
msgid "Thanks! Don't show me this again"
-msgstr "Спасибо! Больше не показывайте мне это сообщение"
+msgstr ""
msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
-msgstr "Расширенный глобальный поиск в GitLab - это серьезный инструмент который сокращает ваше время. Вместо создания дублирующего кода и траты времени, вы можете искать код внутри других команд, который поможет вам в вашем проекте."
+msgstr ""
msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold"
msgstr "Порог срабатывания для СircuitBreaker должен быть меньше, чем порог срабатывания для определения сбоя"
@@ -2053,6 +2527,9 @@ msgstr "Среднее значение в ряду. Пример: между 3,
msgid "There are problems accessing Git storage: "
msgstr "Проблемы с доступом к Git хранилищу: "
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr "Эта ветка была изменена, пока вы её редактировали. Вы хотите создать новую ветку?"
@@ -2074,6 +2551,9 @@ msgstr "Это означает, что вы не можете отправит
msgid "This merge request is locked."
msgstr "Запрос на слияние заблокирован."
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Время до начала попадания обсуждения в планировщик"
@@ -2224,14 +2704,26 @@ msgstr[2] "мин"
msgid "Time|s"
msgstr "с"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "Общее время"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "Общее время тестирования фиксаций/слияний"
msgid "Track activity with Contribution Analytics."
-msgstr "Отслеживать активность с помощью Аналитики Участников."
+msgstr ""
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
msgid "Unlock"
msgstr "Разблокировать"
@@ -2246,19 +2738,19 @@ msgid "Unsubscribe"
msgstr "Отписаться"
msgid "Upgrade your plan to activate Advanced Global Search."
-msgstr "Повысьте ваш тарифный план, чтобы активировать Улучшенный Глобальный Поиск."
+msgstr ""
msgid "Upgrade your plan to activate Contribution Analytics."
-msgstr "Повысьте ваш тарифный план, чтобы активировать Аналитики Участников."
+msgstr ""
msgid "Upgrade your plan to activate Group Webhooks."
-msgstr "Повысьте ваш тарифный план, чтобы активировать Групповые Веб-Обработчики."
+msgstr ""
msgid "Upgrade your plan to activate Issue weight."
-msgstr "Обновите ваш тарифный план для появления веса у обсуждений."
+msgstr ""
msgid "Upgrade your plan to improve Issue boards."
-msgstr "Обновите ваш тарифный план, чтобы улучшить доски обсуждений."
+msgstr ""
msgid "Upload New File"
msgstr "Загрузить новый файл"
@@ -2269,6 +2761,9 @@ msgstr "Загрузить файл"
msgid "UploadLink|click to upload"
msgstr "кликните для загрузки"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr "Используйте следующий токен регистрации в процессе установки:"
@@ -2302,11 +2797,14 @@ msgstr "Хотите увидеть данные? Обратитесь к адм
msgid "We don't have enough data to show this stage."
msgstr "Информация по этапу отсутствует."
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
-msgstr "Веб-обработчики позволяют вам вызывать адрес URL если, например, отправлен новый код или создано новое обсуждение. Вы можете настроить веб-обработчики так, чтобы они реагировали на определённые события, такие как отправки кода, обсуждения или запросы на слияние. Групповые веб-обработчики применяются ко всем проектам в группе и позволяют вам стандартизовать функциональность веб-обработчиков для всей вашей группы."
+msgstr ""
msgid "Weight"
-msgstr "Вес"
+msgstr ""
msgid "When access to a storage fails. GitLab will prevent access to the storage for the time specified here. This allows the filesystem to recover. Repositories on failing shards are temporarly unavailable"
msgstr "Когда доступ к хранилищу получить не удалось, GitLab приостановит доступ к хранилищу на время, указанное здесь. Это позволит файловой системе восстановиться. Репозитории на сбойных \"шардах\" будут временно недоступны"
@@ -2414,7 +2912,7 @@ msgid "Wiki|Wiki Pages"
msgstr "Вики Страницы"
msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members."
-msgstr "С аналитикой участников вы можете изучать активность в обсуждениях, запросах на слияние и событий отправки кода для вашей организации и её участников."
+msgstr ""
msgid "Withdraw Access Request"
msgstr "Отменить запрос доступа"
@@ -2431,17 +2929,11 @@ msgstr "Вы собираетесь удалить связь ответвлен
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Вы собираетесь передать проект %{project_name_with_namespace} другому владельцу. Вы АБСОЛЮТНО уверены?"
-msgid "You are on a read-only GitLab instance."
-msgstr "Вы находитесь на экземпляре \"только для чтения\" кластера GitLab."
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr "Вы находитесь на экземпляре \"только для чтения\" кластера GitLab. Если вы хотите произвести любые изменения, вы должны перейти на \"основной\" экземпляр по ссылке %{link_to_primary_node}."
-
msgid "You can only add files when you are on a branch"
msgstr "Вы можете добавлять только файлы, когда находитесь в ветке"
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
-msgstr "Вы не можете записывать на подчиненные экземпляры \"только для чтения\" кластера GitLab Geo. Используйте вместо этого %{link_to_primary_node}."
+msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr "Вы не можете записывать на этот экземпляр \"только для чтения\" кластера GitLab."
@@ -2476,6 +2968,9 @@ msgstr "Вы не сможете получать и отправлять код
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "Вы не сможете получать и отправлять код проекта через SSH пока %{add_ssh_key_link} в ваш профиль."
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr "Ваш комментарий не будет виден всем."
@@ -2488,8 +2983,14 @@ msgstr "Ваше имя"
msgid "Your projects"
msgstr "Ваши проекты"
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
-msgstr "коммит"
+msgstr ""
msgid "day"
msgid_plural "days"
@@ -2515,8 +3016,11 @@ msgstr "пароль"
msgid "personal access token"
msgstr "токен для персонального доступа"
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
-msgstr "чтобы помочь вашим участникам взаимодействовать эффективнее!"
+msgstr ""
msgid "username"
msgstr "имя пользователя"
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index 53054bdaa27..fc62776a7a4 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-21 16:43-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 06:39-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Ukrainian\n"
"Language: uk_UA\n"
@@ -61,6 +61,9 @@ msgstr[0] "%{storage_name}: спроба невдалого доступу до
msgstr[1] "%{storage_name}: %{failed_attempts} невдалі спроби доступу до сховища:"
msgstr[2] "%{storage_name}: %{failed_attempts} невдалих спроб доступу до сховища:"
+msgid "%{text} is available"
+msgstr "%{text} доступний"
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(перейдіть за посиланням %{link} для отримання інформації стосовно встановлення)."
@@ -83,7 +86,7 @@ msgid "2FA enabled"
msgstr "Двоетапна аутентифікація увімкнена"
msgid "A collection of graphs regarding Continuous Integration"
-msgstr "Це набір графічних елементів для безперервної інтеграції"
+msgstr "Набір графіків відносно безперервної інтеграції"
msgid "About auto deploy"
msgstr "Про авто розгортання"
@@ -95,7 +98,7 @@ 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 "Доступ до помилкових сховищ тимчасово відключений для можливості монтування та відновлення. Скиньте інформацію про сховища після усунення проблеми, щоб дозволити доступ."
+msgstr "Доступ до сховищ, що вийшли з ладу, тимчасово прибраний задля відновлення монтування. Після вирішення проблеми обнуліть інформацію сховища для відновлення доступу."
msgid "Account"
msgstr "Обліковий запис"
@@ -113,17 +116,14 @@ msgid "Add Changelog"
msgstr "Додати список змін (Changelog)"
msgid "Add Contribution guide"
-msgstr "Додати керівництво для контриб’юторів"
+msgstr ""
msgid "Add Group Webhooks and GitLab Enterprise Edition."
-msgstr "Додайте групу Webhooks та GitLab Enterprise Edition."
+msgstr ""
msgid "Add License"
msgstr "Додати ліцензію"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "Додайте SSH ключ в свій профіль, щоб мати можливість завантажити чи надіслати зміни через SSH."
-
msgid "Add new directory"
msgstr "Додати новий каталог"
@@ -136,6 +136,15 @@ msgstr "Додаткові параметри"
msgid "All"
msgstr "Всі"
+msgid "An error occurred when toggling the notification subscription"
+msgstr "Виникла помилка під час зміни підписки на сповіщення"
+
+msgid "An error occurred when updating the issue weight"
+msgstr "Збій під час оновлення ваги проблеми"
+
+msgid "An error occurred while fetching sidebar data"
+msgstr "Виникла помилка під час завантаження даних для бічної панелі"
+
msgid "An error occurred. Please try again."
msgstr "Сталась помилка. Спробуйте ще раз."
@@ -145,11 +154,17 @@ msgstr "Зовнішній вигляд"
msgid "Applications"
msgstr "Додатки"
+msgid "Apr"
+msgstr "квіт."
+
+msgid "April"
+msgstr "квітень"
+
msgid "Archived project! Repository is read-only"
msgstr "Заархівований проект! Репозиторій доступний лише для читання"
msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Ви впевнені, що хочете видалити цей розклад для Конвеєра?"
+msgstr ""
msgid "Are you sure you want to discard your changes?"
msgstr "Ви впевнені, що бажаєте скасувати ваші зміни?"
@@ -161,7 +176,7 @@ msgid "Are you sure you want to reset registration token?"
msgstr "Ви впевнені, що бажаєте скинути реєстраційний токен?"
msgid "Are you sure you want to reset the health check token?"
-msgstr "Ви впевнені, що Ви хочете скинути цей ключ перевірки працездатності?"
+msgstr "Ви впевнені, що хочете скинути цей ключ перевірки працездатності?"
msgid "Are you sure?"
msgstr "Ви впевнені?"
@@ -172,6 +187,12 @@ msgstr "Артефакти"
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "Прикріпити файл за допомогою перетягування або %{upload_link}"
+msgid "Aug"
+msgstr "серп."
+
+msgid "August"
+msgstr "серпень"
+
msgid "Authentication Log"
msgstr "Журнал автентифікації"
@@ -205,6 +226,9 @@ msgstr "Дізнайтеся більше в %{link_to_documentation}"
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr "Ви можете активувати %{link_to_settings} для цього проекту."
+msgid "Available"
+msgstr "Доступний"
+
msgid "Billing"
msgstr "Білінг"
@@ -236,10 +260,10 @@ msgid "BillingPlans|See all %{plan_name} features"
msgstr "Подивіться всі можливості %{plan_name}"
msgid "BillingPlans|This group uses the plan associated with its parent group."
-msgstr "Ця група використовує план, пов'язаний з батьківською групою."
+msgstr "Ця група використовує план, пов'язаний із батьківською групою."
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
-msgstr "Для управління планом цієї групи відвідайте секцію оплати %{parent_billing_page_link}."
+msgstr "Щоб керувати планом цієї групи, відвідайте розділ білінгу на %{parent_billing_page_link}."
msgid "BillingPlans|Upgrade"
msgstr "Підвищити"
@@ -257,7 +281,7 @@ msgid "BillingPlans|paid annually at %{price_per_year}"
msgstr "Оплачується щорічно %{price_per_year}"
msgid "BillingPlans|per user"
-msgstr "За користувача"
+msgstr ""
msgid "Branch"
msgid_plural "Branches"
@@ -271,11 +295,17 @@ msgstr "Гілка %{branch_name} створена. Для на
msgid "Branch has changed"
msgstr "Гілка змінилась"
+msgid "Branch is already taken"
+msgstr "Гілка вже існує"
+
+msgid "Branch name"
+msgstr "Назва гілки"
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Пошук гілок"
msgid "BranchSwitcherTitle|Switch branch"
-msgstr "Переключити гілку"
+msgstr ""
msgid "Branches"
msgstr "Гілки"
@@ -401,13 +431,13 @@ msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Вибрати в гілці"
msgid "ChangeTypeActionLabel|Revert in branch"
-msgstr "Скасувати у гілці"
+msgstr "Анулювати у гілці"
msgid "ChangeTypeAction|Cherry-pick"
-msgstr "Cherry-pick"
+msgstr ""
msgid "ChangeTypeAction|Revert"
-msgstr "Скасувати"
+msgstr "Анулювати коміт"
msgid "Changelog"
msgstr "Список змін (Changelog)"
@@ -418,14 +448,20 @@ msgstr "Графіки"
msgid "Chat"
msgstr "Чат"
+msgid "Checking %{text} availability…"
+msgstr "Перевірка доступності %{text}…"
+
+msgid "Checking branch availability..."
+msgstr "Перевірка доступності гілки..."
+
msgid "Cherry-pick this commit"
-msgstr "Cherry-pick в цьому коміті"
+msgstr ""
msgid "Cherry-pick this merge request"
-msgstr "Cherry-pick в цьому запиті на злиття"
+msgstr ""
msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all."
-msgstr "Виберіть, які групи ви хочете реплікувати на цю вторинну ноду. Залиште порожнім, щоб реплікувати все."
+msgstr ""
msgid "CiStatusLabel|canceled"
msgstr "скасовано"
@@ -493,8 +529,41 @@ msgstr "Закрити"
msgid "Cluster"
msgstr "Кластер"
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
-msgstr "%{link_to_container_project} напевно було створено під цим обліковим записом"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr "%{appList} успішно встановлені на вашому кластері"
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr "%{boldNotice} Це додасть ресурси (наприклад балансер навантаження), що спричинить додаткові витрати. Перегляньте %{pricingLink}"
+
+msgid "ClusterIntegration|API URL"
+msgstr "API URL"
+
+msgid "ClusterIntegration|Active"
+msgstr "Активний"
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr "Додати існуючий кластер"
+
+msgid "ClusterIntegration|Add cluster"
+msgstr "Додати кластер"
+
+msgid "ClusterIntegration|All"
+msgstr "Всі"
+
+msgid "ClusterIntegration|Applications"
+msgstr "Додатки"
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr "Сертифікат центру сертифікації"
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr "Набір сертифікатів (формат PEM)"
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr "Виберіть спосіб налаштування інтеграції з кластером"
+
+msgid "ClusterIntegration|Cluster"
+msgstr "Кластер"
msgid "ClusterIntegration|Cluster details"
msgstr "Параметри кластера"
@@ -509,7 +578,7 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project."
msgstr "Інтеграція із кластером увімкнена для цього проекту."
msgid "ClusterIntegration|Cluster integration is enabled for this project. Disabling this integration will not affect your cluster, it will only temporarily turn off GitLab's connection to it."
-msgstr "Для цього проекту увімкнена інтеграція із кластером. Викнення інтеграції не вплине на кластер, але з'єднання GitLab з ним буде тимчасово розірване."
+msgstr ""
msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..."
msgstr "Створюється кластер в Google Kubernetes Engine..."
@@ -517,21 +586,54 @@ msgstr "Створюється кластер в Google Kubernetes Engine..."
msgid "ClusterIntegration|Cluster name"
msgstr "Ім'я кластера"
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
-msgstr "Кластер був успішно створений в Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr "Кластер був успішно створено в Google Kubernetes Engine. Оновіть сторінку, щоб переглянути додатову інформацію"
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr "Кластери дозволяють вам використовувати Review Apps, розгортати ваші програми, запускати ваші конвеєри і багато іншого простим способом. %{link_to_help_page}"
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr "Скопіювати URL API"
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr "Скопіювати сертифікат центру сертифікації"
+
+msgid "ClusterIntegration|Copy Token"
+msgstr "Скопіювати Токен"
msgid "ClusterIntegration|Copy cluster name"
msgstr "Копіювати назву кластера"
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr "Створити новий кластер у Google Engine прямо з GitLab"
+
msgid "ClusterIntegration|Create cluster"
msgstr "Створити кластер"
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
-msgstr "Створити новий кластер в Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr "Створити кластер в Google Kubernetes Engine"
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr "Створити в GKE"
msgid "ClusterIntegration|Enable cluster integration"
msgstr "Увімкнути інтеграцію із кластерами"
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr "Вкажіть параметри існуючого кластера Kubernetes"
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr "Введіть докладний опис вашого кластера"
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr "Шаблон середовища"
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr "Вартість GKE"
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr "GitLab Runner"
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr "Ідентифікатор проекту в Google Cloud Platform"
@@ -541,29 +643,77 @@ msgstr "Google Kubernetes Engine"
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr "Проект Google Kubernetes Engine"
+msgid "ClusterIntegration|Helm Tiller"
+msgstr "Helm Tiller"
+
+msgid "ClusterIntegration|Inactive"
+msgstr "Неактивні"
+
+msgid "ClusterIntegration|Ingress"
+msgstr "Ingress"
+
+msgid "ClusterIntegration|Install"
+msgstr "Встановити"
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr "Встановіть додатки у ваш кластер. Докладніше про %{helpLink}"
+
+msgid "ClusterIntegration|Installed"
+msgstr "Встановлений"
+
+msgid "ClusterIntegration|Installing"
+msgstr "Встановлення"
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr "Інтеграція кластерної автоматизації"
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "Дізнайтеся більше про %{link_to_documentation}"
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr "Дізнайтеся більше про кластери"
+
msgid "ClusterIntegration|Machine type"
msgstr "Тип машини"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr "Переконайтеся, що ваш обліковий запис %{link_to_requirements} для створення кластерів"
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
-msgstr "Управління інтеграцією із кластером у вашому Gitlab-проекті."
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
+msgstr "Управління інтеграцією із кластером у вашому Gitlab-проекті"
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr "Для керування своїм кластером перейдіть на %{link_gke}"
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr "Кілька кластерів доступні в GitLab Enterprise Edition Premium і Ultimate"
+
+msgid "ClusterIntegration|Note:"
+msgstr "Примітка:"
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Кількість вузлів"
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr "Введіть інформацію про доступ до свого кластера. Якщо вам потрібна допомога, ви можете прочитати наші %{link_to_help_page} по кластерам"
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
-msgstr "Будь-ласка впевніться, що ваш Google-аккаунт задовольняє наступним вимогам:"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr "Проблема налаштування кластера"
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr "Проблема налаштування списку кластерів"
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
msgid "ClusterIntegration|Project namespace (optional, unique)"
-msgstr "Namespace проекту (не обов’язковий, унікальний)"
+msgstr ""
msgid "ClusterIntegration|Read our %{link_to_help_page} on cluster integration."
msgstr "Прочитайте нашу документацію %{link_to_help_page} по інтеграції із кластером."
@@ -574,8 +724,14 @@ msgstr "Видалити інтеграцію з кластером"
msgid "ClusterIntegration|Remove integration"
msgstr "Видалити інтеграцію"
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
-msgstr "При видаленні інтеграції з кластером буде видалена конфігурація кластера, яку ви додали в цей проект. Дана дія не видалить сам проект."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr "Видалення кластерної інтеграції призведе до видалення конфігурації кластера, яку ви додали до цього проекту. Ця дія не буде видаляти ваш кластер у Google Kubernetes Engine."
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr "Запит про початок встановлення не виконано"
+
+msgid "ClusterIntegration|Save changes"
+msgstr "Зберегти зміни"
msgid "ClusterIntegration|See and edit the details for your cluster"
msgstr "Переглянути та редагувати параметри вашого кластера"
@@ -589,15 +745,33 @@ msgstr "Переглянути ваші проекти"
msgid "ClusterIntegration|See zones"
msgstr "Переглянути зони"
+msgid "ClusterIntegration|Service token"
+msgstr "Токен Сервіса"
+
+msgid "ClusterIntegration|Show"
+msgstr "Показати"
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr "Щось пішло не так з нашого боку."
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr "Щось пішло не так під час створення кластера в Google Kubernetes Engine"
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr "Під час встановлення %{title} сталася помилка"
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr "Немає кластерів для відображення"
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr "Цей обліковий запис має мати дозволи для створення кластера в %{link_to_container_project}, зазначеному нижче"
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr "Переключити Кластер"
+msgid "ClusterIntegration|Token"
+msgstr "Токен"
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "За допомогою підключеного до цього проекту кластера, ви можете використовувати Review Apps, розгортати ваші проекти, запускати конвеєри збірки та багато іншого."
@@ -613,9 +787,15 @@ msgstr "доступ до Google Kubernetes Engine"
msgid "ClusterIntegration|cluster"
msgstr "кластер"
+msgid "ClusterIntegration|documentation"
+msgstr "документація"
+
msgid "ClusterIntegration|help page"
msgstr "сторінка допомоги"
+msgid "ClusterIntegration|installing applications"
+msgstr "встановлення додатків"
+
msgid "ClusterIntegration|meets the requirements"
msgstr "задовольняє вимогам"
@@ -631,12 +811,6 @@ msgstr[0] "Коміт"
msgstr[1] "Коміта"
msgstr[2] "Комітів"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] "Закомітити %d файл"
-msgstr[1] "Закомітити %d файли"
-msgstr[2] "Закомітити %d файлів"
-
msgid "Commit Message"
msgstr "Коміт-повідомелння"
@@ -704,7 +878,7 @@ msgid "ContainerRegistry|Tag"
msgstr "Тег"
msgid "ContainerRegistry|Tag ID"
-msgstr "Тег ID"
+msgstr ""
msgid "ContainerRegistry|Use different image names"
msgstr "Використовуйте різні імена образів"
@@ -713,11 +887,20 @@ msgid "ContainerRegistry|With the Docker Container Registry integrated into GitL
msgstr "За допомогою вбудованого в GitLab реєстру Docker контейнерів кожен проект може мати власне місце для зберігання Docker образів."
msgid "Contribution guide"
-msgstr "Керівництво контриб’юторів"
+msgstr ""
msgid "Contributors"
msgstr "Контриб’ютори"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr "Коміти в %{branch_name}, за винятком комітів злиття. Обмежено 6000 комітів."
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr "Будь ласка, зачекайте, ця сторінка автоматично оновиться, коли буде готова."
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr "Задати максимальну кількість потоків для фонового завантаження LFS/вкладень для цього вторинного вузла"
@@ -737,7 +920,7 @@ msgid "Create New Directory"
msgstr "Створити новий каталог"
msgid "Create a personal access token on your account to pull or push via %{protocol}."
-msgstr "Створити токен доступу для вашого аккауета, щоб відправляти або отримувати через %{protocol}."
+msgstr ""
msgid "Create directory"
msgstr "Створити каталог"
@@ -745,6 +928,9 @@ msgstr "Створити каталог"
msgid "Create empty bare repository"
msgstr "Створити порожній репозиторій"
+msgid "Create epic"
+msgstr "Створити епік"
+
msgid "Create file"
msgstr "Створити файл"
@@ -772,6 +958,9 @@ msgstr "Тег"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "Створити токен для особистого доступу"
+msgid "Creating epic"
+msgstr "Створення епіку"
+
msgid "Cron Timezone"
msgstr "Часовий пояс Cron"
@@ -788,10 +977,10 @@ msgid "Cycle Analytics"
msgstr "Аналіз циклу"
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
-msgstr "Аналітика циклу дає огляд того, скільки часу потрібно, щоб перейти від ідеї до виробництва у вашому проекті."
+msgstr ""
msgid "CycleAnalyticsStage|Code"
-msgstr "Код"
+msgstr ""
msgid "CycleAnalyticsStage|Issue"
msgstr "Проблема"
@@ -800,13 +989,13 @@ msgid "CycleAnalyticsStage|Plan"
msgstr "Планування"
msgid "CycleAnalyticsStage|Production"
-msgstr "ПРОД"
+msgstr ""
msgid "CycleAnalyticsStage|Review"
msgstr "Затвердження"
msgid "CycleAnalyticsStage|Staging"
-msgstr "ДЕВ"
+msgstr "Staging"
msgid "CycleAnalyticsStage|Test"
msgstr "Тестування"
@@ -817,6 +1006,12 @@ msgstr "Всі"
msgid "DashboardProjects|Personal"
msgstr "Особисті"
+msgid "Dec"
+msgstr "груд."
+
+msgid "December"
+msgstr "грудень"
+
msgid "Define a custom pattern with cron syntax"
msgstr "Визначте власний шаблон за допомогою синтаксису cron"
@@ -830,13 +1025,13 @@ msgstr[1] "Розгортання"
msgstr[2] "Розгортань"
msgid "Deploy Keys"
-msgstr "Ключи для розгортування"
+msgstr ""
msgid "Description"
msgstr "Опис"
msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "Шаблони опису дозволяють визначити конкретні шаблони обговорень та запитів на зливання для вашого проекту."
+msgstr ""
msgid "Details"
msgstr "Деталі"
@@ -851,7 +1046,7 @@ msgid "Dismiss Cycle Analytics introduction box"
msgstr "Відмінити блок вступу до Аналитики Циклу"
msgid "Dismiss Merge Request promotion"
-msgstr "Не показувати промоушн запитів на злиття"
+msgstr "Відхилити рекламу для Запитів на злиття"
msgid "Don't show again"
msgstr "Не показувати знову"
@@ -878,7 +1073,7 @@ msgid "DownloadCommit|Email Patches"
msgstr "Email-патчи"
msgid "DownloadCommit|Plain Diff"
-msgstr "Plain Diff"
+msgstr ""
msgid "DownloadSource|Download"
msgstr "Завантажити"
@@ -892,6 +1087,72 @@ msgstr "Редагувати Розклад Конвеєра %{id}"
msgid "Emails"
msgstr "Адреси електронної пошти"
+msgid "Environments|An error occurred while fetching the environments."
+msgstr "Виникла помилка при завантаженні середовищ."
+
+msgid "Environments|An error occurred while making the request."
+msgstr "Під час виконання запиту сталася помилка."
+
+msgid "Environments|Commit"
+msgstr "Коміт"
+
+msgid "Environments|Deployment"
+msgstr "Розгортання"
+
+msgid "Environments|Environment"
+msgstr "Середовище"
+
+msgid "Environments|Environments"
+msgstr "Середовища"
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr "Завдання"
+
+msgid "Environments|New environment"
+msgstr "Нове середовище"
+
+msgid "Environments|No deployments yet"
+msgstr "Ще немає розгортань"
+
+msgid "Environments|Open"
+msgstr "Відкрити"
+
+msgid "Environments|Re-deploy"
+msgstr "Повторно розгорнути"
+
+msgid "Environments|Read more about environments"
+msgstr "Дізнайтеся більше про середовища"
+
+msgid "Environments|Rollback"
+msgstr "Відкотити"
+
+msgid "Environments|Show all"
+msgstr "Показати всі"
+
+msgid "Environments|Updated"
+msgstr "Оновлено"
+
+msgid "Environments|You don't have any environments right now."
+msgstr "Ви поки не налаштували жодного середовища."
+
+msgid "Epic will be removed! Are you sure?"
+msgstr "Епік буде видалено! Ви впевнені?"
+
+msgid "Epics"
+msgstr "Епіки"
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr "Епіки дозволяють керувати вашим портфелем проектів ефективніше та з меншими зусиллями"
+
+msgid "Error creating epic"
+msgstr "Помилка при створенні епіку"
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr "Сталася помилка під час підключення підписки на сповіщення"
+
msgid "EventFilterBy|Filter by all"
msgstr "Фільтрувати по всім"
@@ -905,7 +1166,7 @@ msgid "EventFilterBy|Filter by merge events"
msgstr "Фільтрувати по запитам на злиття"
msgid "EventFilterBy|Filter by push events"
-msgstr "Фільтрувати по push-подіях"
+msgstr ""
msgid "EventFilterBy|Filter by team"
msgstr "Фільтрувати по команді"
@@ -929,7 +1190,13 @@ msgid "Failed to change the owner"
msgstr "Не вдалося змінити власника"
msgid "Failed to remove the pipeline schedule"
-msgstr "Не вдалося видалити розклад Конвеєра"
+msgstr ""
+
+msgid "Feb"
+msgstr "лют."
+
+msgid "February"
+msgstr "лютий"
msgid "File name"
msgstr "Ім'я файлу"
@@ -950,7 +1217,7 @@ msgid "FirstPushedBy|First"
msgstr "Перший"
msgid "FirstPushedBy|pushed by"
-msgstr "Надіслані зміни від"
+msgstr ""
msgid "Fork"
msgid_plural "Forks"
@@ -968,10 +1235,10 @@ msgid "Format"
msgstr "Формат"
msgid "From issue creation until deploy to production"
-msgstr "З моменту створення проблеми до розгортання на ПРОД"
+msgstr ""
msgid "From merge request merge until deploy to production"
-msgstr "З об'єднання запиту злиття до розгортання на ПРОД"
+msgstr ""
msgid "GPG Keys"
msgstr "GPG ключі"
@@ -979,6 +1246,21 @@ msgstr "GPG ключі"
msgid "Geo Nodes"
msgstr "Гео-Вузли"
+msgid "GeoNodeSyncStatus|Failed"
+msgstr "Невдало"
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr "Вузол не працює або зламаний."
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr "Вузол працює повільно, перевантажений або тільки що відновився після збою."
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr "Несинхронізовано"
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr "Синхронізовано"
+
msgid "Geo|File sync capacity"
msgstr "Пропускна здатність синхронізації файлів"
@@ -1042,9 +1324,6 @@ msgstr "Групи не знайдені"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr "Ви можете керувати правами доступу членів групи мати доступ до кожного проекту в ній."
-msgid "GroupsTreeRole|as"
-msgstr "як"
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr "Ви впевнені, що хочете залишити групу \"${this.group.fullName}\"?"
@@ -1075,6 +1354,9 @@ msgstr "На жаль жодна группа не задовольняє пар
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr "На жаль жодна группа чи проект не задовольняє параметрам вашого запиту"
+msgid "Have your users email"
+msgstr "Електронна пошта для звертань користувачів"
+
msgid "Health Check"
msgstr "Перевірки працездатності"
@@ -1100,10 +1382,10 @@ msgid "Housekeeping successfully started"
msgstr "Очищення успішно розпочато"
msgid "Import repository"
-msgstr "Імпорт репозеторія"
+msgstr ""
msgid "Improve Issue boards with GitLab Enterprise Edition."
-msgstr "Покращити дошки обговорень за допомогою версії GitLab Enterprise Edition."
+msgstr ""
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
msgstr "Покращити управління проблемами з можливістю визначення ваги проблеми за допомогою GitLab Enterprise Edition."
@@ -1117,7 +1399,7 @@ msgstr "Встановіть Runner, сумісний з GitLab CI"
msgid "Instance"
msgid_plural "Instances"
msgstr[0] "Інстанс"
-msgstr[1] "Інстанса"
+msgstr[1] "Iнстанси"
msgstr[2] "Інстансів"
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
@@ -1133,10 +1415,7 @@ msgid "Introducing Cycle Analytics"
msgstr "Представляємо аналітику циклу"
msgid "Issue board focus mode"
-msgstr "Режим фокусування над дошкою обговорень"
-
-msgid "Issue boards with milestones"
-msgstr "Дошка обговорень із етапами"
+msgstr "Режим фокусування для дошки обговорень"
msgid "Issue events"
msgstr "Проблеми"
@@ -1150,6 +1429,24 @@ msgstr "Дошки"
msgid "Issues"
msgstr "Проблеми"
+msgid "Jan"
+msgstr "січ."
+
+msgid "January"
+msgstr "січень"
+
+msgid "Jul"
+msgstr "лип."
+
+msgid "July"
+msgstr "липень"
+
+msgid "Jun"
+msgstr "чер."
+
+msgid "June"
+msgstr "червень"
+
msgid "LFSStatus|Disabled"
msgstr "Вимкнено"
@@ -1184,7 +1481,7 @@ msgid "Last updated"
msgstr "Востаннє оновленно"
msgid "LastPushEvent|You pushed to"
-msgstr "Ви надіслали зміни до"
+msgstr ""
msgid "LastPushEvent|at"
msgstr "в"
@@ -1225,9 +1522,18 @@ msgstr "Заблоковані файли"
msgid "Login"
msgstr "Вхід"
+msgid "Mar"
+msgstr "бер."
+
+msgid "March"
+msgstr "березень"
+
msgid "Maximum git storage failures"
msgstr "Максимальна кількість невдач в сховищі даних git"
+msgid "May"
+msgstr "травень"
+
msgid "Median"
msgstr "Медіана"
@@ -1238,7 +1544,7 @@ msgid "Merge Requests"
msgstr "Запити на злиття"
msgid "Merge events"
-msgstr "Запити на злиття"
+msgstr ""
msgid "Merge request"
msgstr "Запит на злиття"
@@ -1256,7 +1562,7 @@ msgid "More information is available|here"
msgstr "тут"
msgid "Multiple issue boards"
-msgstr "Зведені дошки обговорення"
+msgstr "Кілька дошок обговорення"
msgid "New Cluster"
msgstr "Новий кластер"
@@ -1273,9 +1579,15 @@ msgstr "Новий розклад Конвеєра"
msgid "New branch"
msgstr "Нова гілка"
+msgid "New branch unavailable"
+msgstr "Нова гілка недоступна"
+
msgid "New directory"
msgstr "Новий каталог"
+msgid "New epic"
+msgstr "Новий епік"
+
msgid "New file"
msgstr "Новий файл"
@@ -1295,7 +1607,7 @@ msgid "New schedule"
msgstr "Новий Розклад"
msgid "New snippet"
-msgstr "Новий сніппет"
+msgstr ""
msgid "New subgroup"
msgstr "Нова підгрупа"
@@ -1307,11 +1619,14 @@ msgid "No container images stored for this project. Add one by following the ins
msgstr "В цьому проекті немає жодного образа контейнера. Додайте його за інструкціями вище."
msgid "No repository"
-msgstr "Немає репозеторія"
+msgstr ""
msgid "No schedules"
msgstr "немає Розкладів"
+msgid "No time spent"
+msgstr "Немає витраченого часу"
+
msgid "None"
msgstr "Жоден"
@@ -1328,13 +1643,13 @@ msgid "NotificationEvent|Close issue"
msgstr "Проблема закрита"
msgid "NotificationEvent|Close merge request"
-msgstr "Запит на об'єднання закритий"
+msgstr ""
msgid "NotificationEvent|Failed pipeline"
msgstr "Невдача в конвеєрі"
msgid "NotificationEvent|Merge merge request"
-msgstr "Об'єднати запит на злиття"
+msgstr ""
msgid "NotificationEvent|New issue"
msgstr "Нова проблема"
@@ -1349,7 +1664,7 @@ msgid "NotificationEvent|Reassign issue"
msgstr "Перепризначити проблему"
msgid "NotificationEvent|Reassign merge request"
-msgstr "Перепризначити запит на злиття"
+msgstr ""
msgid "NotificationEvent|Reopen issue"
msgstr "Повторне відкриття проблему"
@@ -1378,18 +1693,33 @@ msgstr "Відстежувати"
msgid "Notifications"
msgstr "Сповіщення"
+msgid "Nov"
+msgstr "лист."
+
+msgid "November"
+msgstr "листопад"
+
msgid "Number of access attempts"
msgstr "Кількість спроб доступу"
msgid "Number of failures before backing off"
msgstr "Кількість помилок до призупинення"
+msgid "Oct"
+msgstr "жовт."
+
+msgid "October"
+msgstr "жовтень"
+
msgid "OfSearchInADropdown|Filter"
msgstr "Фільтр"
msgid "Only project members can comment."
msgstr "Тільки учасники проекту можуть залишати коментарі."
+msgid "Opened"
+msgstr "Відкрито"
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Відкрито"
@@ -1469,7 +1799,7 @@ msgid "PipelineSchedules|Input variable key"
msgstr "Введіть ім'я змінної"
msgid "PipelineSchedules|Input variable value"
-msgstr "Вхідні значення змінних"
+msgstr ""
msgid "PipelineSchedules|Next Run"
msgstr "Наступний запуск"
@@ -1478,7 +1808,7 @@ msgid "PipelineSchedules|None"
msgstr "Немає"
msgid "PipelineSchedules|Provide a short description for this pipeline"
-msgstr "Задайте короткий опис для цього Конвеєру"
+msgstr ""
msgid "PipelineSchedules|Remove variable row"
msgstr "Видалити змінні"
@@ -1493,7 +1823,7 @@ msgid "PipelineSchedules|Variables"
msgstr "Змінні"
msgid "PipelineSheduleIntervalPattern|Custom"
-msgstr "Власні"
+msgstr ""
msgid "Pipelines"
msgstr "Конвеєри"
@@ -1522,11 +1852,14 @@ msgstr "зі стадією"
msgid "Pipeline|with stages"
msgstr "зі стадіями"
+msgid "Please solve the reCAPTCHA"
+msgstr "Будь ласка, пройдіть reCAPTCHA"
+
msgid "Preferences"
msgstr "Налаштування"
msgid "Private - Project access must be granted explicitly to each user."
-msgstr "Приватний — доступ до проекту повинен надаватися кожному користувачеві."
+msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr "Приватна — цю групу та її проекти можуть бачити тільки її користувачі."
@@ -1583,7 +1916,7 @@ msgid "Project '%{project_name}' was successfully updated."
msgstr "Проект '%{project_name}' успішно оновлено."
msgid "Project access must be granted explicitly to each user."
-msgstr "Доступ до проекту повинен надаватися кожному користувачеві."
+msgstr ""
msgid "Project details"
msgstr "Деталі проекту"
@@ -1607,7 +1940,7 @@ msgid "ProjectFeature|Disabled"
msgstr "Вимкнено"
msgid "ProjectFeature|Everyone with access"
-msgstr "Все з доступом"
+msgstr ""
msgid "ProjectFeature|Only team members"
msgstr "Тільки члени команди"
@@ -1619,7 +1952,7 @@ msgid "ProjectLastActivity|Never"
msgstr "Ніколи"
msgid "ProjectLifecycle|Stage"
-msgstr "Етап"
+msgstr "Стадія"
msgid "ProjectNetworkGraph|Graph"
msgstr "Історія"
@@ -1627,9 +1960,15 @@ msgstr "Історія"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr "Зверніться до адміністратора, щоб змінити це налаштування."
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr "Зразу запускати конвеєр у гілкці за замовчуванням"
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "Тільки підписані коміти можуть бути надіслані в цей репозиторій."
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr "Проблема налаштування параметрів CI / CD JavaScript"
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr "Цей параметр застосовується на рівні сервера та може бути перевизначений адміністратором."
@@ -1640,7 +1979,7 @@ msgid "ProjectSettings|This setting will be applied to all projects unless overr
msgstr "Цей параметр буде застосовано до всіх проектів, якщо адміністратор не змінить його."
msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
-msgstr "Користувачі можуть виконувати push в цей репозиторій лише тих комітів, які містять одну із підтверджених адрес електронної пошти."
+msgstr ""
msgid "Projects"
msgstr "Проекти"
@@ -1666,6 +2005,39 @@ msgstr "На жаль, по вашоу запиту проектів не зна
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Ця функція потребує підтримки localStorage вашим браузером"
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr "За замовчуванням, Prometheus запускається за адресою ‘http://localhost:9090’. Не рекомендується змінювати цю адресу і порт, бо це може призвести до конфлікту з іншими сервісами запущеними на GitLab сервері."
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr "Пошук та налаштування метрик..."
+
+msgid "PrometheusService|Metrics"
+msgstr "Метрики"
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr "Метрики автоматично налаштовуються та контролюються на основі набору метрик від популярних експортерів."
+
+msgid "PrometheusService|Missing environment variable"
+msgstr "Пропущена змінна середовища"
+
+msgid "PrometheusService|Monitored"
+msgstr "Моніторинг підключено"
+
+msgid "PrometheusService|More information"
+msgstr "Додаткова інформація"
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr "Жодні метрики не відслідковуються. Для початку моніторингу, розгорніть середовище."
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr "Базова адреса Prometheus API, наприклад http://prometheus.example.com/"
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr "Моніторинг Prometheus"
+
+msgid "PrometheusService|View environments"
+msgstr "Перегляд середовищ"
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr "Публічна — група та всі публічні проекти можуть переглядатися без автентифікації."
@@ -1673,10 +2045,10 @@ msgid "Public - The project can be accessed without any authentication."
msgstr "Публічний — проект может переглядатися без автентифікації."
msgid "Push Rules"
-msgstr "Push-правила"
+msgstr ""
msgid "Push events"
-msgstr "Push-події"
+msgstr ""
msgid "PushRule|Committer restriction"
msgstr "Обмеження для коміттера"
@@ -1685,7 +2057,7 @@ msgid "Read more"
msgstr "Докладніше"
msgid "Readme"
-msgstr "Прочитай Мене"
+msgstr "Інструкція"
msgid "RefSwitcher|Branches"
msgstr "Гілки"
@@ -1700,19 +2072,19 @@ msgid "Related Commits"
msgstr "Пов'язані Коміти"
msgid "Related Deployed Jobs"
-msgstr "Пов’язані розгорнуті задачі (Jobs)"
+msgstr "Пов’язані розгорнуті завдання (Jobs)"
msgid "Related Issues"
msgstr "Пов’язані Проблеми (Issues)"
msgid "Related Jobs"
-msgstr "Пов’язані Задачі (Jobs)"
+msgstr "Пов’язані Завдання (Jobs)"
msgid "Related Merge Requests"
msgstr "Пов'язані запити на злиття"
msgid "Related Merged Requests"
-msgstr "Пов'язані об'єднані запити"
+msgstr ""
msgid "Remind later"
msgstr "Нагадати пізніше"
@@ -1736,10 +2108,10 @@ msgid "Reset runners registration token"
msgstr "Скинути реєстраційний токен runner-ів"
msgid "Revert this commit"
-msgstr "Скасувати цей коміт"
+msgstr "Анулювати цей коміт"
msgid "Revert this merge request"
-msgstr "Скасувати цей запит на злиття"
+msgstr "Анулювати цей запит на злиття"
msgid "SSH Keys"
msgstr "Ключі SSH"
@@ -1751,7 +2123,7 @@ msgid "Save changes"
msgstr "Зберегти зміни"
msgid "Save pipeline schedule"
-msgstr "Зберегти Розклад Конвеєра"
+msgstr ""
msgid "Schedule a new pipeline"
msgstr "Розклад нового конвеєра"
@@ -1762,6 +2134,9 @@ msgstr "Розклади"
msgid "Scheduling Pipelines"
msgstr "Планування конвеєрів"
+msgid "Scoped issue boards"
+msgstr "Тематичні дошки проблем"
+
msgid "Search branches and tags"
msgstr "Пошук гілок та тегів"
@@ -1783,11 +2158,17 @@ msgstr "Вибрати часовий пояс"
msgid "Select target branch"
msgstr "Вибір цільової гілки"
+msgid "Sep"
+msgstr "вер."
+
+msgid "September"
+msgstr "вересень"
+
msgid "Service Templates"
msgstr "Сервіс шаблонів"
msgid "Set a password on your account to pull or push via %{protocol}."
-msgstr "Встановіть пароль свого облікового запису, щоб відправляти або отримувати код через %{protocol}."
+msgstr ""
msgid "Set up CI"
msgstr "Налаштування CI"
@@ -1816,14 +2197,29 @@ msgstr[0] "Показано %d подію"
msgstr[1] "Показано %d події"
msgstr[2] "Показано %d подій"
+msgid "Sidebar|Change weight"
+msgstr "Змінити вагу"
+
+msgid "Sidebar|Edit"
+msgstr "Редагувати"
+
+msgid "Sidebar|No"
+msgstr "Ні"
+
+msgid "Sidebar|None"
+msgstr "Немає"
+
+msgid "Sidebar|Weight"
+msgstr "Вага"
+
msgid "Snippets"
-msgstr "Фрагменти"
+msgstr ""
msgid "Something went wrong on our end."
msgstr "Щось пішло не так з нашого боку"
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
-msgstr "Щось пішло не так, намагаючись змінити статус блокування цього ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr "Щось пішло не так, при спробі зміни стану блокування ${this.issuableDisplayName}"
msgid "Something went wrong while fetching the projects."
msgstr "Щось пішло не так під час отримання проектів"
@@ -1874,7 +2270,7 @@ msgid "SortOptions|Least popular"
msgstr "Найменш популярний"
msgid "SortOptions|Less weight"
-msgstr "Найменша вага"
+msgstr "Менша вага"
msgid "SortOptions|Milestone"
msgstr "Етап"
@@ -1886,7 +2282,7 @@ msgid "SortOptions|Milestone due soon"
msgstr "Етап запланований незабаром"
msgid "SortOptions|More weight"
-msgstr "Найбільша вага"
+msgstr "Більша вага"
msgid "SortOptions|Most popular"
msgstr "Найбільш популярний"
@@ -1930,9 +2326,15 @@ msgstr "Розпочатий нещодавно"
msgid "SortOptions|Weight"
msgstr "Вага"
+msgid "Source"
+msgstr "Джерело"
+
msgid "Source code"
msgstr "Код"
+msgid "Source is not available"
+msgstr "Джерело недоступне"
+
msgid "Spam Logs"
msgstr "Спам-журнал"
@@ -1951,6 +2353,9 @@ msgstr "Почати %{new_merge_request} з цими змінами"
msgid "Start the Runner!"
msgstr "Запустіть Runner!"
+msgid "Stopped"
+msgstr "Зупинено"
+
msgid "Subgroups"
msgstr "Підгрупи"
@@ -1958,10 +2363,10 @@ msgid "Subscribe"
msgstr "Підписатися"
msgid "Switch branch/tag"
-msgstr "тег"
+msgstr ""
msgid "System Hooks"
-msgstr "Системні Hook'и"
+msgstr ""
msgid "Tag"
msgid_plural "Tags"
@@ -1972,6 +2377,75 @@ msgstr[2] "Тегів"
msgid "Tags"
msgstr "Теги"
+msgid "TagsPage|Browse commits"
+msgstr "Переглянути коміти"
+
+msgid "TagsPage|Browse files"
+msgstr "Переглянути файли"
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr "Неможливо знайти HEAD коміт до цього тегу"
+
+msgid "TagsPage|Cancel"
+msgstr "Скасувати"
+
+msgid "TagsPage|Create tag"
+msgstr "Створити тег"
+
+msgid "TagsPage|Delete tag"
+msgstr "Видалити тег"
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr "Видалення тега %{tag_name} не може бути скасовано. Ви впевнені?"
+
+msgid "TagsPage|Edit release notes"
+msgstr "Редагувати опис релізу"
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr "Ім'я існуючої гілки, тега або SHA коміта"
+
+msgid "TagsPage|Filter by tag name"
+msgstr "Фільтр по імені тега"
+
+msgid "TagsPage|New Tag"
+msgstr "Новий тег"
+
+msgid "TagsPage|New tag"
+msgstr "Новий тег"
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr "При бажанні Ви можете додати повідомлення в тег."
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr "Опис релізу"
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr "Репозиторій не містить тегів."
+
+msgid "TagsPage|Sort by"
+msgstr "Сортувати за"
+
+msgid "TagsPage|Tags"
+msgstr "Теги"
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr "Теги дають можливість позначати певні моменти в історії як важливі"
+
+msgid "TagsPage|This tag has no release notes."
+msgstr "Цей тег не містить опису релізу."
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr "Використовуйте команду git tag, щоб додати новий:"
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr "Напишіть свій опис релізу або перетягніть файли сюди..."
+
+msgid "TagsPage|protected"
+msgstr "захищений"
+
msgid "Target Branch"
msgstr "Цільова гілка"
@@ -1982,22 +2456,22 @@ msgid "Thanks! Don't show me this again"
msgstr "Дякую! Більше не показувати це повідомлення"
msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
-msgstr "Розширений глобальний пошук в GitLab - це потужний інструмент який заощаджує ваш час. Замість дублювання коду і витрати часу, ви можете шукати код всередині інших команд, який може допомогти у вашому проекті."
+msgstr "Розширений глобальний пошук в GitLab - це потужний інструмент який заощаджує ваш час. Замість дублювання коду і витрати часу, ви можете шукати код інших команд, який може допомогти у вашому проекті."
msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold"
msgstr "Поріг призупинення circuitbreaker має бути нижчий за поріг повного відключення"
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 "На стадії написання коду, показує час першого коміту до створення запиту на об'єднання. Дані будуть автоматично додані після створення вашого першого запиту на об'єднання."
+msgstr ""
msgid "The collection of events added to the data gathered for that stage."
-msgstr "Колекція подій додана до даних, зібраних для цього етапу."
+msgstr ""
msgid "The fork relationship has been removed."
-msgstr "Зв'язок форка видалена."
+msgstr ""
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
-msgstr "Етап випуску показує, скільки часу потрібно від створення проблеми до присвоєння випуску, або додавання проблеми в вашу дошку проблем. Почніть створювати проблеми, щоб переглядати дані для цього етапу."
+msgstr ""
msgid "The number of attempts GitLab will make to access a storage."
msgstr "Кількість спроб, які зробить GitLab для отримання доступу до сховища даних."
@@ -2015,10 +2489,10 @@ msgid "The pipelines schedule runs pipelines in the future, repeatedly, for spec
msgstr "Розклад конвеєрів запускає в майбутньому конвеєри, для певних гілок або тегів. Заплановані конвеєри успадковують обмеження на доступ до проекту на основі пов'язаного з ними користувача."
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
-msgstr "На етапі планування відображається час від попереднього кроку до першого коміту. Додається автоматично, як тільки відправится перший коміт."
+msgstr ""
msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "Стадія ПРОДакшин показує загальний час між створенням проблеми та розгортанням коду у ПРОДакшині. Дані будуть автоматично додані після завершення повної ідеї до ПРОДакшин циклу."
+msgstr ""
msgid "The project can be accessed by any logged in user."
msgstr "Доступ до проекту можливий будь-яким зареєстрованим користувачем."
@@ -2030,13 +2504,13 @@ msgid "The repository for this project does not exist."
msgstr "Репозиторій для цього проекту не існує."
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
-msgstr "Стадія огляду показує час від створення запиту про об'єднання до його виконання. Дані будуть автоматично додані після завершення першого запиту на злиття."
+msgstr ""
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
-msgstr "Стадія ДЕВ показує час між злиттям \"MR\" та розгортанням коду у ПРОДакшин. Дані автоматично додаються після розгортання у ПРОДакшин вперше."
+msgstr ""
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
-msgstr "Стадія тестування показує час, який GitLab CI виконує для запуску кожного конвеєра для відповідного запиту злиття. Дані будуть автоматично додані після завершення першого конвеєра."
+msgstr ""
msgid "The time in seconds GitLab will keep failure information. When no failures occur during this time, information about the mount is reset."
msgstr "Кількість секунд, протягом якої GitLab зберігає інформацію про збої. Якщо протягом цього періоду жодних збоїв не відбувається, інформація про точку монтування скидається."
@@ -2045,13 +2519,16 @@ msgid "The time in seconds GitLab will try to access storage. After this time a
msgstr "Кількість секунд, протягом якої GitLab намагатиметься отримати доступ до сховища даних. По завершенню цього періоду буде згенерована помилка про перевищення ліміту часу."
msgid "The time taken by each data entry gathered by that stage."
-msgstr "Час, витрачений на кожен елемент, зібраний на цьому етапі."
+msgstr ""
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr "Середнє значення в рядку. Приклад: між 3, 5, 9, середніми 5, між 3, 5, 7, 8, середніми (5 + 7) / 2 = 6."
msgid "There are problems accessing Git storage: "
-msgstr "Є проблеми з доступом до сховища: "
+msgstr ""
+
+msgid "This board\\'s scope is reduced"
+msgstr "Видимість цієї дошки обмежена"
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr "Ця гілка була змінена після того моменту, коли ви почали її редагувати. Ви хотіли б створити нову?"
@@ -2069,11 +2546,14 @@ msgid "This issue is locked."
msgstr "Ця проблема заблокована."
msgid "This means you can not push code until you create an empty repository or import existing one."
-msgstr "Це означає, що ви не можете відправляти код, поки не створите порожній репозиторій або НЕ імпортуєте існуючий."
+msgstr ""
msgid "This merge request is locked."
msgstr "Цей запит на злиття заблоковано."
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "Час до початку потрапляння проблеми в планувальник"
@@ -2081,7 +2561,7 @@ msgid "Time before an issue starts implementation"
msgstr "Час до початку роботи над проблемою"
msgid "Time between merge request creation and merge/close"
-msgstr "Час між створенням запиту злиття і злиттям або закриттям"
+msgstr ""
msgid "Time until first merge request"
msgstr "Час до першого запиту на злиття"
@@ -2224,14 +2704,26 @@ msgstr[2] "хвилин"
msgid "Time|s"
msgstr "секунд(а)"
+msgid "Title"
+msgstr "Назва"
+
msgid "Total Time"
msgstr "Загальний час"
+msgid "Total issue time spent"
+msgstr "Загальний витрачений час на проблему"
+
msgid "Total test time for all commits/merges"
msgstr "Загальний час, щоб перевірити всі коміти/злиття"
msgid "Track activity with Contribution Analytics."
-msgstr "Відстежувати активність за допомогою Аналітики контриб’юторів."
+msgstr ""
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr "Відстежуйте групи проблем зі спільною темою з різних проектів та етапів"
+
+msgid "Turn on Service Desk"
+msgstr "Ввімкнути Service Desk"
msgid "Unlock"
msgstr "Розблокувати"
@@ -2249,16 +2741,16 @@ msgid "Upgrade your plan to activate Advanced Global Search."
msgstr "Перейдіть на вищий тарифний план щоб активувати Покращений Глобальний Пошук."
msgid "Upgrade your plan to activate Contribution Analytics."
-msgstr "Перейдіть на вищий тарифний план для активації Аналітики контриб’юторів."
+msgstr ""
msgid "Upgrade your plan to activate Group Webhooks."
-msgstr "Перейдіть на вищий тарифний план щоб активувати Групові Webhook’и."
+msgstr ""
msgid "Upgrade your plan to activate Issue weight."
-msgstr "Підвищіть план щоб активувати вагу обговорень."
+msgstr ""
msgid "Upgrade your plan to improve Issue boards."
-msgstr "Підвищіть свій план, щоб покращити дошки обговорень."
+msgstr ""
msgid "Upload New File"
msgstr "Завантажити новий файл"
@@ -2269,6 +2761,9 @@ msgstr "Завантажити файл"
msgid "UploadLink|click to upload"
msgstr "Натисніть, щоб завантажити"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr "Використовуйте Service Desk для зв’язку з вашими користувачами (наприклад, щоб запропонувати клієнтську підтримку) через електронну пошту безпосередньо із GitLab"
+
msgid "Use the following registration token during setup:"
msgstr "Використовувати токен під час установки:"
@@ -2300,10 +2795,13 @@ msgid "Want to see the data? Please ask an administrator for access."
msgstr "Хочете побачити дані? Будь ласка, попросить у адміністратора доступ."
msgid "We don't have enough data to show this stage."
-msgstr "Ми не маємо достатньо даних для показу цього етапу."
+msgstr ""
+
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr "Ми хочемо бути впевнені, що це ви, будь ласка, підтвердіть, що ви не робот."
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
-msgstr "Webhook дозволяють вам викликати адресу URL якщо, наприклад, відправлений новий код або створено нову тему повідомлення. Ви можете налаштувати Webhook так, щоб він реагував на певні події, такі як відправки коду, обговорення або запити на злиття. Групові Webhook’и застосовуються до всіх проектів в групі і дозволяють вам стандартизувати функціональність Webhook’ів для всієї вашої групи."
+msgstr ""
msgid "Weight"
msgstr "Вага"
@@ -2330,7 +2828,7 @@ msgid "WikiClone|Start Gollum and edit locally"
msgstr "Запустіть Gollum і редагуйте локально"
msgid "WikiEmptyPageError|You are not allowed to create wiki pages"
-msgstr "Ви не можете створювати вікі-сторінки"
+msgstr ""
msgid "WikiHistoricalPage|This is an old version of this page."
msgstr "Це — стара версія сторінки."
@@ -2360,7 +2858,7 @@ msgid "WikiNewPageTip|Tip: You can specify the full path for the new file. We wi
msgstr "Порада: можна вказати повний шлях до нового файлу. Ми автоматично створимо всі відсутні каталоги."
msgid "WikiNewPageTitle|New Wiki Page"
-msgstr "Нова Вікі-сторінка"
+msgstr ""
msgid "WikiPageConfirmDelete|Are you sure you want to delete this page?"
msgstr "Ви дійсно бажаєте видалити цю сторінку?"
@@ -2390,7 +2888,7 @@ msgid "Wiki|Create page"
msgstr "Створити сторінку"
msgid "Wiki|Edit Page"
-msgstr "Редагувати сторінку"
+msgstr "Редагування cторінки"
msgid "Wiki|Empty page"
msgstr "Порожня сторінка"
@@ -2411,10 +2909,10 @@ msgid "Wiki|Pages"
msgstr "Сторінки"
msgid "Wiki|Wiki Pages"
-msgstr "Вікі-сторінки"
+msgstr ""
msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members."
-msgstr "З аналітикою контриб’юторів ви може вивчати активність в обговореннях, запитах на злиття і подій відправки коду для вашої організації і її учасників."
+msgstr ""
msgid "Withdraw Access Request"
msgstr "Скасувати запит доступу"
@@ -2431,14 +2929,8 @@ msgstr "Ви збираєтеся видалити зв'язок з форка
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Ви збираєтеся передати проект %{project_name_with_namespace} іншому власнику. Ви АБСОЛЮТНО впевнені?"
-msgid "You are on a read-only GitLab instance."
-msgstr "Ви знаходитеся на інстансі Gitlab \"тільки для читання\"."
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr "Ви знаходитеся на інстансі Gitlab \"тільки для читання\". Якщо ви хочете внести зміни, вам необхідно перейти на %{link_to_primary_node}."
-
msgid "You can only add files when you are on a branch"
-msgstr "Ви можете додавати тільки файли, коли перебуваєте в гілці"
+msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
msgstr "Ви не можете записувати на вторинні інстанси \"тільки для читання\" GitLab Geo. Будь ласка використовуйте %{link_to_primary_node}."
@@ -2471,10 +2963,13 @@ msgid "You will receive notifications only for comments in which you were @menti
msgstr "Ви будете отримувати повідомлення тільки для коментарів, в яких ви були @згадані"
msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
-msgstr "Ви не зможете отримувати і відправляти код проекту через %{protocol} поки %{set_password_link} в ваш аккаунт"
+msgstr ""
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
-msgstr "Ви не зможете отримувати і відправляти код проекту через SSH поки %{add_ssh_key_link} в ваш профіль."
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
msgid "Your comment will not be visible to the public."
msgstr "Ваш коментар не буде видимим для всіх."
@@ -2488,6 +2983,12 @@ msgstr "Ваше ім'я"
msgid "Your projects"
msgstr "Ваші проекти"
+msgid "branch name"
+msgstr "ім'я гілки"
+
+msgid "by"
+msgstr "від"
+
msgid "commit"
msgstr "коміт"
@@ -2505,9 +3006,9 @@ msgstr "Повідомлення електронною поштою"
msgid "parent"
msgid_plural "parents"
-msgstr[0] "джерело"
-msgstr[1] "джерела"
-msgstr[2] "джерел"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
msgid "password"
msgstr "пароль"
@@ -2515,8 +3016,11 @@ msgstr "пароль"
msgid "personal access token"
msgstr "особистий токен доступу"
+msgid "source"
+msgstr "джерело"
+
msgid "to help your contributors communicate effectively!"
-msgstr "щоб допомогти вашим контриб’юторам ефективно спілкуватися!"
+msgstr ""
msgid "username"
msgstr "ім'я користувача"
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index e1bc9219908..f0a5453f224 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-23 02:44-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:42-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}:已 %{failed_attempts} 次尝试访问存储失败:"
+msgid "%{text} is available"
+msgstr "%{text}可用"
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(如需了解更多的安装信息,请查看 %{link})"
@@ -104,14 +107,11 @@ msgid "Add Contribution guide"
msgstr "添加贡献指南"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
-msgstr "添加来自 Webhooks 或者 GitLab 企业版的团队。"
+msgstr "添加组Webhooks和GitLab企业版。"
msgid "Add License"
msgstr "添加许可证"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "新建一个用于推送或拉取的 SSH 秘钥到账号中。"
-
msgid "Add new directory"
msgstr "添加目录"
@@ -124,6 +124,15 @@ msgstr "高级设置"
msgid "All"
msgstr "全部"
+msgid "An error occurred when toggling the notification subscription"
+msgstr "切换通知订阅时发生错误"
+
+msgid "An error occurred when updating the issue weight"
+msgstr "更新议题权重时发生错误"
+
+msgid "An error occurred while fetching sidebar data"
+msgstr "获取侧边栏数据时发生错误"
+
msgid "An error occurred. Please try again."
msgstr "发生了错误,请再试一次。"
@@ -133,6 +142,12 @@ msgstr "外观"
msgid "Applications"
msgstr "应用程序"
+msgid "Apr"
+msgstr "四"
+
+msgid "April"
+msgstr "四月"
+
msgid "Archived project! Repository is read-only"
msgstr "项目已归档!存储库为只读状态"
@@ -160,6 +175,12 @@ msgstr "产物"
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "拖放文件到此处或者 %{upload_link}"
+msgid "Aug"
+msgstr "八"
+
+msgid "August"
+msgstr "八月"
+
msgid "Authentication Log"
msgstr "认证日志"
@@ -193,50 +214,53 @@ msgstr "想了解更多请访问 %{link_to_documentation}"
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr "您可以为此项目激活 %{link_to_settings}。"
+msgid "Available"
+msgstr "可用的"
+
msgid "Billing"
msgstr "账单"
msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
-msgstr "%{group_name} 正在使用 %{plan_link} 方案。"
+msgstr "%{group_name}目前位于%{plan_link}计划中。"
msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
-msgstr "在当前方案中不可使用自动降级或自动升级。"
+msgstr "自动降级、升级到某些计划目前不可用。"
msgid "BillingPlans|Current plan"
-msgstr "当前方案"
+msgstr "当前计划"
msgid "BillingPlans|Customer Support"
-msgstr "用户支持"
+msgstr "客户支持"
msgid "BillingPlans|Downgrade"
msgstr "降级"
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
-msgstr "阅读 %{faq_link} 以了解更多信息。"
+msgstr "通过阅读我们的%{faq_link}了解有关每个计划的更多信息。"
msgid "BillingPlans|Manage plan"
-msgstr "管理方案"
+msgstr "管理计划"
msgid "BillingPlans|Please contact %{customer_support_link} in that case."
-msgstr "请联系 %{customer_support_link}"
+msgstr "在这种情况下请联系%{customer_support_link}。"
msgid "BillingPlans|See all %{plan_name} features"
-msgstr "查看所有 %{plan_name} 功能"
+msgstr "查看所有%{plan_name}功能"
msgid "BillingPlans|This group uses the plan associated with its parent group."
-msgstr "使用与其父项目一致的方案"
+msgstr "该群组使用其父群组相关联的计划。"
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
-msgstr "访问 %{parent_billing_page_link} 以管理该项目的计费方案。"
+msgstr "要管理此群组的计划,请访问%{parent_billing_page_link}的账单部分。"
msgid "BillingPlans|Upgrade"
msgstr "升级"
msgid "BillingPlans|You are currently on the %{plan_link} plan."
-msgstr "您目前正在使用 %{plan_link} 方案。"
+msgstr "您目前正在使用%{plan_link}计划。"
msgid "BillingPlans|frequently asked questions"
-msgstr "常见问题"
+msgstr "常问问题"
msgid "BillingPlans|monthly"
msgstr "每月"
@@ -245,7 +269,7 @@ msgid "BillingPlans|paid annually at %{price_per_year}"
msgstr "每年支付 %{price_per_year}"
msgid "BillingPlans|per user"
-msgstr "每个用户"
+msgstr "每用户"
msgid "Branch"
msgid_plural "Branches"
@@ -257,6 +281,12 @@ msgstr "已创建分支 %{branch_name} 。如需设置自动部
msgid "Branch has changed"
msgstr "分支已有新变更"
+msgid "Branch is already taken"
+msgstr "分支已被采用"
+
+msgid "Branch name"
+msgstr "分支名称"
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "搜索分支"
@@ -318,7 +348,7 @@ msgid "Branches|Sort by"
msgstr "排序"
msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart."
-msgstr "分支无法自动提交,因为与上游分支冲突。"
+msgstr "分支不能自动更新,因为它与上游分支不一致。"
msgid "Branches|The default branch cannot be deleted"
msgstr "无法删除默认分支"
@@ -333,13 +363,13 @@ msgid "Branches|To confirm, type %{branch_name_confirmation}:"
msgstr "要确认?请输入 %{branch_name_confirmation} :"
msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
-msgstr "若要放弃本地更改并使用上游版本覆盖本分支,请先删除并“立即更新”。"
+msgstr "要放弃本地更改并覆盖上游版本的分支,请在此处将其删除,然后选择上面的“立即更新”。"
msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
msgstr "将要永久删除受保护 %{branch_name} 分支。"
msgid "Branches|diverged from upstream"
-msgstr "与上游存在差异"
+msgstr "上游分支"
msgid "Branches|merged"
msgstr "已合并的"
@@ -381,7 +411,7 @@ msgid "Cancel edit"
msgstr "取消编辑"
msgid "Change Weight"
-msgstr "变更权重"
+msgstr "改变权重"
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "选择分支"
@@ -404,6 +434,12 @@ msgstr "统计图"
msgid "Chat"
msgstr "即时通讯"
+msgid "Checking %{text} availability…"
+msgstr "正在检查%{text}的可用性..."
+
+msgid "Checking branch availability..."
+msgstr "正在检查分支的可用性..."
+
msgid "Cherry-pick this commit"
msgstr "优选此提交"
@@ -479,8 +515,41 @@ msgstr "关闭"
msgid "Cluster"
msgstr "集群"
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
-msgstr "必须在此帐户下创建 %{link_to_container_project}"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr "%{appList}已成功安装在您的群集上"
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr "%{boldNotice}这会增加一些额外的资源,如负载均衡器,这会产生额外的成本。请参阅%{pricingLink}"
+
+msgid "ClusterIntegration|API URL"
+msgstr "API地址"
+
+msgid "ClusterIntegration|Active"
+msgstr "启用"
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr "添加一个现有的集群"
+
+msgid "ClusterIntegration|Add cluster"
+msgstr "添加集群"
+
+msgid "ClusterIntegration|All"
+msgstr "所有"
+
+msgid "ClusterIntegration|Applications"
+msgstr "应用程序"
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr "CA证书"
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr "证书授权包(PEM格式)"
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr "选择如何设置集群集成"
+
+msgid "ClusterIntegration|Cluster"
+msgstr "集群"
msgid "ClusterIntegration|Cluster details"
msgstr "集群详情"
@@ -498,26 +567,59 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab
msgstr "此项目已启用集群集成。禁用此集成不会影响您的集群,它只会暂时关闭 GitLab 的连接。"
msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..."
-msgstr "集群正在 Google Kubernetes Engine 上创建..."
+msgstr "群集正在Google Kubernetes Engine上创建..."
msgid "ClusterIntegration|Cluster name"
msgstr "集群名称"
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
-msgstr "集群已在 Google Kubernetes Engine 上成功创建"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr "集群已在Google Kubernetes Engine上成功创建。刷新页面以查看集群的详细信息"
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr "集群允许您使用审阅应用程序、部署应用程序、运行流水线等等。%{link_to_help_page}"
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr "复制API地址"
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr "复制CA证书"
+
+msgid "ClusterIntegration|Copy Token"
+msgstr "复制令牌"
msgid "ClusterIntegration|Copy cluster name"
msgstr "复制集群名称"
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr "在 GitLab 上创建一个 Google Engine 集群"
+
msgid "ClusterIntegration|Create cluster"
msgstr "创建集群"
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
-msgstr "在 Google Kubernetes Engine 上创建新集群"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr "在 Google Kubernetes Engine 上创建集群"
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr "在GKE中创建"
msgid "ClusterIntegration|Enable cluster integration"
msgstr "启用集群集成"
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr "输入现有的 Kubernetes 集群详细信息"
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr "输入您的集群详细信息"
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr "环境模式"
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr "GKE价格"
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr "GitLab Runner"
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr "Google 云平台项目ID"
@@ -527,27 +629,75 @@ msgstr "Google Kubernetes Engine"
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr "Google Kubernetes Engine 项目"
+msgid "ClusterIntegration|Helm Tiller"
+msgstr "Helm Tiller"
+
+msgid "ClusterIntegration|Inactive"
+msgstr "待用"
+
+msgid "ClusterIntegration|Ingress"
+msgstr "入口"
+
+msgid "ClusterIntegration|Install"
+msgstr "安装"
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr "在集群上安装应用程序。阅读更多关于%{helpLink}"
+
+msgid "ClusterIntegration|Installed"
+msgstr "已安装"
+
+msgid "ClusterIntegration|Installing"
+msgstr "安装中"
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr "集群自动化集成"
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "了解详细%{link_to_documentation}"
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr "了解更多集群的信息"
+
msgid "ClusterIntegration|Machine type"
msgstr "机器类型"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr "确保您的帐户符合创建集群的%{link_to_requirements}"
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
-msgstr "管理您的 GitLab 项目集群集成"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
+msgstr "在 GitLab 项目上管理集群集成"
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr "访问%{link_gke}来管理您的集群"
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr "GitLab企业高级版和旗舰版提供了多个集群"
+
+msgid "ClusterIntegration|Note:"
+msgstr "注意:"
+
msgid "ClusterIntegration|Number of nodes"
msgstr "节点数量"
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr "请为您的群集输入访问信息。如果您需要帮助,可以阅读我们关于集群的 %{link_to_help_page}"
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr "请确保您的 Google 帐户符合以下要求:"
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr "设置集群时出现问题"
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr "设置集群列表时出现问题"
+
+msgid "ClusterIntegration|Project ID"
+msgstr "项目 ID"
+
+msgid "ClusterIntegration|Project namespace"
+msgstr "项目命名空间"
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr "项目命名空间(可选,唯一)"
@@ -560,8 +710,14 @@ msgstr "删除集群集成"
msgid "ClusterIntegration|Remove integration"
msgstr "删除集成"
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
-msgstr "删除集群集成将删除您添加到此项目的集群配置。它不会删除您的项目。"
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr "删除集群集成将删除已添加到此项目的集群配置。它不会删除 Google Kubernetes Engine 上的集群。"
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr "请求安装失败"
+
+msgid "ClusterIntegration|Save changes"
+msgstr "保存更改"
msgid "ClusterIntegration|See and edit the details for your cluster"
msgstr "查看并编辑集群的详细信息"
@@ -575,20 +731,38 @@ msgstr "看到您的项目"
msgid "ClusterIntegration|See zones"
msgstr "查看区域"
+msgid "ClusterIntegration|Service token"
+msgstr "服务令牌"
+
+msgid "ClusterIntegration|Show"
+msgstr "显示"
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr "发生了内部错误"
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr "在 Google Kubernetes Engine 上创建集群时发生错误"
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr "安装 %{title} 时发生故障"
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr "没有要显示的集群"
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr "此帐户必须有权在下面指定的%{link_to_container_project}中创建集群"
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr "切换集群"
+msgid "ClusterIntegration|Token"
+msgstr "令牌"
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "使用与此项目关联的集群,您可以使用审阅应用程序,部署应用程序,运行流水线等等。"
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
-msgstr "您的帐户必须有%{link_to_kubernetes_engine}"
+msgstr "您的帐户必须拥有%{link_to_kubernetes_engine}"
msgid "ClusterIntegration|Zone"
msgstr "区域"
@@ -599,9 +773,15 @@ msgstr "访问 Google Kubernetes Engine"
msgid "ClusterIntegration|cluster"
msgstr "集群"
+msgid "ClusterIntegration|documentation"
+msgstr "文档"
+
msgid "ClusterIntegration|help page"
msgstr "帮助页面"
+msgid "ClusterIntegration|installing applications"
+msgstr "安装应用程序"
+
msgid "ClusterIntegration|meets the requirements"
msgstr "符合要求"
@@ -615,10 +795,6 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "提交"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] "提交 %d 个文件"
-
msgid "Commit Message"
msgstr "提交消息"
@@ -700,11 +876,20 @@ msgstr "贡献指南"
msgid "Contributors"
msgstr "贡献者"
+msgid "ContributorsPage|Building repository graph."
+msgstr "构建存储库图标。"
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr "提交到%{branch_name},排除合并提交。限于6000次提交。"
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr "请稍等片刻,这个页面会在准备好时自动刷新。"
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
-msgstr "控制此次要节点的 LFS/attachment 的最大并发性"
+msgstr "控制此次要节点的 LFS/attachment 的最大并发"
msgid "Control the maximum concurrency of repository backfill for this secondary node"
-msgstr "控制此次要节点的存储库的最大并发"
+msgstr "控制此次要节点的存储库最大并发"
msgid "Copy SSH public key to clipboard"
msgstr "复制 SSH 公钥到剪贴板"
@@ -727,6 +912,9 @@ msgstr "创建目录"
msgid "Create empty bare repository"
msgstr "创建空的存储库"
+msgid "Create epic"
+msgstr "创建EPIC"
+
msgid "Create file"
msgstr "创建文件"
@@ -754,6 +942,9 @@ msgstr "标签"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "创建个人访问令牌"
+msgid "Creating epic"
+msgstr "创建EPIC中"
+
msgid "Cron Timezone"
msgstr "Cron 时区"
@@ -799,6 +990,12 @@ msgstr "所有"
msgid "DashboardProjects|Personal"
msgstr "个人"
+msgid "Dec"
+msgstr "十二"
+
+msgid "December"
+msgstr "十二月"
+
msgid "Define a custom pattern with cron syntax"
msgstr "使用 Cron 语法定义自定义模式"
@@ -816,7 +1013,7 @@ msgid "Description"
msgstr "描述"
msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "描述模板允许您为项目的议题和合并请求在创建时选择特定的模版。"
+msgstr "描述模板允许您为项目的问题和合并请求定义描述字段的特定模板。"
msgid "Details"
msgstr "详情"
@@ -872,6 +1069,72 @@ msgstr "编辑 %{id} 流水线计划"
msgid "Emails"
msgstr "电子邮件"
+msgid "Environments|An error occurred while fetching the environments."
+msgstr "获取环境时发生错误。"
+
+msgid "Environments|An error occurred while making the request."
+msgstr "发送请求时发生错误。"
+
+msgid "Environments|Commit"
+msgstr "提交"
+
+msgid "Environments|Deployment"
+msgstr "部署"
+
+msgid "Environments|Environment"
+msgstr "环境"
+
+msgid "Environments|Environments"
+msgstr "环境"
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr "环境是部署代码的地方,例如预生产或生产。"
+
+msgid "Environments|Job"
+msgstr "作业"
+
+msgid "Environments|New environment"
+msgstr "新建环境"
+
+msgid "Environments|No deployments yet"
+msgstr "未部署"
+
+msgid "Environments|Open"
+msgstr "打开"
+
+msgid "Environments|Re-deploy"
+msgstr "重新部署"
+
+msgid "Environments|Read more about environments"
+msgstr "了解有关环境的更多信息"
+
+msgid "Environments|Rollback"
+msgstr "还原"
+
+msgid "Environments|Show all"
+msgstr "显示全部"
+
+msgid "Environments|Updated"
+msgstr "已更新"
+
+msgid "Environments|You don't have any environments right now."
+msgstr "你还没有设置环境"
+
+msgid "Epic will be removed! Are you sure?"
+msgstr "EPIC将被删除!是否确定?"
+
+msgid "Epics"
+msgstr "EPIC"
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr "EPIC让你更有效率地管理你的项目组合,而且不费吹灰之力"
+
+msgid "Error creating epic"
+msgstr "创建EPIC时出错"
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr "切换通知订阅时发生错误"
+
msgid "EventFilterBy|Filter by all"
msgstr "全部"
@@ -911,6 +1174,12 @@ msgstr "无法变更所有者"
msgid "Failed to remove the pipeline schedule"
msgstr "无法删除流水线计划"
+msgid "Feb"
+msgstr "二"
+
+msgid "February"
+msgstr "二月"
+
msgid "File name"
msgstr "文件名"
@@ -957,14 +1226,29 @@ msgstr "GPG 密钥"
msgid "Geo Nodes"
msgstr "Geo 节点"
+msgid "GeoNodeSyncStatus|Failed"
+msgstr "失败"
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr "节点出现故障或损坏。"
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr "节点运行缓慢、超载, 或者在停机后刚刚恢复。"
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr "未同步"
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr "已同步"
+
msgid "Geo|File sync capacity"
-msgstr "文件同步容量"
+msgstr "文件同步量"
msgid "Geo|Groups to replicate"
-msgstr "要复制的群组"
+msgstr "复制群组"
msgid "Geo|Repository sync capacity"
-msgstr "存储库同步容量"
+msgstr "存储库同步量"
msgid "Geo|Select groups to replicate."
msgstr "选择要复制的群组。"
@@ -1020,9 +1304,6 @@ msgstr "找不到群组"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr "您可以管理群组成员的权限并访问群组中的每个项目。"
-msgid "GroupsTreeRole|as"
-msgstr "的"
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr "您确定要离开群组“${this.group.fullName}”吗?"
@@ -1053,6 +1334,9 @@ msgstr "对不起,没有搜索到任何符合的群组"
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr "对不起,没有任何群组或项目符合您的搜索"
+msgid "Have your users email"
+msgstr "有你的用户邮件"
+
msgid "Health Check"
msgstr "健康检查"
@@ -1111,9 +1395,6 @@ msgstr "周期分析简介"
msgid "Issue board focus mode"
msgstr "议题看板模式"
-msgid "Issue boards with milestones"
-msgstr "议题看板与里程碑"
-
msgid "Issue events"
msgstr "议题事件"
@@ -1126,6 +1407,24 @@ msgstr "看板"
msgid "Issues"
msgstr "议题"
+msgid "Jan"
+msgstr "一"
+
+msgid "January"
+msgstr "一月"
+
+msgid "Jul"
+msgstr "七"
+
+msgid "July"
+msgstr "七月"
+
+msgid "Jun"
+msgstr "六"
+
+msgid "June"
+msgstr "六月"
+
msgid "LFSStatus|Disabled"
msgstr "停用"
@@ -1197,9 +1496,18 @@ msgstr "已锁定文件"
msgid "Login"
msgstr "登录"
+msgid "Mar"
+msgstr "三"
+
+msgid "March"
+msgstr "三月"
+
msgid "Maximum git storage failures"
msgstr "最大 git 存储失败"
+msgid "May"
+msgstr "五"
+
msgid "Median"
msgstr "中位数"
@@ -1243,9 +1551,15 @@ msgstr "创建流水线计划"
msgid "New branch"
msgstr "新建分支"
+msgid "New branch unavailable"
+msgstr "新分支不可用"
+
msgid "New directory"
msgstr "新建目录"
+msgid "New epic"
+msgstr "新EPIC"
+
msgid "New file"
msgstr "新建文件"
@@ -1282,6 +1596,9 @@ msgstr "没有存储库"
msgid "No schedules"
msgstr "没有计划"
+msgid "No time spent"
+msgstr "没有花费时间"
+
msgid "None"
msgstr "无"
@@ -1348,18 +1665,33 @@ msgstr "关注"
msgid "Notifications"
msgstr "通知"
+msgid "Nov"
+msgstr "十一"
+
+msgid "November"
+msgstr "十一月"
+
msgid "Number of access attempts"
msgstr "尝试访问次数"
msgid "Number of failures before backing off"
msgstr "退出前的失败次数"
+msgid "Oct"
+msgstr "十"
+
+msgid "October"
+msgstr "十月"
+
msgid "OfSearchInADropdown|Filter"
msgstr "筛选"
msgid "Only project members can comment."
msgstr "只有项目成员可以发表评论。"
+msgid "Opened"
+msgstr "已打开"
+
msgid "OpenedNDaysAgo|Opened"
msgstr "创建于"
@@ -1492,6 +1824,9 @@ msgstr "于阶段"
msgid "Pipeline|with stages"
msgstr "于阶段"
+msgid "Please solve the reCAPTCHA"
+msgstr "请填写验证码。"
+
msgid "Preferences"
msgstr "偏好设置"
@@ -1597,9 +1932,15 @@ msgstr "分支图"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr "联系管理员更改此设置。"
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr "立即在默认分支上运行流水线"
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "只有已签署提交才可以推送到此存储库。"
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr "设置CI/CD时出现JavaScript问题"
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr "此设置已应用于服务器级别,可由管理员覆盖。"
@@ -1636,6 +1977,39 @@ msgstr "对不起,没有搜索到符合条件的项目"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "此功能需要浏览器支持 localStorage"
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr "默认情况下,Prometheus 侦听 ‘http://localhost:9090’。不建议更改默认地址和端口,因为这可能会影响或冲突在 GitLab 服务器上运行的其他服务。"
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr "查找和配置指标..."
+
+msgid "PrometheusService|Metrics"
+msgstr "指标"
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr "指标会根据指定的指标库自动配置和监控。"
+
+msgid "PrometheusService|Missing environment variable"
+msgstr "没有环境变量"
+
+msgid "PrometheusService|Monitored"
+msgstr "监测"
+
+msgid "PrometheusService|More information"
+msgstr "更多的信息"
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr "没有监测指标。要开始监测,请部署到环境中。"
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr "Prometheus API 地址,例如 http://prometheus.example.com/"
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr "Prometheus 监测"
+
+msgid "PrometheusService|View environments"
+msgstr "查看环境"
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr "公开 - 群组和任何公共项目可以在没有任何身份验证的情况下查看。"
@@ -1732,6 +2106,9 @@ msgstr "日程"
msgid "Scheduling Pipelines"
msgstr "流水线计划"
+msgid "Scoped issue boards"
+msgstr "议题看板范围"
+
msgid "Search branches and tags"
msgstr "搜索分支和标签"
@@ -1753,6 +2130,12 @@ msgstr "选择时区"
msgid "Select target branch"
msgstr "选择目标分支"
+msgid "Sep"
+msgstr "九"
+
+msgid "September"
+msgstr "九月"
+
msgid "Service Templates"
msgstr "服务模板"
@@ -1784,14 +2167,29 @@ msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "显示 %d 个事件"
+msgid "Sidebar|Change weight"
+msgstr "编辑宽度"
+
+msgid "Sidebar|Edit"
+msgstr "编辑"
+
+msgid "Sidebar|No"
+msgstr "无"
+
+msgid "Sidebar|None"
+msgstr "无"
+
+msgid "Sidebar|Weight"
+msgstr "宽度"
+
msgid "Snippets"
msgstr "代码片段"
msgid "Something went wrong on our end."
msgstr "发生了错误。"
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
-msgstr "尝试更改 ${this.issuableDisplayName(this.issuableType)} 的锁定状态时发生错误"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr "试图改变 ${this.issuableDisplayName} 的锁定状态时出错了"
msgid "Something went wrong while fetching the projects."
msgstr "拉取项目时发生错误。"
@@ -1854,7 +2252,7 @@ msgid "SortOptions|Milestone due soon"
msgstr "即将截止的里程碑"
msgid "SortOptions|More weight"
-msgstr "更大的权重"
+msgstr "最高权重"
msgid "SortOptions|Most popular"
msgstr "最受欢迎"
@@ -1898,9 +2296,15 @@ msgstr "现在开始"
msgid "SortOptions|Weight"
msgstr "权重"
+msgid "Source"
+msgstr "源"
+
msgid "Source code"
msgstr "源代码"
+msgid "Source is not available"
+msgstr "源不可用"
+
msgid "Spam Logs"
msgstr "垃圾信息日志"
@@ -1919,6 +2323,9 @@ msgstr "由此更改 %{new_merge_request}"
msgid "Start the Runner!"
msgstr "启动 Runner!"
+msgid "Stopped"
+msgstr "已停止"
+
msgid "Subgroups"
msgstr "子群组"
@@ -1938,6 +2345,75 @@ msgstr[0] "标签"
msgid "Tags"
msgstr "标签"
+msgid "TagsPage|Browse commits"
+msgstr "浏览提交"
+
+msgid "TagsPage|Browse files"
+msgstr "浏览文件"
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr "无法找到此标记的HEAD提交"
+
+msgid "TagsPage|Cancel"
+msgstr "取消"
+
+msgid "TagsPage|Create tag"
+msgstr "创建标签"
+
+msgid "TagsPage|Delete tag"
+msgstr "删除标签"
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr "删除 %{tag_name} 后将无法恢复,您确定?"
+
+msgid "TagsPage|Edit release notes"
+msgstr "编辑发行记录"
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr "已存在分支名称,标记或提交SHA"
+
+msgid "TagsPage|Filter by tag name"
+msgstr "根据标签名称过滤"
+
+msgid "TagsPage|New Tag"
+msgstr "新标签"
+
+msgid "TagsPage|New tag"
+msgstr "新标签"
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr "(可选)添加一条消息到标签。"
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr "(可选)将发行说明添加到标签。它们将被存储在GitLab数据库中并显示在标签页上。"
+
+msgid "TagsPage|Release notes"
+msgstr "发行说明"
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr "版本库还没有标签。"
+
+msgid "TagsPage|Sort by"
+msgstr "排序"
+
+msgid "TagsPage|Tags"
+msgstr "标签"
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr "标签具有在提交历史上标记特定提交的能力"
+
+msgid "TagsPage|This tag has no release notes."
+msgstr "此标签没有发行说明。"
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr "使用git tag命令添加一个:"
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr "撰写发行说明或拖放文件到这里..."
+
+msgid "TagsPage|protected"
+msgstr "已保护"
+
msgid "Target Branch"
msgstr "目标分支"
@@ -1945,10 +2421,10 @@ msgid "Team"
msgstr "团队"
msgid "Thanks! Don't show me this again"
-msgstr "不再显示该提示"
+msgstr "谢谢 ! 请不要再显示"
msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
-msgstr "GitLab 中的高级全局搜索功能是非常强大的搜索服务。您可以搜索其他团队的代码以帮助您完善自己项目中的代码。从而避免创建重复的代码或浪费时间。"
+msgstr "GitLab 中的高级全局搜索功能是非常强大的搜索服务。您可以搜索其他团队的代码以帮助您完善自己项目中的代码。从而避免创建重复的代码和浪费时间。"
msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold"
msgstr "断路器关闭阈值应该低于故障计数阈值"
@@ -2019,6 +2495,9 @@ msgstr "中位数是一个数列中最中间的值。例如在 3、5、9 之间
msgid "There are problems accessing Git storage: "
msgstr "访问 Git 存储时出现问题:"
+msgid "This board\\'s scope is reduced"
+msgstr "这个看板的范围缩小了"
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr "自您开始编辑后, 此分支已更改。您想创建一个新的分支吗?"
@@ -2040,6 +2519,9 @@ msgstr "在创建一个空的存储库或导入现有存储库之前,将无法
msgid "This merge request is locked."
msgstr "此合并请求已锁定。"
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr "这些电子邮件自动生成为问题(评论生成为电子邮件对话)在这里列出。"
+
msgid "Time before an issue gets scheduled"
msgstr "议题被列入日程表的时间"
@@ -2186,14 +2668,26 @@ msgstr[0] "分钟"
msgid "Time|s"
msgstr "秒"
+msgid "Title"
+msgstr "标题"
+
msgid "Total Time"
msgstr "总时间"
+msgid "Total issue time spent"
+msgstr "议题花费时间总计"
+
msgid "Total test time for all commits/merges"
msgstr "所有提交和合并的总测试时间"
msgid "Track activity with Contribution Analytics."
-msgstr "跟踪分析贡献与活动。"
+msgstr "跟踪活动与贡献的分析。"
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr "在项目和里程碑之间跟踪共享主题的议题组"
+
+msgid "Turn on Service Desk"
+msgstr "打开服务台"
msgid "Unlock"
msgstr "解锁"
@@ -2231,6 +2725,9 @@ msgstr "上传文件"
msgid "UploadLink|click to upload"
msgstr "点击上传"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr "使用服务台在GitLab内部通过电子邮件与用户联系(例如提供客户支持)"
+
msgid "Use the following registration token during setup:"
msgstr "在安装过程中使用以下注册令牌:"
@@ -2264,6 +2761,9 @@ msgstr "权限不足。如需查看相关数据,请向管理员申请权限。
msgid "We don't have enough data to show this stage."
msgstr "该阶段的数据不足,无法显示。"
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr "我们要确定你是不是机器人。"
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr "如果有新的推送或新的议题,Webhook将自动触发您设置URL。 您可以配置 Webhook 来监听特定事件,如推送、议题或合并请求。 群组 Webhook 将适用于团队中的所有项目,并允许您设置整个团队中的 Webhook 。"
@@ -2393,12 +2893,6 @@ msgstr "即将删除与源项目 %{forked_from_project} 的派生关系。确定
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "即将 %{project_name_with_namespace} 转移给另一个所有者。确定继续吗?"
-msgid "You are on a read-only GitLab instance."
-msgstr "您在一个只读 GitLab 实例上。"
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr "您在一个只读的 GitLab 实例上。如果您想进行任何更改,您必须访问%{link_to_primary_node}。"
-
msgid "You can only add files when you are on a branch"
msgstr "只能在分支上添加文件"
@@ -2438,6 +2932,9 @@ msgstr "在账号中 %{set_password_link} 之前将无法通过 %{protocol} 拉
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "在账号中 %{add_ssh_key_link} 之前将无法通过 SSH 拉取或推送代码。"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr "在您的个人资料中添加SSH密钥之前,您不能通过SSH来拉取或推送项目代码。"
+
msgid "Your comment will not be visible to the public."
msgstr "您的评论将不会公开显示。"
@@ -2450,6 +2947,12 @@ msgstr "您的名字"
msgid "Your projects"
msgstr "您的项目"
+msgid "branch name"
+msgstr "分支名称"
+
+msgid "by"
+msgstr "来自"
+
msgid "commit"
msgstr "提交"
@@ -2473,6 +2976,9 @@ msgstr "密码"
msgid "personal access token"
msgstr "个人访问令牌"
+msgid "source"
+msgstr "源"
+
msgid "to help your contributors communicate effectively!"
msgstr "帮助您的贡献者进行有效沟通!"
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index b851809fc7c..b368487ac71 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-15 02:54-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:42-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Chinese Traditional, Hong Kong\n"
"Language: zh_HK\n"
@@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}:已訪問此主機失敗 %{failed_attempts} 次"
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(想了解更多的安裝訊息請查看 %{link})"
@@ -109,9 +112,6 @@ msgstr ""
msgid "Add License"
msgstr "添加許可證"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "新增壹個用於推送或拉取的 SSH 秘鑰到賬號中。"
-
msgid "Add new directory"
msgstr "添加新目錄"
@@ -124,6 +124,15 @@ msgstr ""
msgid "All"
msgstr "全部"
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr ""
@@ -133,6 +142,12 @@ msgstr ""
msgid "Applications"
msgstr ""
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "歸檔項目!存儲庫為只讀"
@@ -160,6 +175,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "拖放文件到此處或者 %{upload_link}"
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr ""
@@ -193,6 +214,9 @@ msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr ""
+msgid "Available"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -257,6 +281,12 @@ msgstr "分支 %{branch_name} 已創建。如需設置自動部
msgid "Branch has changed"
msgstr ""
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "搜索分支"
@@ -404,6 +434,12 @@ msgstr "統計圖"
msgid "Chat"
msgstr ""
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "優選此提交"
@@ -479,7 +515,40 @@ msgstr ""
msgid "Cluster"
msgstr ""
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
msgstr ""
msgid "ClusterIntegration|Cluster details"
@@ -503,21 +572,54 @@ msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr ""
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr ""
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr ""
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr ""
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr ""
@@ -527,27 +629,75 @@ msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
+
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr ""
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr ""
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr ""
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -560,7 +710,13 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
@@ -575,15 +731,33 @@ msgstr ""
msgid "ClusterIntegration|See zones"
msgstr ""
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
msgstr ""
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
+
msgid "ClusterIntegration|Toggle Cluster"
msgstr ""
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -599,9 +773,15 @@ msgstr ""
msgid "ClusterIntegration|cluster"
msgstr ""
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr ""
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -615,10 +795,6 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "提交"
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] ""
-
msgid "Commit Message"
msgstr ""
@@ -700,6 +876,15 @@ msgstr "貢獻指南"
msgid "Contributors"
msgstr "貢獻者"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
msgstr ""
@@ -727,6 +912,9 @@ msgstr "創建目錄"
msgid "Create empty bare repository"
msgstr "創建空的存儲庫"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr ""
@@ -754,6 +942,9 @@ msgstr "標籤"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "創建個人訪問令牌"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Cron 時區"
@@ -799,6 +990,12 @@ msgstr ""
msgid "DashboardProjects|Personal"
msgstr ""
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "使用 Cron 語法定義自定義模式"
@@ -872,6 +1069,72 @@ msgstr "編輯 %{id} 流水線計劃"
msgid "Emails"
msgstr ""
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "全部"
@@ -911,6 +1174,12 @@ msgstr "無法變更所有者"
msgid "Failed to remove the pipeline schedule"
msgstr "無法刪除流水線計劃"
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr ""
@@ -957,6 +1226,21 @@ msgstr ""
msgid "Geo Nodes"
msgstr ""
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
+
msgid "Geo|File sync capacity"
msgstr ""
@@ -1020,9 +1304,6 @@ msgstr ""
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
-msgid "GroupsTreeRole|as"
-msgstr ""
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr ""
@@ -1053,6 +1334,9 @@ msgstr ""
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr ""
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr "健康檢查 (Health Check)"
@@ -1111,9 +1395,6 @@ msgstr "週期分析簡介"
msgid "Issue board focus mode"
msgstr ""
-msgid "Issue boards with milestones"
-msgstr ""
-
msgid "Issue events"
msgstr "議題事件 (issue event)"
@@ -1126,6 +1407,24 @@ msgstr ""
msgid "Issues"
msgstr ""
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "停用"
@@ -1197,9 +1496,18 @@ msgstr ""
msgid "Login"
msgstr ""
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr ""
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "中位數"
@@ -1243,9 +1551,15 @@ msgstr "創建流水線計劃"
msgid "New branch"
msgstr "新增分支"
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "新增目錄"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "新增文件"
@@ -1282,6 +1596,9 @@ msgstr "沒有存儲庫"
msgid "No schedules"
msgstr "沒有計劃"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr ""
@@ -1348,18 +1665,33 @@ msgstr "關注"
msgid "Notifications"
msgstr ""
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr ""
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "篩選"
msgid "Only project members can comment."
msgstr ""
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "開始於"
@@ -1492,6 +1824,9 @@ msgstr "於階段"
msgid "Pipeline|with stages"
msgstr "於階段"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -1597,9 +1932,15 @@ msgstr "分支圖"
msgid "ProjectSettings|Contact an admin to change this setting."
msgstr ""
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
+
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
+
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
msgstr ""
@@ -1636,6 +1977,39 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -1732,6 +2106,9 @@ msgstr ""
msgid "Scheduling Pipelines"
msgstr "流水線計劃"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "搜索分支和標籤"
@@ -1753,6 +2130,12 @@ msgstr "選擇時區"
msgid "Select target branch"
msgstr "選擇目標分支"
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr ""
@@ -1784,13 +2167,28 @@ msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "顯示 %d 個事件"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
msgstr ""
msgid "Something went wrong while fetching the projects."
@@ -1898,9 +2296,15 @@ msgstr ""
msgid "SortOptions|Weight"
msgstr ""
+msgid "Source"
+msgstr ""
+
msgid "Source code"
msgstr "源代碼"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr ""
@@ -1919,6 +2323,9 @@ msgstr "由此更改 %{new_merge_request}"
msgid "Start the Runner!"
msgstr "運作 Runner!"
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr ""
@@ -1938,6 +2345,75 @@ msgstr[0] "標籤"
msgid "Tags"
msgstr "標籤"
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "目標分支"
@@ -2019,6 +2495,9 @@ msgstr "中位數是壹個數列中最中間的值。例如在 3、5、9 之間
msgid "There are problems accessing Git storage: "
msgstr "訪問 Git 存儲時出現問題:"
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
@@ -2040,6 +2519,9 @@ msgstr "在創建壹個空的存儲庫或導入現有存儲庫之前,您將無
msgid "This merge request is locked."
msgstr ""
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "議題被列入日程表的時間"
@@ -2186,15 +2668,27 @@ msgstr[0] "分鐘"
msgid "Time|s"
msgstr "秒"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "總時間"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "所有提交和合併的總測試時間"
msgid "Track activity with Contribution Analytics."
msgstr ""
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
+
msgid "Unlock"
msgstr ""
@@ -2231,6 +2725,9 @@ msgstr "上傳文件"
msgid "UploadLink|click to upload"
msgstr "點擊上傳"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr "在安裝過程中使用以下註冊令牌:"
@@ -2264,6 +2761,9 @@ msgstr "權限不足。如需查看相關數據,請向管理員申請權限。
msgid "We don't have enough data to show this stage."
msgstr "該階段的數據不足,無法顯示。"
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
@@ -2393,12 +2893,6 @@ msgstr "即將刪除與源項目 %{forked_from_project} 的派生關系。確定
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "即將 %{project_name_with_namespace} 轉義給另壹個所有者。確定繼續嗎?"
-msgid "You are on a read-only GitLab instance."
-msgstr ""
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr ""
-
msgid "You can only add files when you are on a branch"
msgstr "只能在分支上添加文件"
@@ -2438,6 +2932,9 @@ msgstr "在賬號上 %{set_password_link} 之前將無法通過 %{protocol} 拉
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "在賬號中 %{add_ssh_key_link} 之前將無法通過 SSH 拉取或推送代碼。"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr ""
@@ -2450,6 +2947,12 @@ msgstr "您的名字"
msgid "Your projects"
msgstr ""
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
msgstr ""
@@ -2473,6 +2976,9 @@ msgstr ""
msgid "personal access token"
msgstr ""
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index b6d4ed27487..76c1e598433 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-11-02 14:42+0100\n"
-"PO-Revision-Date: 2017-11-20 03:59-0500\n"
+"POT-Creation-Date: 2017-12-12 18:31+0000\n"
+"PO-Revision-Date: 2018-01-05 04:42-0500\n"
"Last-Translator: gitlab \n"
"Language-Team: Chinese Traditional\n"
"Language: zh_TW\n"
@@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:"
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
msgstr[0] "%{storage_name}:已存取此主機失敗 %{failed_attempts} 次"
+msgid "%{text} is available"
+msgstr ""
+
msgid "(checkout the %{link} for information on how to install it)."
msgstr "(如何安裝請參閱 %{link})"
@@ -95,7 +98,7 @@ msgid "Activity"
msgstr "活動"
msgid "Add"
-msgstr "增加"
+msgstr ""
msgid "Add Changelog"
msgstr "新增更新日誌"
@@ -104,14 +107,11 @@ msgid "Add Contribution guide"
msgstr "新增協作指南"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
-msgstr "加入來自 Webhooks 或者是 GitLab 企業版的群組"
+msgstr ""
msgid "Add License"
msgstr "新增授權條款"
-msgid "Add an SSH key to your profile to pull or push via SSH."
-msgstr "將 SSH 金鑰新增至您的個人帳號後, 即可透過 SSH 來上傳 (push) 或下載 (pull) 。"
-
msgid "Add new directory"
msgstr "新增目錄"
@@ -124,6 +124,15 @@ msgstr "進階設定"
msgid "All"
msgstr "全部"
+msgid "An error occurred when toggling the notification subscription"
+msgstr ""
+
+msgid "An error occurred when updating the issue weight"
+msgstr ""
+
+msgid "An error occurred while fetching sidebar data"
+msgstr ""
+
msgid "An error occurred. Please try again."
msgstr "發生錯誤,請再試一次。"
@@ -133,6 +142,12 @@ msgstr "外觀"
msgid "Applications"
msgstr "應用程式"
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
msgid "Archived project! Repository is read-only"
msgstr "此專案已封存!檔案庫 (repository) 為唯讀狀態"
@@ -160,6 +175,12 @@ msgstr ""
msgid "Attach a file by drag & drop or %{upload_link}"
msgstr "拖放檔案到此處或者 %{upload_link}"
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
msgid "Authentication Log"
msgstr "登入紀錄"
@@ -193,59 +214,62 @@ msgstr "了解更多於 %{link_to_documentation}"
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgstr "你可以為此專案啟動 %{link_to_settings}"
+msgid "Available"
+msgstr ""
+
msgid "Billing"
-msgstr "方案"
+msgstr ""
msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan."
-msgstr "%{group_name} 目前使用 %{plan_link} 方案。"
+msgstr ""
msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available."
-msgstr "目前無法自動升級或降級至其他方案。"
+msgstr ""
msgid "BillingPlans|Current plan"
-msgstr "目前方案"
+msgstr ""
msgid "BillingPlans|Customer Support"
-msgstr "客戶服務"
+msgstr ""
msgid "BillingPlans|Downgrade"
-msgstr "降級"
+msgstr ""
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}."
-msgstr "了解更多我們的方案,或是閱讀 %{faq_link}"
+msgstr ""
msgid "BillingPlans|Manage plan"
-msgstr "管理方案"
+msgstr ""
msgid "BillingPlans|Please contact %{customer_support_link} in that case."
-msgstr "請聯繫 %{customer_support_link}"
+msgstr ""
msgid "BillingPlans|See all %{plan_name} features"
-msgstr "查看更多 %{plan_name} 功能"
+msgstr ""
msgid "BillingPlans|This group uses the plan associated with its parent group."
-msgstr "此群組與上層群組使用相同的方案。"
+msgstr ""
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
-msgstr "請至 %{parent_billing_page_link} 來管理此群組的方案。"
+msgstr ""
msgid "BillingPlans|Upgrade"
-msgstr "升級"
+msgstr ""
msgid "BillingPlans|You are currently on the %{plan_link} plan."
-msgstr "目前使用 %{plan_link} 方案。"
+msgstr ""
msgid "BillingPlans|frequently asked questions"
-msgstr "常見問題"
+msgstr ""
msgid "BillingPlans|monthly"
-msgstr "每個月"
+msgstr ""
msgid "BillingPlans|paid annually at %{price_per_year}"
-msgstr "每年收取 %{price_per_year}"
+msgstr ""
msgid "BillingPlans|per user"
-msgstr "每位使用者"
+msgstr ""
msgid "Branch"
msgid_plural "Branches"
@@ -257,6 +281,12 @@ msgstr "已建立分支 (branch) %{branch_name} 。如需設定
msgid "Branch has changed"
msgstr "分支(branch)已變更"
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "搜尋分支 (branches)"
@@ -318,7 +348,7 @@ msgid "Branches|Sort by"
msgstr "排序自"
msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart."
-msgstr "分支無法自動送交,因為與上游分支衝突。"
+msgstr ""
msgid "Branches|The default branch cannot be deleted"
msgstr "無法刪除預設分支"
@@ -339,7 +369,7 @@ msgid "Branches|You’re about to permanently delete the protected branch %{bran
msgstr "你將永久刪除受保護的 %{branch_name} 分支。"
msgid "Branches|diverged from upstream"
-msgstr "與上游分歧"
+msgstr ""
msgid "Branches|merged"
msgstr "已合併"
@@ -381,7 +411,7 @@ msgid "Cancel edit"
msgstr "取消編輯"
msgid "Change Weight"
-msgstr "變更權重"
+msgstr ""
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "挑選到分支 (branch) "
@@ -404,6 +434,12 @@ msgstr "統計圖"
msgid "Chat"
msgstr "即時通訊"
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
msgid "Cherry-pick this commit"
msgstr "挑選此更動記錄 (commit) "
@@ -411,7 +447,7 @@ msgid "Cherry-pick this merge request"
msgstr "挑選此合併請求 (merge request) "
msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all."
-msgstr "選擇你想要複製到第二節點的群組。若留白則會複製全部的群組。"
+msgstr ""
msgid "CiStatusLabel|canceled"
msgstr "已取消"
@@ -474,13 +510,46 @@ msgid "Clone repository"
msgstr "複製(clone)檔案庫(repository)"
msgid "Close"
-msgstr "關閉"
+msgstr ""
msgid "Cluster"
msgstr "叢集"
-msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
-msgstr "必須在此帳號下建立 %{link_to_container_project}"
+msgid "ClusterIntegration|%{appList} was successfully installed on your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}"
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Active"
+msgstr ""
+
+msgid "ClusterIntegration|Add an existing cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Add cluster"
+msgstr ""
+
+msgid "ClusterIntegration|All"
+msgstr ""
+
+msgid "ClusterIntegration|Applications"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Choose how to set up cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster"
+msgstr ""
msgid "ClusterIntegration|Cluster details"
msgstr "叢集詳情"
@@ -498,56 +567,137 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab
msgstr "此專案已啟用叢集整合。禁止叢集整合不會影響您的叢集,它只是暫時關閉 GitLab 的連接。"
msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..."
-msgstr "在 Google 容器引擎中建立新的叢集"
+msgstr ""
msgid "ClusterIntegration|Cluster name"
msgstr "叢集名稱"
-msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine"
-msgstr "在 Google 容器引擎上成功建立叢集"
+msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details"
+msgstr ""
+
+msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Token"
+msgstr ""
msgid "ClusterIntegration|Copy cluster name"
msgstr "複製叢集名稱"
+msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab"
+msgstr ""
+
msgid "ClusterIntegration|Create cluster"
msgstr "建立叢集"
-msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine"
-msgstr "在 Google 容器引擎中建立新的叢集"
+msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Create on GKE"
+msgstr ""
msgid "ClusterIntegration|Enable cluster integration"
msgstr "啟動叢集整合"
+msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Enter the details for your cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Environment pattern"
+msgstr ""
+
+msgid "ClusterIntegration|GKE pricing"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Runner"
+msgstr ""
+
msgid "ClusterIntegration|Google Cloud Platform project ID"
msgstr "Google 雲端專案 ID"
msgid "ClusterIntegration|Google Kubernetes Engine"
-msgstr "Google 容器引擎"
+msgstr ""
msgid "ClusterIntegration|Google Kubernetes Engine project"
-msgstr "Google 容器引擎專案"
+msgstr ""
+
+msgid "ClusterIntegration|Helm Tiller"
+msgstr ""
+
+msgid "ClusterIntegration|Inactive"
+msgstr ""
+
+msgid "ClusterIntegration|Ingress"
+msgstr ""
+
+msgid "ClusterIntegration|Install"
+msgstr ""
+
+msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}"
+msgstr ""
+
+msgid "ClusterIntegration|Installed"
+msgstr ""
+
+msgid "ClusterIntegration|Installing"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate cluster automation"
+msgstr ""
msgid "ClusterIntegration|Learn more about %{link_to_documentation}"
msgstr "學習更多有關於%{link_to_documentation}"
+msgid "ClusterIntegration|Learn more about Clusters"
+msgstr ""
+
msgid "ClusterIntegration|Machine type"
msgstr "機器型別"
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters"
msgstr "請確認您的帳戶中%{link_to_requirements} 是否建立叢集"
-msgid "ClusterIntegration|Manage Cluster integration on your GitLab project"
-msgstr "在你的 GitLab 專案上管理叢集整合"
+msgid "ClusterIntegration|Manage cluster integration on your GitLab project"
+msgstr ""
msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}"
msgstr "請至 %{link_gke} 管理你的叢集"
+msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate"
+msgstr ""
+
+msgid "ClusterIntegration|Note:"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "所有的端點數量"
+msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters"
+msgstr ""
+
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr "請確認你的 Google 帳號是否符合這些條件"
+msgid "ClusterIntegration|Problem setting up the cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Problem setting up the clusters list"
+msgstr ""
+
+msgid "ClusterIntegration|Project ID"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace"
+msgstr ""
+
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr "專案命名空間(選填,不可重複)"
@@ -560,8 +710,14 @@ msgstr "刪除叢集整合"
msgid "ClusterIntegration|Remove integration"
msgstr "刪除整合"
-msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
-msgstr "當刪除叢集需要加入專案的定義組態檔,會刪除叢集整合。這並不會刪除你的專案。 刪除叢集的同時,將一起刪除已加入此專案的定義組態檔,但你的專案不會因此被刪除。"
+msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine."
+msgstr ""
+
+msgid "ClusterIntegration|Request to begin installing failed"
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
+msgstr ""
msgid "ClusterIntegration|See and edit the details for your cluster"
msgstr "查看與編輯你的叢集內容"
@@ -575,33 +731,57 @@ msgstr "查看您的專案"
msgid "ClusterIntegration|See zones"
msgstr "查看區域"
+msgid "ClusterIntegration|Service token"
+msgstr ""
+
+msgid "ClusterIntegration|Show"
+msgstr ""
+
msgid "ClusterIntegration|Something went wrong on our end."
msgstr "內部發生了錯誤"
msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine"
-msgstr "在 Google Kubernetes Engine 上建立叢集時發生了錯誤"
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while installing %{title}"
+msgstr ""
+
+msgid "ClusterIntegration|There are no clusters to show"
+msgstr ""
+
+msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
+msgstr ""
msgid "ClusterIntegration|Toggle Cluster"
msgstr "叢集開關"
+msgid "ClusterIntegration|Token"
+msgstr ""
+
msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "當叢集連結到此專案,你可以使用複閱應用 (review apps),部署你的應用程式,執行你的流水線 (pipelines),還有更多容易上手的方式可以使用。"
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
-msgstr "您的帳號必須有 %{link_to_kubernetes_engine}"
+msgstr ""
msgid "ClusterIntegration|Zone"
msgstr "區域"
msgid "ClusterIntegration|access to Google Kubernetes Engine"
-msgstr "存取 Google Kubernetes Engine"
+msgstr ""
msgid "ClusterIntegration|cluster"
msgstr "叢集"
+msgid "ClusterIntegration|documentation"
+msgstr ""
+
msgid "ClusterIntegration|help page"
msgstr "說明頁面"
+msgid "ClusterIntegration|installing applications"
+msgstr ""
+
msgid "ClusterIntegration|meets the requirements"
msgstr "符合需求"
@@ -615,10 +795,6 @@ msgid "Commit"
msgid_plural "Commits"
msgstr[0] "更動記錄 (commit) "
-msgid "Commit %d file"
-msgid_plural "Commit %d files"
-msgstr[0] "提交 %d 個檔案"
-
msgid "Commit Message"
msgstr "更動訊息"
@@ -700,14 +876,23 @@ msgstr "協作指南"
msgid "Contributors"
msgstr "協作者"
+msgid "ContributorsPage|Building repository graph."
+msgstr ""
+
+msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node"
-msgstr "控制次節點 (secondary node) 同步 LFS 和附檔的最大並行率 (concurrency)"
+msgstr ""
msgid "Control the maximum concurrency of repository backfill for this secondary node"
-msgstr "控制次節點 (secondary node) 同步檔案庫 (repository) 的最大並行率 (concurrency)"
+msgstr ""
msgid "Copy SSH public key to clipboard"
-msgstr "複製 SSH 金鑰到剪貼簿"
+msgstr ""
msgid "Copy URL to clipboard"
msgstr "複製網址到剪貼簿"
@@ -727,6 +912,9 @@ msgstr "建立目錄"
msgid "Create empty bare repository"
msgstr "建立一個新的 bare repository"
+msgid "Create epic"
+msgstr ""
+
msgid "Create file"
msgstr "新增檔案"
@@ -754,6 +942,9 @@ msgstr "建立標籤"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr "建立個人存取憑證 (access token)"
+msgid "Creating epic"
+msgstr ""
+
msgid "Cron Timezone"
msgstr "Cron 時區"
@@ -799,6 +990,12 @@ msgstr "全部"
msgid "DashboardProjects|Personal"
msgstr "個人"
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
msgid "Define a custom pattern with cron syntax"
msgstr "使用 Cron 語法自訂排程"
@@ -816,7 +1013,7 @@ msgid "Description"
msgstr "描述"
msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "描述範本 (Description templates) 讓你在建立專案的議題 (Issue) 和合併請求時可以選擇特定的範本。"
+msgstr ""
msgid "Details"
msgstr "細節"
@@ -872,6 +1069,72 @@ msgstr "編輯 %{id} 流水線 (pipeline) 排程"
msgid "Emails"
msgstr "電子郵件"
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production."
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Re-deploy"
+msgstr ""
+
+msgid "Environments|Read more about environments"
+msgstr ""
+
+msgid "Environments|Rollback"
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|You don't have any environments right now."
+msgstr ""
+
+msgid "Epic will be removed! Are you sure?"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error occurred when toggling the notification subscription"
+msgstr ""
+
msgid "EventFilterBy|Filter by all"
msgstr "顯示全部"
@@ -911,6 +1174,12 @@ msgstr "無法變更所有權"
msgid "Failed to remove the pipeline schedule"
msgstr "無法刪除流水線 (pipeline) 排程"
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
msgid "File name"
msgstr "檔案名稱"
@@ -955,19 +1224,34 @@ msgid "GPG Keys"
msgstr "GPG 金鑰"
msgid "Geo Nodes"
-msgstr "Geo 節點"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Failed"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is failing or broken."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Out of sync"
+msgstr ""
+
+msgid "GeoNodeSyncStatus|Synced"
+msgstr ""
msgid "Geo|File sync capacity"
-msgstr "檔案同步容量"
+msgstr ""
msgid "Geo|Groups to replicate"
-msgstr "要複製的群組"
+msgstr ""
msgid "Geo|Repository sync capacity"
-msgstr "檔案庫(repository)同步量"
+msgstr ""
msgid "Geo|Select groups to replicate."
-msgstr "選擇欲複製之群組。"
+msgstr ""
msgid "Git storage health information has been reset"
msgstr "Git 儲存空間健康指數已重置"
@@ -1020,9 +1304,6 @@ msgstr "找不到群組"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr "你可以管理群組內所有成員的每個專案的存取權限"
-msgid "GroupsTreeRole|as"
-msgstr "的"
-
msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?"
msgstr "你確定要離開群組 \"${this.group.fullName}\" 嗎?"
@@ -1053,6 +1334,9 @@ msgstr "不好意思,沒有搜尋到任何符合條件的群組"
msgid "GroupsTree|Sorry, no groups or projects matched your search"
msgstr "不好意思,沒有搜尋到任何符合條件的群組或專案"
+msgid "Have your users email"
+msgstr ""
+
msgid "Health Check"
msgstr "健康檢查"
@@ -1081,20 +1365,20 @@ msgid "Import repository"
msgstr "匯入檔案庫 (repository)"
msgid "Improve Issue boards with GitLab Enterprise Edition."
-msgstr "協助改進 GitLab 企業版的議題看板(issue boards)"
+msgstr ""
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
-msgstr "協助改進 GitLab 企業版的議題管理與權重。"
+msgstr ""
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
-msgstr "協助改進 GitLab 企業版的搜尋 & 進階全局搜尋。"
+msgstr ""
msgid "Install a Runner compatible with GitLab CI"
msgstr "安裝與 GitLab CI 相容的 Runner"
msgid "Instance"
msgid_plural "Instances"
-msgstr[0] "主機"
+msgstr[0] ""
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
msgstr "內部 - 任何登入的使用者都可以查看該群組及其專案"
@@ -1109,10 +1393,7 @@ msgid "Introducing Cycle Analytics"
msgstr "週期分析簡介"
msgid "Issue board focus mode"
-msgstr "議題看板(issue boards)模式"
-
-msgid "Issue boards with milestones"
-msgstr "議題看板(issue boards)與里程碑"
+msgstr ""
msgid "Issue events"
msgstr "議題 (issue) 事件"
@@ -1121,11 +1402,29 @@ msgid "IssueBoards|Board"
msgstr "看板"
msgid "IssueBoards|Boards"
-msgstr "看板"
+msgstr ""
msgid "Issues"
msgstr "議題"
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
msgid "LFSStatus|Disabled"
msgstr "停用"
@@ -1179,7 +1478,7 @@ msgid "Leave project"
msgstr "退出專案"
msgid "License"
-msgstr "授權"
+msgstr ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
@@ -1192,14 +1491,23 @@ msgid "Locked"
msgstr "鎖定"
msgid "Locked Files"
-msgstr "被鎖定的檔案"
+msgstr ""
msgid "Login"
msgstr "登入"
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
msgid "Maximum git storage failures"
msgstr "最大 git 儲存失敗"
+msgid "May"
+msgstr ""
+
msgid "Median"
msgstr "中位數"
@@ -1228,7 +1536,7 @@ msgid "More information is available|here"
msgstr "健康檢查"
msgid "Multiple issue boards"
-msgstr "多個議題看板 (issue boards)"
+msgstr ""
msgid "New Cluster"
msgstr "新叢集"
@@ -1243,9 +1551,15 @@ msgstr "建立流水線 (pipeline) 排程"
msgid "New branch"
msgstr "新分支 (branch) "
+msgid "New branch unavailable"
+msgstr ""
+
msgid "New directory"
msgstr "新增目錄"
+msgid "New epic"
+msgstr ""
+
msgid "New file"
msgstr "新增檔案"
@@ -1282,6 +1596,9 @@ msgstr "找不到檔案庫 (repository)"
msgid "No schedules"
msgstr "沒有排程"
+msgid "No time spent"
+msgstr ""
+
msgid "None"
msgstr "無"
@@ -1348,18 +1665,33 @@ msgstr "關注"
msgid "Notifications"
msgstr "通知"
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
msgid "Number of access attempts"
msgstr "嘗試存取的次數"
msgid "Number of failures before backing off"
msgstr ""
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
msgid "OfSearchInADropdown|Filter"
msgstr "篩選"
msgid "Only project members can comment."
msgstr "只有群組成員才能留言。"
+msgid "Opened"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr "開始於"
@@ -1406,7 +1738,7 @@ msgid "Pipeline Schedules"
msgstr "流水線 (pipeline) 排程"
msgid "Pipeline quota"
-msgstr "流水線額度"
+msgstr ""
msgid "PipelineCharts|Failed:"
msgstr "失敗:"
@@ -1492,6 +1824,9 @@ msgstr "於階段"
msgid "Pipeline|with stages"
msgstr "於階段"
+msgid "Please solve the reCAPTCHA"
+msgstr ""
+
msgid "Preferences"
msgstr "偏好設定"
@@ -1595,22 +1930,28 @@ msgid "ProjectNetworkGraph|Graph"
msgstr "分支圖"
msgid "ProjectSettings|Contact an admin to change this setting."
-msgstr "聯絡管理員以變更設定。"
+msgstr ""
+
+msgid "ProjectSettings|Immediately run a pipeline on the default branch"
+msgstr ""
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
-msgstr "只有已簽章的變更才能被推送到檔案庫(repository)。"
+msgstr ""
+
+msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript"
+msgstr ""
msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
-msgstr "此設定已經套用於伺服器層級,並且可被管理員覆寫。"
+msgstr ""
msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
-msgstr "此設定已經套用至伺服器層級,但此專案使用另一個設定。"
+msgstr ""
msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
-msgstr "此設定將套用至所有專案,除非被管理員覆寫。"
+msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
-msgstr "使用者推送的修改 (commits) 只能使用他們自己的電子郵件。"
+msgstr ""
msgid "Projects"
msgstr "專案"
@@ -1636,6 +1977,39 @@ msgstr "抱歉,沒有符合搜尋條件的專案"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "此功能需要瀏覽器支援 localStorage"
+msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitored"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment."
+msgstr ""
+
+msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|Prometheus monitoring"
+msgstr ""
+
+msgid "PrometheusService|View environments"
+msgstr ""
+
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr "公開 - 未登入的情況下依然可以查看任何公開專案"
@@ -1643,13 +2017,13 @@ msgid "Public - The project can be accessed without any authentication."
msgstr "公開 - 無須任何身份驗證即可存取該專案"
msgid "Push Rules"
-msgstr "推送 [Push] 規則"
+msgstr ""
msgid "Push events"
msgstr "推送 (push) 事件"
msgid "PushRule|Committer restriction"
-msgstr "提交限制"
+msgstr ""
msgid "Read more"
msgstr "瞭解更多"
@@ -1664,7 +2038,7 @@ msgid "RefSwitcher|Tags"
msgstr "標籤"
msgid "Registry"
-msgstr "登錄表"
+msgstr ""
msgid "Related Commits"
msgstr "相關的更動記錄 (commit) "
@@ -1732,6 +2106,9 @@ msgstr "排程"
msgid "Scheduling Pipelines"
msgstr "流水線 (pipeline) 排程"
+msgid "Scoped issue boards"
+msgstr ""
+
msgid "Search branches and tags"
msgstr "搜尋分支 (branch) 和標籤"
@@ -1753,6 +2130,12 @@ msgstr "選擇時區"
msgid "Select target branch"
msgstr "選擇目標分支 (branch) "
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
msgid "Service Templates"
msgstr "服務範本"
@@ -1784,14 +2167,29 @@ msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "顯示 %d 個事件"
+msgid "Sidebar|Change weight"
+msgstr ""
+
+msgid "Sidebar|Edit"
+msgstr ""
+
+msgid "Sidebar|No"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidebar|Weight"
+msgstr ""
+
msgid "Snippets"
msgstr "文字片段"
msgid "Something went wrong on our end."
msgstr "發生了錯誤。"
-msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}"
-msgstr "有個地方出錯了,因為他嘗試去變更 ${this.issuableDisplayName(this.issuableType)} 的鎖定狀態。"
+msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}"
+msgstr ""
msgid "Something went wrong while fetching the projects."
msgstr "讀取專案時發生錯誤。"
@@ -1842,7 +2240,7 @@ msgid "SortOptions|Least popular"
msgstr "最不受歡迎"
msgid "SortOptions|Less weight"
-msgstr "最低權重"
+msgstr ""
msgid "SortOptions|Milestone"
msgstr "里程碑"
@@ -1854,7 +2252,7 @@ msgid "SortOptions|Milestone due soon"
msgstr "即將截止的里程碑"
msgid "SortOptions|More weight"
-msgstr "更大的權重"
+msgstr ""
msgid "SortOptions|Most popular"
msgstr "最受歡迎"
@@ -1896,11 +2294,17 @@ msgid "SortOptions|Start soon"
msgstr "現在開始"
msgid "SortOptions|Weight"
-msgstr "權重"
+msgstr ""
+
+msgid "Source"
+msgstr ""
msgid "Source code"
msgstr "原始碼"
+msgid "Source is not available"
+msgstr ""
+
msgid "Spam Logs"
msgstr "垃圾訊息記錄"
@@ -1919,6 +2323,9 @@ msgstr "以這些改動建立一個新的 %{new_merge_request} "
msgid "Start the Runner!"
msgstr "啟動 Runner!"
+msgid "Stopped"
+msgstr ""
+
msgid "Subgroups"
msgstr "子群組"
@@ -1938,6 +2345,75 @@ msgstr[0] "標籤"
msgid "Tags"
msgstr "標籤"
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "TagsPage|Edit release notes"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag."
+msgstr ""
+
+msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
+msgstr ""
+
+msgid "TagsPage|Release notes"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sort by"
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|This tag has no release notes."
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Write your release notes or drag files here..."
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
msgid "Target Branch"
msgstr "目標分支 (branch) "
@@ -1945,10 +2421,10 @@ msgid "Team"
msgstr "團隊"
msgid "Thanks! Don't show me this again"
-msgstr "感謝!請不要再次顯示"
+msgstr ""
msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
-msgstr "GitLab 的進階全局搜尋功能是非常強大的搜尋服務。您可以搜尋其他團隊的代碼以幫助您完善自己項目中的代碼。從而避免建立重複的代碼浪費時間。"
+msgstr ""
msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold"
msgstr "限流阻斷元件的觸發門檻應低於計數錯誤門檻"
@@ -2019,6 +2495,9 @@ msgstr "中位數是一個數列中最中間的值。例如在 3、5、9 之間
msgid "There are problems accessing Git storage: "
msgstr "存取 Git 儲存空間時出現問題:"
+msgid "This board\\'s scope is reduced"
+msgstr ""
+
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr "在您編輯後,此分支已被更改,您想要建立一個新的分支嗎?"
@@ -2040,6 +2519,9 @@ msgstr "這代表在您建立一個空的檔案庫 (repository) 或是匯入一
msgid "This merge request is locked."
msgstr "這個合併請求已被鎖定。"
+msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr "議題 (issue) 被列入日程表的時間"
@@ -2186,14 +2668,26 @@ msgstr[0] "分鐘"
msgid "Time|s"
msgstr "秒"
+msgid "Title"
+msgstr ""
+
msgid "Total Time"
msgstr "總時間"
+msgid "Total issue time spent"
+msgstr ""
+
msgid "Total test time for all commits/merges"
msgstr "合併 (merge) 與更動記錄 (commit) 的總測試時間"
msgid "Track activity with Contribution Analytics."
-msgstr "追蹤分析貢獻與活動。"
+msgstr ""
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Turn on Service Desk"
+msgstr ""
msgid "Unlock"
msgstr "解鎖"
@@ -2208,19 +2702,19 @@ msgid "Unsubscribe"
msgstr "取消訂閱"
msgid "Upgrade your plan to activate Advanced Global Search."
-msgstr "升級您的方案以啟用進階全局搜尋。"
+msgstr ""
msgid "Upgrade your plan to activate Contribution Analytics."
-msgstr "升級您的方案以啟用貢獻分析。"
+msgstr ""
msgid "Upgrade your plan to activate Group Webhooks."
-msgstr "升級您的方案以啟用群組 Webhooks。"
+msgstr ""
msgid "Upgrade your plan to activate Issue weight."
-msgstr "升級您的方案以啟用問題權重。"
+msgstr ""
msgid "Upgrade your plan to improve Issue boards."
-msgstr "升級您的方案以使用議題看板(issue boards)"
+msgstr ""
msgid "Upload New File"
msgstr "上傳新檔案"
@@ -2231,6 +2725,9 @@ msgstr "上傳檔案"
msgid "UploadLink|click to upload"
msgstr "點擊上傳"
+msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
+msgstr ""
+
msgid "Use the following registration token during setup:"
msgstr "在安裝過程中使用此註冊憑證 (registration token):"
@@ -2264,11 +2761,14 @@ msgstr "權限不足。如需查看相關資料,請向管理員申請權限。
msgid "We don't have enough data to show this stage."
msgstr "因該階段的資料不足而無法顯示相關資訊"
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr ""
msgid "Weight"
-msgstr "權重"
+msgstr ""
msgid "When access to a storage fails. GitLab will prevent access to the storage for the time specified here. This allows the filesystem to recover. Repositories on failing shards are temporarly unavailable"
msgstr "當存取檔案庫 (repository) 失敗時, GitLab 將在此處指定的時間內防止檔案庫的存取,以此等待檔案系統恢復。失敗的檔案庫分流 (shard) 會暫時無法使用。"
@@ -2376,7 +2876,7 @@ msgid "Wiki|Wiki Pages"
msgstr "維基頁面"
msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members."
-msgstr "透過貢獻分析,您可以分析您的組織及其成員的問題、合併請求和推送活動。"
+msgstr ""
msgid "Withdraw Access Request"
msgstr "取消權限申請"
@@ -2393,17 +2893,11 @@ msgstr "將要刪除本分支專案與主幹 %{forked_from_project} 的所有關
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "將要把 %{project_name_with_namespace} 的所有權轉移給另一個人。真的「確定」要這麼做嗎?"
-msgid "You are on a read-only GitLab instance."
-msgstr "您在唯讀的 GitLab 主機上。"
-
-msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}."
-msgstr "您在唯讀的 GitLab 主機上,如果您想要進行修改,必須到 %{link_to_primary_node}"
-
msgid "You can only add files when you are on a branch"
msgstr "只能在分支 (branch) 上建立檔案"
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
-msgstr "您不能寫入唯讀的次要 GitLab Geo 主機。請改用 %{link_to_primary_node}。"
+msgstr ""
msgid "You cannot write to this read-only GitLab instance."
msgstr "您不能修改這個唯讀的 GitLab 主機。"
@@ -2438,6 +2932,9 @@ msgstr "在帳號上 %{set_password_link} 之前, 將無法使用 %{protocol}
msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
msgstr "在個人帳號中 %{add_ssh_key_link} 之前, 將無法使用 SSH 上傳 (push) 或下載 (pull) 程式碼。"
+msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
+msgstr ""
+
msgid "Your comment will not be visible to the public."
msgstr "你的留言將不會被公開。"
@@ -2450,8 +2947,14 @@ msgstr "您的名字"
msgid "Your projects"
msgstr "你的計劃"
+msgid "branch name"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
msgid "commit"
-msgstr "更動"
+msgstr ""
msgid "day"
msgid_plural "days"
@@ -2473,8 +2976,11 @@ msgstr "密碼"
msgid "personal access token"
msgstr "私人存取憑證 (access token)"
+msgid "source"
+msgstr ""
+
msgid "to help your contributors communicate effectively!"
-msgstr "幫助你的貢獻者進行有效的溝通!"
+msgstr ""
msgid "username"
msgstr "使用者名稱"
--
cgit v1.2.1
From da6af70a22ad34f76923fc8b0c5a1309e0ec541e Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Fri, 5 Jan 2018 16:18:01 +0000
Subject: Changes after review
---
app/assets/javascripts/jobs/components/header.vue | 6 ++---
.../vue_shared/components/header_ci_component.vue | 4 ++--
app/views/projects/jobs/_empty_state.html.haml | 17 ++++++++++++++
app/views/projects/jobs/show.html.haml | 27 ++++++++++------------
.../components/header_ci_component_spec.js | 6 ++---
5 files changed, 37 insertions(+), 23 deletions(-)
create mode 100644 app/views/projects/jobs/_empty_state.html.haml
diff --git a/app/assets/javascripts/jobs/components/header.vue b/app/assets/javascripts/jobs/components/header.vue
index 0de823831d9..c660828b30e 100644
--- a/app/assets/javascripts/jobs/components/header.vue
+++ b/app/assets/javascripts/jobs/components/header.vue
@@ -30,7 +30,7 @@
shouldRenderContent() {
return !this.isLoading && Object.keys(this.job).length;
},
- wasTriggered() {
+ jobStarted() {
return this.job.started;
},
},
@@ -67,8 +67,8 @@
:user="job.user"
:actions="actions"
:has-sidebar-button="true"
- :triggered="wasTriggered"
- />
+ :should-render-triggered-label="jobStarted"
+ />
-
+
triggered
diff --git a/app/views/projects/jobs/_empty_state.html.haml b/app/views/projects/jobs/_empty_state.html.haml
new file mode 100644
index 00000000000..8f44628a5c3
--- /dev/null
+++ b/app/views/projects/jobs/_empty_state.html.haml
@@ -0,0 +1,17 @@
+- illustration = locals.fetch(:illustration)
+- illustration_size = locals.fetch(:illustration_size)
+- title = locals.fetch(:title)
+- content = locals.fetch(:content)
+- action = locals.fetch(:action)
+
+.row.empty-state
+ .col-xs-12
+ .svg-content{ class: illustration_size }
+ = image_tag illustration
+ .col-xs-12
+ .text-content
+ %h4.text-center= title
+ %p= content
+ - if action?
+ .text-center
+ = action
diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml
index d029af2f5e9..60fd1d32b14 100644
--- a/app/views/projects/jobs/show.html.haml
+++ b/app/views/projects/jobs/show.html.haml
@@ -88,22 +88,19 @@
%pre.build-trace#build-trace
%code.bash.js-build-output
.build-loader-animation.js-build-refresh
+ - elsif @build.playable?
+ = render 'empty_state',
+ illustration: 'illustrations/manual_action.svg',
+ illustration_size: 'svg-394',
+ title: _('This job requires a manual action'),
+ content: _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments.'),
+ action: ( link_to _('Trigger this manual action'), play_project_job_path(@project, @build), class: 'btn btn-primary', title: _('Trigger this manual action') )
- else
- - illustration = @build.playable? ? 'illustrations/manual_action.svg' : 'illustrations/job_not_triggered.svg'
- - illustration_size = @build.playable? ? 'svg-394' : 'svg-306'
- - title = @build.playable? ? _('This job requires a manual action') : _('This job has not been triggered yet')
- - content = @build.playable? ? _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments.') : _('This job depends on upstream jobs that need to succeed in order for this job to be triggered.')
- .row.empty-state
- .col-xs-12
- .svg-content{ class: illustration_size }
- = image_tag illustration
- .col-xs-12
- .text-content
- %h4.text-center= title
- %p= content
- - if @build.playable?
- .text-center
- = link_to _('Trigger this manual action'), play_project_job_path(@project, @build), class: 'btn btn-primary', title: _('Trigger this manual action')
+ = render 'empty_state',
+ illustration: 'illustrations/job_not_triggered.svg',
+ illustration_size: 'svg-306',
+ title: _('This job has not been triggered yet'),
+ content: _('This job has not been triggered yet')
= render "sidebar"
diff --git a/spec/javascripts/vue_shared/components/header_ci_component_spec.js b/spec/javascripts/vue_shared/components/header_ci_component_spec.js
index 66c6f70a667..b378a0bd896 100644
--- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js
+++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js
@@ -98,9 +98,9 @@ describe('Header CI Component', () => {
});
});
- describe('triggered', () => {
- it('should rendered created keyword when the triggered is false', () => {
- vm = mountComponent(HeaderCi, { ...props, triggered: false });
+ describe('shouldRenderTriggeredLabel', () => {
+ it('should rendered created keyword when the shouldRenderTriggeredLabel is false', () => {
+ vm = mountComponent(HeaderCi, { ...props, shouldRenderTriggeredLabel: false });
expect(vm.$el.textContent).toContain('created');
expect(vm.$el.textContent).not.toContain('triggered');
--
cgit v1.2.1
From 91477f6dae624bcce85c0b734a73f2db07398f2a Mon Sep 17 00:00:00 2001
From: Tim Zallmann
Date: Fri, 5 Jan 2018 17:35:34 +0000
Subject: Resolve "Helpful and instructing Empty state for multi file editor"
---
app/assets/images/icons.json | 2 +-
app/assets/images/icons.svg | 2 +-
.../illustrations/multi_file_editor_empty.svg | 1 +
.../images/illustrations/wiki_login_empty.svg | 1 +
.../images/illustrations/wiki_logout_empty.svg | 1 +
app/assets/javascripts/ide/components/ide.vue | 24 +++++++++++++++-
.../javascripts/ide/components/ide_repo_tree.vue | 29 ++++++++++++--------
.../javascripts/ide/components/ide_side_bar.vue | 13 +++++++++
app/assets/javascripts/ide/index.js | 32 +++-------------------
.../javascripts/ide/stores/actions/project.js | 2 ++
app/assets/stylesheets/pages/repo.scss | 13 +++++++++
app/views/ide/index.html.haml | 4 +--
app/views/layouts/nav/_dashboard.html.haml | 6 ++++
package.json | 2 +-
.../repo/components/ide_repo_tree_spec.js | 6 ++--
spec/javascripts/repo/components/ide_spec.js | 4 ++-
yarn.lock | 6 ++--
17 files changed, 95 insertions(+), 53 deletions(-)
create mode 100644 app/assets/images/illustrations/multi_file_editor_empty.svg
create mode 100644 app/assets/images/illustrations/wiki_login_empty.svg
create mode 100644 app/assets/images/illustrations/wiki_logout_empty.svg
diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json
index 38c1faccbf1..296cb856734 100644
--- a/app/assets/images/icons.json
+++ b/app/assets/images/icons.json
@@ -1 +1 @@
-{"iconCount":186,"spriteSize":84748,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
\ No newline at end of file
+{"iconCount":189,"spriteSize":85766,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o-open","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]}
\ No newline at end of file
diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg
index 42f5377a10e..8d5426da19c 100644
--- a/app/assets/images/icons.svg
+++ b/app/assets/images/icons.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/assets/images/illustrations/multi_file_editor_empty.svg b/app/assets/images/illustrations/multi_file_editor_empty.svg
new file mode 100644
index 00000000000..bd376f0a050
--- /dev/null
+++ b/app/assets/images/illustrations/multi_file_editor_empty.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/images/illustrations/wiki_login_empty.svg b/app/assets/images/illustrations/wiki_login_empty.svg
new file mode 100644
index 00000000000..1cfa47220a5
--- /dev/null
+++ b/app/assets/images/illustrations/wiki_login_empty.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/images/illustrations/wiki_logout_empty.svg b/app/assets/images/illustrations/wiki_logout_empty.svg
new file mode 100644
index 00000000000..c71841f72e5
--- /dev/null
+++ b/app/assets/images/illustrations/wiki_logout_empty.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue
index 7f29a355eca..26a70f6e748 100644
--- a/app/assets/javascripts/ide/components/ide.vue
+++ b/app/assets/javascripts/ide/components/ide.vue
@@ -9,6 +9,12 @@ import repoPreview from './repo_preview.vue';
import repoEditor from './repo_editor.vue';
export default {
+ props: {
+ emptyStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ },
computed: {
...mapState([
'currentBlobView',
@@ -64,7 +70,23 @@ export default {
-
Welcome to the GitLab IDE
+
+
+
+
+
+
+
+
+
+ Welcome to the GitLab IDE
+
+
+ You can select a file in the left sidebar to begin editing and use the right sidebar to commit your changes.
+