')
+ end
+ end
+
it_behaves_like 'group child json'
end
end
--
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 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 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 4963f39141208b91be52f7ae6dbdc2d885b4db3c Mon Sep 17 00:00:00 2001
From: George Tsiolis
Date: Wed, 3 Jan 2018 21:04:42 +0200
Subject: Fix dashboard projects nav links height
---
app/views/dashboard/projects/_nav.html.haml | 2 +-
changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml
diff --git a/app/views/dashboard/projects/_nav.html.haml b/app/views/dashboard/projects/_nav.html.haml
index 3701e1c0578..c18077bc66f 100644
--- a/app/views/dashboard/projects/_nav.html.haml
+++ b/app/views/dashboard/projects/_nav.html.haml
@@ -1,4 +1,4 @@
-.top-area
+.nav-block
%ul.nav-links
= nav_link(html_options: { class: ("active" unless params[:personal].present?) }) do
= link_to s_('DashboardProjects|All'), dashboard_projects_path
diff --git a/changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml b/changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml
new file mode 100644
index 00000000000..2f6a07bb234
--- /dev/null
+++ b/changelogs/unreleased/fix-dashboard-projects-nav-links-height.yml
@@ -0,0 +1,5 @@
+---
+title: Fix dashboard projects nav links height
+merge_request: 16204
+author: George Tsiolis
+type: fixed
--
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: '
@@ -121,12 +124,13 @@
updated comment
- to ensure information is not lost.
+ rel="noopener noreferrer">
+ updated comment
+
+ to ensure information is not lost.
- {{ __('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.') }}
+ {{ __('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.') }}
- {{__("No container images stored for this project. Add one by following the instructions above.")}}
+ {{ __("No container images stored for this project. Add one by following the instructions above.") }}
+
diff --git a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
index 80927529ffe..839f9ec88b9 100644
--- a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
@@ -1,51 +1,51 @@
@@ -54,8 +54,8 @@ change the confidentiality of this issue`);
-
+ aria-hidden="true"
+ />
Confidentiality
@@ -75,22 +75,26 @@ change the confidentiality of this issue`);
:is-confidential="isConfidential"
:update-confidential-attribute="updateConfidentialAttribute"
/>
-
+
-
+ class="sidebar-item-icon inline"
+ />
Not confidential
-
+
-
+ class="sidebar-item-icon inline is-active"
+ />
This issue is confidential
-
+
+ tabindex="-1"
+ >
Markdown is supported
-
-
+
+ tabindex="-1"
+ >
Markdown
and
-
+ tabindex="-1"
+ >
quick actions
are supported
@@ -53,46 +62,58 @@
+ aria-hidden="true"
+ >
+
0%
+ aria-hidden="true"
+ >
+
+ aria-hidden="true"
+ >
+
or
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
index e3e41f8f0ca..2d2d69ebeb2 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
@@ -3,6 +3,12 @@
import icon from '../icon.vue';
export default {
+ components: {
+ icon,
+ },
+ directives: {
+ tooltip,
+ },
props: {
buttonTitle: {
type: String,
@@ -27,12 +33,6 @@
default: false,
},
},
- components: {
- icon,
- },
- directives: {
- tooltip,
- },
};
@@ -47,9 +47,10 @@
:data-md-block="tagBlock"
:data-md-prepend="prepend"
:title="buttonTitle"
- :aria-label="buttonTitle">
+ :aria-label="buttonTitle"
+ >
-
+ :name="icon"
+ />
--
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**.
-![Fast forward merge request](img/ff_merge_mr.png)
+![Fast forward merge request](img/ff_merge_rebase.png)
If the target branch is ahead of the source branch, you need to rebase the
source branch locally before you will be able to do a fast-forward merge.
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"
/>
{{ __('Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.') }}
@@ -46,8 +50,9 @@
:href="documentationLink"
target="_blank"
rel="nofollow"
- class="btn">
- {{__('Read more')}}
+ class="btn"
+ >
+ {{ __('Read more') }}
--
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 7c7f52668420007d551549f34df66345f1373e36 Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Fri, 5 Jan 2018 14:31:01 +0000
Subject: [ci skip] Fix more rules
---
.../javascripts/boards/components/board_card.vue | 3 +-
.../clusters/components/applications.vue | 12 +-
.../components/stage_code_component.vue | 2 +-
.../components/stage_plan_component.vue | 2 +-
.../components/stage_review_component.vue | 5 +-
.../components/stage_staging_component.vue | 6 +-
.../components/stage_test_component.vue | 66 +-
.../components/total_time_component.vue | 28 +-
.../deploy_keys/components/action_btn.vue | 24 +-
.../javascripts/deploy_keys/components/app.vue | 46 +-
.../javascripts/deploy_keys/components/key.vue | 9 +-
.../deploy_keys/components/keys_panel.vue | 12 +-
.../environments/components/container.vue | 19 +-
.../environments/components/empty_state.vue | 13 +-
.../components/environment_actions.vue | 94 +--
.../components/environment_external_url.vue | 46 +-
.../environments/components/environment_item.vue | 890 +++++++++++----------
.../issue_show/components/description.vue | 14 +-
.../javascripts/issue_show/components/edited.vue | 52 +-
.../issue_show/components/fields/description.vue | 6 +-
.../javascripts/issue_show/components/form.vue | 26 +-
.../javascripts/issue_show/components/title.vue | 28 +-
app/assets/javascripts/jobs/components/header.vue | 24 +-
.../jobs/components/sidebar_detail_row.vue | 7 +-
.../jobs/components/sidebar_details_block.vue | 60 +-
.../monitoring/components/dashboard.vue | 62 +-
.../monitoring/components/empty_state.vue | 18 +-
.../javascripts/monitoring/components/graph.vue | 148 ++--
.../monitoring/components/graph/deployment.vue | 74 +-
.../monitoring/components/graph/flag.vue | 23 +-
.../monitoring/components/graph/legend.vue | 77 +-
.../monitoring/components/graph/path.vue | 9 +-
.../monitoring/components/graph_group.vue | 16 +-
.../javascripts/notes/components/note_actions.vue | 34 +-
34 files changed, 1035 insertions(+), 920 deletions(-)
diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue
index 7e0e0a13a46..23fec503586 100644
--- a/app/assets/javascripts/boards/components/board_card.vue
+++ b/app/assets/javascripts/boards/components/board_card.vue
@@ -89,6 +89,7 @@ export default {
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
- :update-filters="true" />
+ :update-filters="true"
+ />
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index 38fcc006831..25cef44c1b8 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -77,12 +77,12 @@ which incur additional costs. See %{pricingLink}`)),
return sprintf(
_.escape(s__(`ClusterIntegration|Prometheus is an open-source monitoring system
with %{gitlabIntegrationLink} to monitor deployed applications.`)),
- {
- gitlabIntegrationLink: `
- ${_.escape(s__('ClusterIntegration|Gitlab Integration'))}
- `,
- },
+ {
+ gitlabIntegrationLink: `
+ ${_.escape(s__('ClusterIntegration|Gitlab Integration'))}
+ `,
+ },
false,
);
},
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
index e06f803b30b..a71dcf78103 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
@@ -12,7 +12,7 @@
props: {
items: {
type: Array,
- default: []
+ default: () => [],
},
stage: {
type: Object,
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
index 4f2c8256277..cee294b4ac2 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
@@ -13,7 +13,7 @@
props: {
items: {
type: Array,
- default: []
+ default: () => [],
},
stage: {
type: Object,
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
index c419347d219..39b699a6395 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
@@ -14,7 +14,7 @@
props: {
items: {
type: Array,
- default: []
+ default: () => [],
},
stage: {
type: Object,
@@ -81,8 +81,7 @@
name="fork"
:size="16"
/>
-
+
{{ mergeRequest.branch.name }}
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
index 26ee5a8c69d..92f2a95a66a 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
@@ -15,7 +15,7 @@
props: {
items: {
type: Array,
- default: []
+ default: () => [],
},
stage: {
type: Object,
@@ -69,7 +69,7 @@
+ >
{{ build.shortSha }}
@@ -77,7 +77,7 @@
+ >
{{ build.date }}
{{ s__('ByAuthor|by') }}
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
index 88fa6b073ca..c0f6c9ae573 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
@@ -6,15 +6,21 @@
import icon from '../../vue_shared/components/icon.vue';
export default {
- props: {
- items: Array,
- stage: Object,
- },
components: {
totalTime,
limitWarning,
icon,
},
+ props: {
+ items: {
+ type: Array,
+ default: () => [],
+ },
+ stage: {
+ type: Object,
+ default: () => ({}),
+ },
+ },
computed: {
iconBuildStatus() {
return iconBuildStatus;
@@ -35,29 +41,59 @@
--
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 `![${el.dataset.title}](${el.getAttribute('src')})`;
},
},
+ 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 088de7237ac20739bec189ac701510cdfa01386f Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Fri, 5 Jan 2018 15:45:05 +0000
Subject: [ci skip] Fix more eslint rules
---
.../javascripts/ide/components/repo_preview.vue | 118 +++--
app/assets/javascripts/ide/components/repo_tab.vue | 71 ++-
.../javascripts/issue_show/components/app.vue | 564 ++++++++++-----------
.../issue_show/components/fields/description.vue | 2 +-
.../javascripts/issue_show/components/title.vue | 2 +-
app/assets/javascripts/jobs/components/header.vue | 2 +-
.../javascripts/monitoring/components/graph.vue | 1 -
7 files changed, 380 insertions(+), 380 deletions(-)
diff --git a/app/assets/javascripts/ide/components/repo_preview.vue b/app/assets/javascripts/ide/components/repo_preview.vue
index 3d1e0297bd5..e47270a9855 100644
--- a/app/assets/javascripts/ide/components/repo_preview.vue
+++ b/app/assets/javascripts/ide/components/repo_preview.vue
@@ -1,65 +1,71 @@
-
-
-
-
-
- The source could not be displayed for this temporary file.
-
-
-
-
- The source could not be displayed because it is too large. You can download it instead.
-
-
-
-
- The source could not be displayed because a rendering error occurred. You can download it instead.
-
+
+
+
+
+
+ The source could not be displayed for this temporary file.
+
+
+
+
+ The source could not be displayed because it is too large.
+ You can download it instead.
+
+
+
+
+ The source could not be displayed because a rendering error occurred.
+ You can download it instead.
+
diff --git a/app/assets/javascripts/issue_show/components/fields/description.vue b/app/assets/javascripts/issue_show/components/fields/description.vue
index 7cfdefa0eb6..d9fa2764d65 100644
--- a/app/assets/javascripts/issue_show/components/fields/description.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description.vue
@@ -3,10 +3,10 @@
import markdownField from '../../../vue_shared/components/markdown/field.vue';
export default {
- mixins: [updateMixin],
components: {
markdownField,
},
+ mixins: [updateMixin],
props: {
formState: {
type: Object,
diff --git a/app/assets/javascripts/issue_show/components/title.vue b/app/assets/javascripts/issue_show/components/title.vue
index 982c72e0fd1..aec890a2ff6 100644
--- a/app/assets/javascripts/issue_show/components/title.vue
+++ b/app/assets/javascripts/issue_show/components/title.vue
@@ -5,10 +5,10 @@
import { spriteIcon } from '../../lib/utils/common_utils';
export default {
- mixins: [animateMixin],
directives: {
tooltip,
},
+ mixins: [animateMixin],
props: {
issuableRef: {
type: String,
diff --git a/app/assets/javascripts/jobs/components/header.vue b/app/assets/javascripts/jobs/components/header.vue
index 39696976952..fb47881d422 100644
--- a/app/assets/javascripts/jobs/components/header.vue
+++ b/app/assets/javascripts/jobs/components/header.vue
@@ -3,7 +3,7 @@
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default {
- name: 'jobHeaderSection',
+ name: 'JobHeaderSection',
components: {
ciHeader,
loadingIcon,
diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue
index 72925ec6d23..05e6e7829d6 100644
--- a/app/assets/javascripts/monitoring/components/graph.vue
+++ b/app/assets/javascripts/monitoring/components/graph.vue
@@ -26,7 +26,6 @@
mixins: [MonitoringMixin],
-
props: {
graphData: {
type: Object,
--
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.
+
@@ -100,7 +100,7 @@
Fast-forward merge is not possible.
Rebase the source branch onto
- {{mr.targetBranch}}
+ {{ mr.targetBranch }}
to allow this merge request to be merged.
@@ -110,13 +110,15 @@
type="button"
class="btn btn-sm btn-reopen btn-success"
:disabled="isMakingRequest"
- @click="rebase">
+ @click="rebase"
+ >
Rebase
+ class="bold"
+ >
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.
@@ -124,7 +126,7 @@
- {{rebasingError}}
+ {{ rebasingError }}
diff --git a/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js b/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js
index cbca14ede02..6cc67ba57ee 100644
--- a/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js
+++ b/app/assets/javascripts/monitoring/mixins/monitoring_mixins.js
@@ -29,15 +29,18 @@ const mixins = {
time.setSeconds(this.timeSeries[0].values[0].time.getSeconds());
if (xPos >= 0) {
+ const seriesIndex = bisectDate(this.timeSeries[0].values, time, 1);
+
deploymentDataArray.push({
id: deployment.id,
time,
sha: deployment.sha,
commitUrl: `${this.projectPath}/commit/${deployment.sha}`,
tag: deployment.tag,
- tagUrl: `${this.tagsPath}/${deployment.tag}`,
+ tagUrl: deployment.tag ? `${this.tagsPath}/${deployment.ref.name}` : null,
ref: deployment.ref.name,
xPos,
+ seriesIndex,
showDeploymentFlag: false,
});
}
diff --git a/app/assets/javascripts/monitoring/utils/date_time_formatters.js b/app/assets/javascripts/monitoring/utils/date_time_formatters.js
index 068813ddee6..f3c9acdd93e 100644
--- a/app/assets/javascripts/monitoring/utils/date_time_formatters.js
+++ b/app/assets/javascripts/monitoring/utils/date_time_formatters.js
@@ -14,7 +14,7 @@ const d3 = {
timeYear,
};
-export const dateFormat = d3.time('%b %-d, %Y');
+export const dateFormat = d3.time('%a, %b %-d');
export const timeFormat = d3.time('%-I:%M%p');
export const dateFormatWithName = d3.time('%a, %b %-d');
export const bisectDate = d3.bisector(d => d.time).left;
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index f4882305c57..794bc668562 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -248,6 +248,73 @@
}
}
+.prometheus-graph-cursor {
+ position: absolute;
+ background: $theme-gray-600;
+ width: 1px;
+}
+
+.prometheus-graph-flag {
+ display: block;
+ min-width: 160px;
+
+ h5 {
+ padding: 0;
+ margin: 0;
+ font-size: 14px;
+ line-height: 1.2;
+ }
+
+ table {
+ border-collapse: collapse;
+ padding: 0;
+ margin: 0;
+ }
+
+ td {
+ vertical-align: middle;
+
+ + td {
+ padding-left: 5px;
+ vertical-align: top;
+ }
+ }
+
+ .deploy-meta-content {
+ border-bottom: 1px solid $white-dark;
+
+ svg {
+ height: 15px;
+ vertical-align: bottom;
+ }
+ }
+
+ &.popover {
+ &.left {
+ left: auto;
+ right: 0;
+ margin-right: 10px;
+ }
+
+ &.right {
+ left: 0;
+ right: auto;
+ margin-left: 10px;
+ }
+
+ > .arrow {
+ top: 40px;
+ }
+
+ > .popover-title,
+ > .popover-content {
+ padding: 5px 8px;
+ font-size: 12px;
+ white-space: nowrap;
+ }
+ }
+}
+
.prometheus-svg-container {
position: relative;
height: 0;
diff --git a/changelogs/unreleased/38030-add-graph-value-to-hover.yml b/changelogs/unreleased/38030-add-graph-value-to-hover.yml
new file mode 100644
index 00000000000..233db2b19c9
--- /dev/null
+++ b/changelogs/unreleased/38030-add-graph-value-to-hover.yml
@@ -0,0 +1,5 @@
+---
+title: Display graph values on hover within monitoring page
+merge_request: 16261
+author:
+type: changed
diff --git a/spec/javascripts/monitoring/graph/deployment_spec.js b/spec/javascripts/monitoring/graph/deployment_spec.js
index bf6ada8185e..d07db871d69 100644
--- a/spec/javascripts/monitoring/graph/deployment_spec.js
+++ b/spec/javascripts/monitoring/graph/deployment_spec.js
@@ -11,168 +11,38 @@ const createComponent = (propsData) => {
};
describe('MonitoringDeployment', () => {
- const reducedDeploymentData = [deploymentData[0]];
- reducedDeploymentData[0].ref = reducedDeploymentData[0].ref.name;
- reducedDeploymentData[0].xPos = 10;
- reducedDeploymentData[0].time = new Date(reducedDeploymentData[0].created_at);
describe('Methods', () => {
- it('refText shows the ref when a tag is available', () => {
- reducedDeploymentData[0].tag = '1.0';
- const component = createComponent({
- showDeployInfo: false,
- deploymentData: reducedDeploymentData,
- graphWidth: 440,
- graphHeight: 300,
- graphHeightOffset: 120,
- });
-
- expect(
- component.refText(reducedDeploymentData[0]),
- ).toEqual(reducedDeploymentData[0].ref);
- });
-
- it('refText shows the sha when no tag is available', () => {
- reducedDeploymentData[0].tag = null;
- const component = createComponent({
- showDeployInfo: false,
- deploymentData: reducedDeploymentData,
- graphHeight: 300,
- graphWidth: 440,
- graphHeightOffset: 120,
- });
-
- expect(
- component.refText(reducedDeploymentData[0]),
- ).toContain('f5bcd1');
- });
-
- it('nameDeploymentClass creates a class with the prefix deploy-info-', () => {
+ it('should contain a hidden gradient', () => {
const component = createComponent({
- showDeployInfo: false,
- deploymentData: reducedDeploymentData,
+ showDeployInfo: true,
+ deploymentData,
graphHeight: 300,
graphWidth: 440,
graphHeightOffset: 120,
});
- expect(
- component.nameDeploymentClass(reducedDeploymentData[0]),
- ).toContain('deploy-info');
+ expect(component.$el.querySelector('#shadow-gradient')).not.toBeNull();
});
it('transformDeploymentGroup translates an available deployment', () => {
const component = createComponent({
showDeployInfo: false,
- deploymentData: reducedDeploymentData,
+ deploymentData,
graphHeight: 300,
graphWidth: 440,
graphHeightOffset: 120,
});
expect(
- component.transformDeploymentGroup(reducedDeploymentData[0]),
+ component.transformDeploymentGroup({ xPos: 16 }),
).toContain('translate(11, 20)');
});
- it('hides the deployment flag', () => {
- reducedDeploymentData[0].showDeploymentFlag = false;
- const component = createComponent({
- showDeployInfo: true,
- deploymentData: reducedDeploymentData,
- graphWidth: 440,
- graphHeight: 300,
- graphHeightOffset: 120,
- });
-
- expect(component.$el.querySelector('.js-deploy-info-box')).toBeNull();
- });
-
- it('positions the flag to the left when the xPos is too far right', () => {
- reducedDeploymentData[0].showDeploymentFlag = false;
- reducedDeploymentData[0].xPos = 250;
- const component = createComponent({
- showDeployInfo: true,
- deploymentData: reducedDeploymentData,
- graphWidth: 440,
- graphHeight: 300,
- graphHeightOffset: 120,
- });
-
- expect(
- component.positionFlag(reducedDeploymentData[0]),
- ).toBeLessThan(0);
- });
-
- it('shows the deployment flag', () => {
- reducedDeploymentData[0].showDeploymentFlag = true;
- const component = createComponent({
- showDeployInfo: true,
- deploymentData: reducedDeploymentData,
- graphHeight: 300,
- graphWidth: 440,
- graphHeightOffset: 120,
- });
-
- expect(
- component.$el.querySelector('.js-deploy-info-box').style.display,
- ).not.toEqual('display: none;');
- });
-
- it('contains date, refs and the "deployed" text', () => {
- reducedDeploymentData[0].showDeploymentFlag = true;
- const component = createComponent({
- showDeployInfo: true,
- deploymentData: reducedDeploymentData,
- graphHeight: 300,
- graphWidth: 440,
- graphHeightOffset: 120,
- });
-
- expect(
- component.$el.querySelectorAll('.deploy-info-text'),
- ).toContainText('Deployed');
-
- expect(
- component.$el.querySelectorAll('.deploy-info-text'),
- ).toContainText('Wed, May 31');
-
- expect(
- component.$el.querySelectorAll('.deploy-info-text'),
- ).toContainText(component.refText(reducedDeploymentData[0]));
- });
-
- it('contains a link to the commit contents', () => {
- reducedDeploymentData[0].showDeploymentFlag = true;
- const component = createComponent({
- showDeployInfo: true,
- deploymentData: reducedDeploymentData,
- graphHeight: 300,
- graphWidth: 440,
- graphHeightOffset: 120,
- });
-
- expect(
- component.$el.querySelectorAll('.deploy-info-text-link')[0].parentElement.getAttribute('xlink:href'),
- ).not.toEqual('');
- });
-
- it('should contain a hidden gradient', () => {
- const component = createComponent({
- showDeployInfo: true,
- deploymentData: reducedDeploymentData,
- graphHeight: 300,
- graphWidth: 440,
- graphHeightOffset: 120,
- });
-
- expect(component.$el.querySelector('#shadow-gradient')).not.toBeNull();
- });
-
describe('Computed props', () => {
it('calculatedHeight', () => {
const component = createComponent({
showDeployInfo: true,
- deploymentData: reducedDeploymentData,
+ deploymentData,
graphHeight: 300,
graphWidth: 440,
graphHeightOffset: 120,
diff --git a/spec/javascripts/monitoring/graph/flag_spec.js b/spec/javascripts/monitoring/graph/flag_spec.js
index 8ee1171419d..2d474e9092f 100644
--- a/spec/javascripts/monitoring/graph/flag_spec.js
+++ b/spec/javascripts/monitoring/graph/flag_spec.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import GraphFlag from '~/monitoring/components/graph/flag.vue';
+import { deploymentData } from '../mock_data';
const createComponent = (propsData) => {
const Component = Vue.extend(GraphFlag);
@@ -9,11 +10,6 @@ const createComponent = (propsData) => {
}).$mount();
};
-function getCoordinate(component, selector, coordinate) {
- const coordinateVal = component.$el.querySelector(selector).getAttribute(coordinate);
- return parseInt(coordinateVal, 10);
-}
-
const defaultValuesComponent = {
currentXCoordinate: 200,
currentYCoordinate: 100,
@@ -25,31 +21,111 @@ const defaultValuesComponent = {
graphHeight: 300,
graphHeightOffset: 120,
showFlagContent: true,
+ realPixelRatio: 1,
+ timeSeries: [{
+ values: [{
+ time: new Date('2017-06-04T18:17:33.501Z'),
+ value: '1.49609375',
+ }],
+ }],
+ unitOfDisplay: 'ms',
+ currentDataIndex: 0,
+ legendTitle: 'Average',
+};
+
+const deploymentFlagData = {
+ ...deploymentData[0],
+ ref: deploymentData[0].ref.name,
+ xPos: 10,
+ time: new Date(deploymentData[0].created_at),
};
describe('GraphFlag', () => {
- it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => {
- const component = createComponent(defaultValuesComponent);
+ let component;
- expect(getCoordinate(component, '.selected-metric-line', 'x1'))
- .toEqual(component.currentXCoordinate);
- expect(getCoordinate(component, '.selected-metric-line', 'x2'))
- .toEqual(component.currentXCoordinate);
+ it('has a line at the currentXCoordinate', () => {
+ component = createComponent(defaultValuesComponent);
+
+ expect(component.$el.style.left)
+ .toEqual(`${70 + component.currentXCoordinate}px`);
});
- it('has a SVG with the class rect-text-metric at the currentFlagPosition', () => {
- const component = createComponent(defaultValuesComponent);
+ describe('Deployment flag', () => {
+ it('shows a deployment flag when deployment data provided', () => {
+ const deploymentFlagComponent = createComponent({
+ ...defaultValuesComponent,
+ deploymentFlagData,
+ });
+
+ expect(
+ deploymentFlagComponent.$el.querySelector('.popover-title'),
+ ).toContainText('Deployed');
+ });
+
+ it('contains the ref when a tag is available', () => {
+ const deploymentFlagComponent = createComponent({
+ ...defaultValuesComponent,
+ deploymentFlagData: {
+ ...deploymentFlagData,
+ sha: 'f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187',
+ tag: true,
+ ref: '1.0',
+ },
+ });
+
+ expect(
+ deploymentFlagComponent.$el.querySelector('.deploy-meta-content'),
+ ).toContainText('f5bcd1d9');
+
+ expect(
+ deploymentFlagComponent.$el.querySelector('.deploy-meta-content'),
+ ).toContainText('1.0');
+ });
+
+ it('does not contain the ref when a tag is unavailable', () => {
+ const deploymentFlagComponent = createComponent({
+ ...defaultValuesComponent,
+ deploymentFlagData: {
+ ...deploymentFlagData,
+ sha: 'f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187',
+ tag: false,
+ ref: '1.0',
+ },
+ });
+
+ expect(
+ deploymentFlagComponent.$el.querySelector('.deploy-meta-content'),
+ ).toContainText('f5bcd1d9');
- const svg = component.$el.querySelector('.rect-text-metric');
- expect(svg.tagName).toEqual('svg');
- expect(parseInt(svg.getAttribute('x'), 10)).toEqual(component.currentFlagPosition);
+ expect(
+ deploymentFlagComponent.$el.querySelector('.deploy-meta-content'),
+ ).not.toContainText('1.0');
+ });
});
describe('Computed props', () => {
- it('calculatedHeight', () => {
- const component = createComponent(defaultValuesComponent);
+ beforeEach(() => {
+ component = createComponent(defaultValuesComponent);
+ });
+
+ it('formatTime', () => {
+ expect(component.formatTime).toMatch(/\d:17PM/);
+ });
+
+ it('formatDate', () => {
+ expect(component.formatDate).toEqual('Sun, Jun 4');
+ });
+
+ it('cursorStyle', () => {
+ expect(component.cursorStyle).toEqual({
+ top: '20px',
+ left: '270px',
+ height: '180px',
+ });
+ });
- expect(component.calculatedHeight).toEqual(180);
+ it('flagOrientation', () => {
+ expect(component.flagOrientation).toEqual('left');
});
});
});
--
cgit v1.2.1
From 3f54abb26c48885cb022a1a86ac7dc947579869c Mon Sep 17 00:00:00 2001
From: Winnie Hellmann
Date: Mon, 8 Jan 2018 13:33:30 +0100
Subject: Make tasklist:changed test in merge_request_spec.js async
---
spec/javascripts/merge_request_spec.js | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js
index 2f02c11482f..9d6ea3781bc 100644
--- a/spec/javascripts/merge_request_spec.js
+++ b/spec/javascripts/merge_request_spec.js
@@ -19,17 +19,24 @@ import IssuablesHelper from '~/helpers/issuables_helper';
$('input[type=checkbox]').attr('checked', true)[0].dispatchEvent(changeEvent);
return expect($('.js-task-list-field').val()).toBe('- [x] Task List Item');
});
- return it('submits an ajax request on tasklist:changed', function() {
- spyOn(jQuery, 'ajax').and.callFake(function(req) {
+
+ it('submits an ajax request on tasklist:changed', (done) => {
+ spyOn(jQuery, 'ajax').and.callFake((req) => {
expect(req.type).toBe('PATCH');
expect(req.url).toBe(`${gl.TEST_HOST}/frontend-fixtures/merge-requests-project/merge_requests/1.json`);
- return expect(req.data.merge_request.description).not.toBe(null);
+ expect(req.data.merge_request.description).not.toBe(null);
+ done();
});
- return $('.js-task-list-field').trigger('tasklist:changed');
+
+ $('.js-task-list-field').trigger('tasklist:changed');
});
});
describe('class constructor', () => {
+ beforeEach(() => {
+ spyOn(jQuery, 'ajax').and.stub();
+ });
+
it('calls .initCloseReopenReport', () => {
spyOn(IssuablesHelper, 'initCloseReopenReport');
--
cgit v1.2.1
From 6762d2875e979e1e2692062b2353265f5d743fc8 Mon Sep 17 00:00:00 2001
From: Brett Walker
Date: Mon, 8 Jan 2018 12:44:32 +0000
Subject: Resolve "Allow QA tests to run with `CHROME_HEADLESS=false`"
---
qa/qa.rb | 1 +
qa/qa/runtime/browser.rb | 41 ++++++++++++++++++++++++-----
qa/qa/runtime/env.rb | 15 +++++++++++
qa/spec/runtime/env_spec.rb | 64 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 114 insertions(+), 7 deletions(-)
create mode 100644 qa/qa/runtime/env.rb
create mode 100644 qa/spec/runtime/env_spec.rb
diff --git a/qa/qa.rb b/qa/qa.rb
index 453e4e9e164..71b80a6adcb 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -10,6 +10,7 @@ module QA
autoload :Namespace, 'qa/runtime/namespace'
autoload :Scenario, 'qa/runtime/scenario'
autoload :Browser, 'qa/runtime/browser'
+ autoload :Env, 'qa/runtime/env'
end
##
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index 220bb45741b..14b2a488760 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -38,22 +38,49 @@ module QA
Capybara.register_driver :chrome do |app|
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
- 'chromeOptions' => {
- 'args' => %w[headless no-sandbox disable-gpu window-size=1280,1680]
+ # This enables access to logs with `page.driver.manage.get_log(:browser)`
+ loggingPrefs: {
+ browser: "ALL",
+ client: "ALL",
+ driver: "ALL",
+ server: "ALL"
}
)
- Capybara::Selenium::Driver
- .new(app, browser: :chrome, desired_capabilities: capabilities)
- end
+ options = Selenium::WebDriver::Chrome::Options.new
+ options.add_argument("window-size=1240,1680")
- Capybara::Screenshot.register_driver(:chrome) do |driver, path|
- driver.browser.save_screenshot(path)
+ # Chrome won't work properly in a Docker container in sandbox mode
+ options.add_argument("no-sandbox")
+
+ # Run headless by default unless CHROME_HEADLESS is false
+ if QA::Runtime::Env.chrome_headless?
+ options.add_argument("headless")
+
+ # Chrome documentation says this flag is needed for now
+ # https://developers.google.com/web/updates/2017/04/headless-chrome#cli
+ options.add_argument("disable-gpu")
+ end
+
+ # Disable /dev/shm use in CI. See https://gitlab.com/gitlab-org/gitlab-ee/issues/4252
+ options.add_argument("disable-dev-shm-usage") if QA::Runtime::Env.running_in_ci?
+
+ Capybara::Selenium::Driver.new(
+ app,
+ browser: :chrome,
+ desired_capabilities: capabilities,
+ options: options
+ )
end
# Keep only the screenshots generated from the last failing test suite
Capybara::Screenshot.prune_strategy = :keep_last_run
+ # From https://github.com/mattheworiordan/capybara-screenshot/issues/84#issuecomment-41219326
+ Capybara::Screenshot.register_driver(:chrome) do |driver, path|
+ driver.browser.save_screenshot(path)
+ end
+
Capybara.configure do |config|
config.default_driver = :chrome
config.javascript_driver = :chrome
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
new file mode 100644
index 00000000000..d5c28e9a7db
--- /dev/null
+++ b/qa/qa/runtime/env.rb
@@ -0,0 +1,15 @@
+module QA
+ module Runtime
+ module Env
+ extend self
+
+ def chrome_headless?
+ (ENV['CHROME_HEADLESS'] =~ /^(false|no|0)$/i) != 0
+ end
+
+ def running_in_ci?
+ ENV['CI'] || ENV['CI_SERVER']
+ end
+ end
+ end
+end
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
new file mode 100644
index 00000000000..57a72a04507
--- /dev/null
+++ b/qa/spec/runtime/env_spec.rb
@@ -0,0 +1,64 @@
+describe QA::Runtime::Env do
+ before do
+ allow(ENV).to receive(:[]).and_call_original
+ end
+
+ describe '.chrome_headless?' do
+ context 'when there is an env variable set' do
+ it 'returns false when falsey values specified' do
+ stub_env('CHROME_HEADLESS', 'false')
+ expect(described_class.chrome_headless?).to be_falsey
+
+ stub_env('CHROME_HEADLESS', 'no')
+ expect(described_class.chrome_headless?).to be_falsey
+
+ stub_env('CHROME_HEADLESS', '0')
+ expect(described_class.chrome_headless?).to be_falsey
+ end
+
+ it 'returns true when anything else specified' do
+ stub_env('CHROME_HEADLESS', 'true')
+ expect(described_class.chrome_headless?).to be_truthy
+
+ stub_env('CHROME_HEADLESS', '1')
+ expect(described_class.chrome_headless?).to be_truthy
+
+ stub_env('CHROME_HEADLESS', 'anything')
+ expect(described_class.chrome_headless?).to be_truthy
+ end
+ end
+
+ context 'when there is no env variable set' do
+ it 'returns the default, true' do
+ stub_env('CHROME_HEADLESS', nil)
+ expect(described_class.chrome_headless?).to be_truthy
+ end
+ end
+ end
+
+ describe '.running_in_ci?' do
+ context 'when there is an env variable set' do
+ it 'returns true if CI' do
+ stub_env('CI', 'anything')
+ expect(described_class.running_in_ci?).to be_truthy
+ end
+
+ it 'returns true if CI_SERVER' do
+ stub_env('CI_SERVER', 'anything')
+ expect(described_class.running_in_ci?).to be_truthy
+ end
+ end
+
+ context 'when there is no env variable set' do
+ it 'returns true' do
+ stub_env('CI', nil)
+ stub_env('CI_SERVER', nil)
+ expect(described_class.running_in_ci?).to be_falsey
+ end
+ end
+ end
+
+ def stub_env(name, value)
+ allow(ENV).to receive(:[]).with(name).and_return(value)
+ end
+end
--
cgit v1.2.1
From 6732795231dd71f2d5cd8a851372db1894ba0a3f Mon Sep 17 00:00:00 2001
From: Shinya Maeda
Date: Mon, 8 Jan 2018 22:24:23 +0900
Subject: Add memoization for properties
---
...ate_kubernetes_service_to_new_clusters_architectures.rb | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/db/post_migrate/20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb b/db/post_migrate/20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb
index 3fe0a4941d5..11b581e4b57 100644
--- a/db/post_migrate/20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb
+++ b/db/post_migrate/20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb
@@ -76,19 +76,25 @@ class MigrateKubernetesServiceToNewClustersArchitectures < ActiveRecord::Migrati
end
def api_url
- JSON.parse(self.properties)['api_url']
+ parsed_properties['api_url']
end
def ca_pem
- JSON.parse(self.properties)['ca_pem']
+ parsed_properties['ca_pem']
end
def namespace
- JSON.parse(self.properties)['namespace']
+ parsed_properties['namespace']
end
def token
- JSON.parse(self.properties)['token']
+ parsed_properties['token']
+ end
+
+ private
+
+ def parsed_properties
+ @parsed_properties ||= JSON.parse(self.properties)
end
end
--
cgit v1.2.1
From a32fcf33ee56ebd7e2d07e377610cfcce53d5a88 Mon Sep 17 00:00:00 2001
From: Onuwa Nnachi Isaac
Date: Mon, 8 Jan 2018 15:18:13 +0100
Subject: chore: remove symbolic link
---
doc/doc | 1 -
1 file changed, 1 deletion(-)
delete mode 120000 doc/doc
diff --git a/doc/doc b/doc/doc
deleted file mode 120000
index e78a24e7fe6..00000000000
--- a/doc/doc
+++ /dev/null
@@ -1 +0,0 @@
-/home/isaac/apps/opensource/GitLab/gitlab-ce/doc
\ No newline at end of file
--
cgit v1.2.1
From dca85d4bad39e4c2e5a9b3fec792ccc259f81cff Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer
Date: Mon, 8 Jan 2018 15:38:24 +0100
Subject: Use workhorse 3.4.0
---
GITLAB_WORKHORSE_VERSION | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index bea438e9ade..18091983f59 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-3.3.1
+3.4.0
--
cgit v1.2.1
From b95815e5f808c5a4005c2eb5b5f7194684f79f6b Mon Sep 17 00:00:00 2001
From: Josh Unger
Date: Mon, 8 Jan 2018 16:02:40 +0000
Subject: Add Gitter room link to I want to contribute since you always have
questions
---
CONTRIBUTING.md | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2b79f0825e2..057e2d6e0dc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -104,9 +104,13 @@ the remaining issues on the GitHub issue tracker.
## I want to contribute!
-If you want to contribute to GitLab, [issues with the label `Accepting Merge Requests` and small weight][accepting-mrs-weight] is a great place to start. Issues with a lower weight (1 or 2) are deemed suitable for beginners.
-These issues will be of reasonable size and challenge, for anyone to start
-contributing to GitLab.
+If you want to contribute to GitLab [issues with the label `Accepting Merge Requests` and small weight][accepting-mrs-weight]
+is a great place to start. Issues with a lower weight (1 or 2) are deemed
+suitable for beginners. These issues will be of reasonable size and challenge,
+for anyone to start contributing to GitLab. If you have any questions or need help visit [Getting Help](https://about.gitlab.com/getting-help/#discussion) to
+learn how to communicate with GitLab. If you're looking for a Gitter or Slack channel
+please consider we favor
+[asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real time communication. Thanks for your contribution!
## Workflow labels
--
cgit v1.2.1
From d0b8f536a1865af3741fc3255325b7e211ed1d42 Mon Sep 17 00:00:00 2001
From: Yorick Peterse
Date: Tue, 2 Jan 2018 17:21:28 +0100
Subject: Remove soft removals related code
This removes all usage of soft removals except for the "pending delete"
system implemented for projects. This in turn simplifies all the query
plans of the models that used soft removals. Since we don't really use
soft removals for anything useful there's no point in keeping it around.
This _does_ mean that hard removals of issues (which only admins can do
if I'm not mistaken) can influence the "iid" values, but that code is
broken to begin with. More on this (and how to fix it) can be found in
https://gitlab.com/gitlab-org/gitlab-ce/issues/31114.
Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/37447
---
Gemfile | 3 -
Gemfile.lock | 3 -
app/models/ci/pipeline_schedule.rb | 3 +-
app/models/ci/trigger.rb | 3 +-
app/models/concerns/internal_id.rb | 1 -
app/models/issue.rb | 4 +-
app/models/merge_request.rb | 5 +-
app/models/namespace.rb | 11 +-
app/serializers/issue_entity.rb | 1 -
app/services/groups/destroy_service.rb | 3 +-
app/services/users/destroy_service.rb | 2 +-
app/workers/group_destroy_worker.rb | 2 +-
changelogs/unreleased/remove-soft-removals.yml | 5 +
.../20171207150343_remove_soft_removed_objects.rb | 210 +++++++++++++++++++++
.../20171207150344_remove_deleted_at_columns.rb | 31 +++
db/schema.rb | 8 -
doc/api/pipeline_triggers.md | 5 -
lib/api/entities.rb | 2 +-
lib/api/v3/entities.rb | 2 +-
lib/gitlab/cycle_analytics/base_query.rb | 1 -
lib/gitlab/hook_data/issue_builder.rb | 1 -
lib/gitlab/hook_data/merge_request_builder.rb | 1 -
spec/fixtures/api/schemas/entities/issue.json | 1 -
.../api/schemas/entities/merge_request_widget.json | 1 -
spec/javascripts/notes/mock_data.js | 2 -
spec/javascripts/sidebar/mock_data.js | 2 -
spec/javascripts/vue_mr_widget/mock_data.js | 1 -
spec/lib/gitlab/hook_data/issue_builder_spec.rb | 1 -
.../gitlab/hook_data/merge_request_builder_spec.rb | 1 -
spec/lib/gitlab/import_export/project.group.json | 2 -
spec/lib/gitlab/import_export/project.json | 20 --
spec/lib/gitlab/import_export/project.light.json | 1 -
.../gitlab/import_export/safe_model_attributes.yml | 4 -
spec/models/ci/pipeline_schedule_spec.rb | 1 -
spec/models/issue_spec.rb | 5 -
spec/models/merge_request_spec.rb | 5 -
spec/models/namespace_spec.rb | 11 --
spec/services/users/destroy_service_spec.rb | 2 +-
38 files changed, 262 insertions(+), 105 deletions(-)
create mode 100644 changelogs/unreleased/remove-soft-removals.yml
create mode 100644 db/post_migrate/20171207150343_remove_soft_removed_objects.rb
create mode 100644 db/post_migrate/20171207150344_remove_deleted_at_columns.rb
diff --git a/Gemfile b/Gemfile
index 38381d34b6b..da482ad3b7a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -381,9 +381,6 @@ gem 'ruby-prof', '~> 0.16.2'
# OAuth
gem 'oauth2', '~> 1.4'
-# Soft deletion
-gem 'paranoia', '~> 2.3.1'
-
# Health check
gem 'health_check', '~> 2.6.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 2a81c81b0f8..f35bccdf070 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -580,8 +580,6 @@ GEM
orm_adapter (0.5.0)
os (0.9.6)
parallel (1.12.0)
- paranoia (2.3.1)
- activerecord (>= 4.0, < 5.2)
parser (2.4.0.2)
ast (~> 2.3)
parslet (1.5.0)
@@ -1110,7 +1108,6 @@ DEPENDENCIES
omniauth-twitter (~> 1.2.0)
omniauth_crowd (~> 2.2.0)
org-ruby (~> 0.9.12)
- paranoia (~> 2.3.1)
peek (~> 1.0.1)
peek-gc (~> 0.0.2)
peek-host (~> 1.0.0)
diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb
index 10ead6b6d3b..b6abc3d7681 100644
--- a/app/models/ci/pipeline_schedule.rb
+++ b/app/models/ci/pipeline_schedule.rb
@@ -2,8 +2,9 @@ module Ci
class PipelineSchedule < ActiveRecord::Base
extend Gitlab::Ci::Model
include Importable
+ include IgnorableColumn
- acts_as_paranoid
+ ignore_column :deleted_at
belongs_to :project
belongs_to :owner, class_name: 'User'
diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb
index b5290bcaf53..aa065e33739 100644
--- a/app/models/ci/trigger.rb
+++ b/app/models/ci/trigger.rb
@@ -1,8 +1,9 @@
module Ci
class Trigger < ActiveRecord::Base
extend Gitlab::Ci::Model
+ include IgnorableColumn
- acts_as_paranoid
+ ignore_column :deleted_at
belongs_to :project
belongs_to :owner, class_name: "User"
diff --git a/app/models/concerns/internal_id.rb b/app/models/concerns/internal_id.rb
index a3d0ac8d862..01079fb8bd6 100644
--- a/app/models/concerns/internal_id.rb
+++ b/app/models/concerns/internal_id.rb
@@ -10,7 +10,6 @@ module InternalId
if iid.blank?
parent = project || group
records = parent.public_send(self.class.name.tableize) # rubocop:disable GitlabSecurity/PublicSend
- records = records.with_deleted if self.paranoid?
max_iid = records.maximum(:iid)
self.iid = max_iid.to_i + 1
diff --git a/app/models/issue.rb b/app/models/issue.rb
index ad4a3c737ff..93628b456f2 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -12,7 +12,7 @@ class Issue < ActiveRecord::Base
include ThrottledTouch
include IgnorableColumn
- ignore_column :assignee_id, :branch_name
+ ignore_column :assignee_id, :branch_name, :deleted_at
DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
@@ -78,8 +78,6 @@ class Issue < ActiveRecord::Base
end
end
- acts_as_paranoid
-
class << self
alias_method :in_parents, :in_projects
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index ef58816937c..8fdeddf1ed1 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -11,7 +11,8 @@ class MergeRequest < ActiveRecord::Base
include Gitlab::Utils::StrongMemoize
ignore_column :locked_at,
- :ref_fetched
+ :ref_fetched,
+ :deleted_at
belongs_to :target_project, class_name: "Project"
belongs_to :source_project, class_name: "Project"
@@ -150,8 +151,6 @@ class MergeRequest < ActiveRecord::Base
after_save :keep_around_commit
- acts_as_paranoid
-
def self.reference_prefix
'!'
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index bdcc9159d26..37a7417cafc 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -1,6 +1,4 @@
class Namespace < ActiveRecord::Base
- acts_as_paranoid without_default_scope: true
-
include CacheMarkdownField
include Sortable
include Gitlab::ShellAdapter
@@ -10,6 +8,9 @@ class Namespace < ActiveRecord::Base
include AfterCommitQueue
include Storage::LegacyNamespace
include Gitlab::SQL::Pattern
+ include IgnorableColumn
+
+ ignore_column :deleted_at
# Prevent users from creating unreasonably deep level of nesting.
# The number 20 was taken based on maximum nesting level of
@@ -221,12 +222,6 @@ class Namespace < ActiveRecord::Base
has_parent?
end
- def soft_delete_without_removing_associations
- # We can't use paranoia's `#destroy` since this will hard-delete projects.
- # Project uses `pending_delete` instead of the acts_as_paranoia gem.
- self.deleted_at = Time.now
- end
-
private
def refresh_access_of_projects_invited_groups
diff --git a/app/serializers/issue_entity.rb b/app/serializers/issue_entity.rb
index 0bdd4d7a272..b5e2334b6e3 100644
--- a/app/serializers/issue_entity.rb
+++ b/app/serializers/issue_entity.rb
@@ -6,7 +6,6 @@ class IssueEntity < IssuableEntity
expose :updated_by_id
expose :created_at
expose :updated_at
- expose :deleted_at
expose :milestone, using: API::Entities::Milestone
expose :labels, using: LabelEntity
expose :lock_version
diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb
index e3f9d9ee95d..58e88688dfa 100644
--- a/app/services/groups/destroy_service.rb
+++ b/app/services/groups/destroy_service.rb
@@ -1,7 +1,6 @@
module Groups
class DestroyService < Groups::BaseService
def async_execute
- group.soft_delete_without_removing_associations
job_id = GroupDestroyWorker.perform_async(group.id, current_user.id)
Rails.logger.info("User #{current_user.id} scheduled a deletion of group ID #{group.id} with job ID #{job_id}")
end
@@ -23,7 +22,7 @@ module Groups
group.chat_team&.remove_mattermost_team(current_user)
- group.really_destroy!
+ group.destroy
end
end
end
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index 00db8a2c434..b71002433d6 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -53,7 +53,7 @@ module Users
# Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
user_data = user.destroy
- namespace.really_destroy!
+ namespace.destroy
user_data
end
diff --git a/app/workers/group_destroy_worker.rb b/app/workers/group_destroy_worker.rb
index f577b310b20..509bd09dc2e 100644
--- a/app/workers/group_destroy_worker.rb
+++ b/app/workers/group_destroy_worker.rb
@@ -4,7 +4,7 @@ class GroupDestroyWorker
def perform(group_id, user_id)
begin
- group = Group.with_deleted.find(group_id)
+ group = Group.find(group_id)
rescue ActiveRecord::RecordNotFound
return
end
diff --git a/changelogs/unreleased/remove-soft-removals.yml b/changelogs/unreleased/remove-soft-removals.yml
new file mode 100644
index 00000000000..aa53d33e502
--- /dev/null
+++ b/changelogs/unreleased/remove-soft-removals.yml
@@ -0,0 +1,5 @@
+---
+title: Remove soft removals related code
+merge_request: 15789
+author:
+type: changed
diff --git a/db/post_migrate/20171207150343_remove_soft_removed_objects.rb b/db/post_migrate/20171207150343_remove_soft_removed_objects.rb
new file mode 100644
index 00000000000..542cfb42fdc
--- /dev/null
+++ b/db/post_migrate/20171207150343_remove_soft_removed_objects.rb
@@ -0,0 +1,210 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveSoftRemovedObjects < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ module SoftRemoved
+ extend ActiveSupport::Concern
+
+ included do
+ scope :soft_removed, -> { where('deleted_at IS NOT NULL') }
+ end
+ end
+
+ class User < ActiveRecord::Base
+ self.table_name = 'users'
+
+ include EachBatch
+ end
+
+ class Issue < ActiveRecord::Base
+ self.table_name = 'issues'
+
+ include EachBatch
+ include SoftRemoved
+ end
+
+ class MergeRequest < ActiveRecord::Base
+ self.table_name = 'merge_requests'
+
+ include EachBatch
+ include SoftRemoved
+ end
+
+ class Namespace < ActiveRecord::Base
+ self.table_name = 'namespaces'
+
+ include EachBatch
+ include SoftRemoved
+
+ scope :soft_removed_personal, -> { soft_removed.where(type: nil) }
+ scope :soft_removed_group, -> { soft_removed.where(type: 'Group') }
+ end
+
+ class Route < ActiveRecord::Base
+ self.table_name = 'routes'
+
+ include EachBatch
+ include SoftRemoved
+ end
+
+ class Project < ActiveRecord::Base
+ self.table_name = 'projects'
+
+ include EachBatch
+ include SoftRemoved
+ end
+
+ class CiPipelineSchedule < ActiveRecord::Base
+ self.table_name = 'ci_pipeline_schedules'
+
+ include EachBatch
+ include SoftRemoved
+ end
+
+ class CiTrigger < ActiveRecord::Base
+ self.table_name = 'ci_triggers'
+
+ include EachBatch
+ include SoftRemoved
+ end
+
+ MODELS = [Issue, MergeRequest, CiPipelineSchedule, CiTrigger].freeze
+
+ def up
+ disable_statement_timeout
+
+ remove_personal_routes
+ remove_personal_namespaces
+ remove_group_namespaces
+ remove_simple_soft_removed_rows
+ end
+
+ def down
+ # The data removed by this migration can't be restored in an automated way.
+ end
+
+ def remove_simple_soft_removed_rows
+ create_temporary_indexes
+
+ MODELS.each do |model|
+ say_with_time("Removing soft removed rows from #{model.table_name}") do
+ model.soft_removed.each_batch do |batch, index|
+ batch.delete_all
+ end
+ end
+ end
+ ensure
+ remove_temporary_indexes
+ end
+
+ def create_temporary_indexes
+ MODELS.each do |model|
+ index_name = temporary_index_name_for(model)
+
+ # Without this index the removal process can take a very long time. For
+ # example, getting the next ID of a batch for the `issues` table in
+ # staging would take between 15 and 20 seconds.
+ next if temporary_index_exists?(model)
+
+ say_with_time("Creating temporary index #{index_name}") do
+ add_concurrent_index(
+ model.table_name,
+ [:deleted_at, :id],
+ name: index_name,
+ where: 'deleted_at IS NOT NULL'
+ )
+ end
+ end
+ end
+
+ def remove_temporary_indexes
+ MODELS.each do |model|
+ index_name = temporary_index_name_for(model)
+
+ next unless temporary_index_exists?(model)
+
+ say_with_time("Removing temporary index #{index_name}") do
+ remove_concurrent_index_by_name(model.table_name, index_name)
+ end
+ end
+ end
+
+ def temporary_index_name_for(model)
+ "index_on_#{model.table_name}_tmp"
+ end
+
+ def temporary_index_exists?(model)
+ index_name = temporary_index_name_for(model)
+
+ index_exists?(model.table_name, [:deleted_at, :id], name: index_name)
+ end
+
+ def remove_personal_namespaces
+ # Some personal namespaces are left behind in case of GitLab.com. In these
+ # cases the associated data such as the projects and users has already been
+ # removed.
+ Namespace.soft_removed_personal.each_batch do |batch|
+ batch.delete_all
+ end
+ end
+
+ def remove_group_namespaces
+ # Left over groups can't be easily removed because we may also need to
+ # remove memberships, repositories, and other associated data. As a result
+ # we'll just schedule a Sidekiq job to remove these.
+ #
+ # As of January 5th, 2018 there are 36 groups that will be removed using
+ # this code.
+ Namespace.select(:id).soft_removed_group.each_batch(of: 10) do |batch, index|
+ # We need the ID of an admin user as the owners of the group may no longer
+ # exist (or might not even be set in `namespaces.owner_id`).
+ admin_id = id_for_admin_user
+
+ batch.each do |ns|
+ schedule_group_removal(index * 5.minutes, ns.id, admin_id)
+ end
+ end
+ end
+
+ def schedule_group_removal(delay, group_id, user_id)
+ if migrate_inline?
+ GroupDestroyWorker.new.perform(group_id, user_id)
+ else
+ GroupDestroyWorker.perform_in(delay, group_id, user_id)
+ end
+ end
+
+ def remove_personal_routes
+ namespaces = Namespace.select(1)
+ .soft_removed
+ .where('namespaces.type IS NULL')
+ .where('routes.source_type = ?', 'Namespace')
+ .where('routes.source_id = namespaces.id')
+
+ Route.where('EXISTS (?)', namespaces).each_batch do |batch|
+ batch.delete_all
+ end
+ end
+
+ def id_for_admin_user
+ return @id_for_admin_user if @id_for_admin_user
+
+ if (admin_id = User.where(admin: true).limit(1).pluck(:id).first)
+ @id_for_admin_user = admin_id
+ else
+ raise 'Can not remove soft removed groups as no admin user exists. ' \
+ 'Please make sure at least one user with `admin` set to TRUE exists before proceeding.'
+ end
+ end
+
+ def migrate_inline?
+ Rails.env.test? || Rails.env.development?
+ end
+end
diff --git a/db/post_migrate/20171207150344_remove_deleted_at_columns.rb b/db/post_migrate/20171207150344_remove_deleted_at_columns.rb
new file mode 100644
index 00000000000..154d7a1b926
--- /dev/null
+++ b/db/post_migrate/20171207150344_remove_deleted_at_columns.rb
@@ -0,0 +1,31 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveDeletedAtColumns < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ TABLES = %i[issues merge_requests namespaces ci_pipeline_schedules ci_triggers].freeze
+ COLUMN = :deleted_at
+
+ def up
+ TABLES.each do |table|
+ remove_column(table, COLUMN) if column_exists?(table, COLUMN)
+ end
+ end
+
+ def down
+ TABLES.each do |table|
+ unless column_exists?(table, COLUMN)
+ add_column(table, COLUMN, :datetime_with_timezone)
+ end
+
+ unless index_exists?(table, COLUMN)
+ add_concurrent_index(table, COLUMN)
+ end
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e6a2ea4c862..544a1bcc439 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -356,7 +356,6 @@ ActiveRecord::Schema.define(version: 20171230123729) do
t.integer "project_id"
t.integer "owner_id"
t.boolean "active", default: true
- t.datetime "deleted_at"
t.datetime "created_at"
t.datetime "updated_at"
end
@@ -466,7 +465,6 @@ ActiveRecord::Schema.define(version: 20171230123729) do
create_table "ci_triggers", force: :cascade do |t|
t.string "token"
- t.datetime "deleted_at"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "project_id"
@@ -860,7 +858,6 @@ ActiveRecord::Schema.define(version: 20171230123729) do
t.integer "iid"
t.integer "updated_by_id"
t.boolean "confidential", default: false, null: false
- t.datetime "deleted_at"
t.date "due_date"
t.integer "moved_to_id"
t.integer "lock_version"
@@ -877,7 +874,6 @@ ActiveRecord::Schema.define(version: 20171230123729) do
add_index "issues", ["author_id"], name: "index_issues_on_author_id", using: :btree
add_index "issues", ["confidential"], name: "index_issues_on_confidential", using: :btree
- add_index "issues", ["deleted_at"], name: "index_issues_on_deleted_at", using: :btree
add_index "issues", ["description"], name: "index_issues_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
add_index "issues", ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree
add_index "issues", ["moved_to_id"], name: "index_issues_on_moved_to_id", where: "(moved_to_id IS NOT NULL)", using: :btree
@@ -1086,7 +1082,6 @@ ActiveRecord::Schema.define(version: 20171230123729) do
t.boolean "merge_when_pipeline_succeeds", default: false, null: false
t.integer "merge_user_id"
t.string "merge_commit_sha"
- t.datetime "deleted_at"
t.string "in_progress_merge_commit_sha"
t.integer "lock_version"
t.text "title_html"
@@ -1105,7 +1100,6 @@ ActiveRecord::Schema.define(version: 20171230123729) do
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree
add_index "merge_requests", ["created_at"], name: "index_merge_requests_on_created_at", using: :btree
- add_index "merge_requests", ["deleted_at"], name: "index_merge_requests_on_deleted_at", using: :btree
add_index "merge_requests", ["description"], name: "index_merge_requests_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
add_index "merge_requests", ["head_pipeline_id"], name: "index_merge_requests_on_head_pipeline_id", using: :btree
add_index "merge_requests", ["latest_merge_request_diff_id"], name: "index_merge_requests_on_latest_merge_request_diff_id", using: :btree
@@ -1165,7 +1159,6 @@ ActiveRecord::Schema.define(version: 20171230123729) do
t.boolean "share_with_group_lock", default: false
t.integer "visibility_level", default: 20, null: false
t.boolean "request_access_enabled", default: false, null: false
- t.datetime "deleted_at"
t.text "description_html"
t.boolean "lfs_enabled"
t.integer "parent_id"
@@ -1175,7 +1168,6 @@ ActiveRecord::Schema.define(version: 20171230123729) do
end
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
- add_index "namespaces", ["deleted_at"], name: "index_namespaces_on_deleted_at", using: :btree
add_index "namespaces", ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree
add_index "namespaces", ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
diff --git a/doc/api/pipeline_triggers.md b/doc/api/pipeline_triggers.md
index 9030ae32d17..e881e61d4ef 100644
--- a/doc/api/pipeline_triggers.md
+++ b/doc/api/pipeline_triggers.md
@@ -24,7 +24,6 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/
"id": 10,
"description": "my trigger",
"created_at": "2016-01-07T09:53:58.235Z",
- "deleted_at": null,
"last_used": null,
"token": "6d056f63e50fe6f8c5f8f4aa10edb7",
"updated_at": "2016-01-07T09:53:58.235Z",
@@ -55,7 +54,6 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/
"id": 10,
"description": "my trigger",
"created_at": "2016-01-07T09:53:58.235Z",
- "deleted_at": null,
"last_used": null,
"token": "6d056f63e50fe6f8c5f8f4aa10edb7",
"updated_at": "2016-01-07T09:53:58.235Z",
@@ -85,7 +83,6 @@ curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form descri
"id": 10,
"description": "my trigger",
"created_at": "2016-01-07T09:53:58.235Z",
- "deleted_at": null,
"last_used": null,
"token": "6d056f63e50fe6f8c5f8f4aa10edb7",
"updated_at": "2016-01-07T09:53:58.235Z",
@@ -116,7 +113,6 @@ curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form descrip
"id": 10,
"description": "my trigger",
"created_at": "2016-01-07T09:53:58.235Z",
- "deleted_at": null,
"last_used": null,
"token": "6d056f63e50fe6f8c5f8f4aa10edb7",
"updated_at": "2016-01-07T09:53:58.235Z",
@@ -146,7 +142,6 @@ curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitl
"id": 10,
"description": "my trigger",
"created_at": "2016-01-07T09:53:58.235Z",
- "deleted_at": null,
"last_used": null,
"token": "6d056f63e50fe6f8c5f8f4aa10edb7",
"updated_at": "2016-01-07T09:53:58.235Z",
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index bd0c54a1b04..4b3c26d7c02 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -918,7 +918,7 @@ module API
class Trigger < Grape::Entity
expose :id
expose :token, :description
- expose :created_at, :updated_at, :deleted_at, :last_used
+ expose :created_at, :updated_at, :last_used
expose :owner, using: Entities::UserBasic
end
diff --git a/lib/api/v3/entities.rb b/lib/api/v3/entities.rb
index c17b6f45ed8..64758dae7d3 100644
--- a/lib/api/v3/entities.rb
+++ b/lib/api/v3/entities.rb
@@ -207,7 +207,7 @@ module API
end
class Trigger < Grape::Entity
- expose :token, :created_at, :updated_at, :deleted_at, :last_used
+ expose :token, :created_at, :updated_at, :last_used
expose :owner, using: ::API::Entities::UserBasic
end
diff --git a/lib/gitlab/cycle_analytics/base_query.rb b/lib/gitlab/cycle_analytics/base_query.rb
index dcbdf9a64b0..8b3bc3e440d 100644
--- a/lib/gitlab/cycle_analytics/base_query.rb
+++ b/lib/gitlab/cycle_analytics/base_query.rb
@@ -15,7 +15,6 @@ module Gitlab
query = mr_closing_issues_table.join(issue_table).on(issue_table[:id].eq(mr_closing_issues_table[:issue_id]))
.join(issue_metrics_table).on(issue_table[:id].eq(issue_metrics_table[:issue_id]))
.where(issue_table[:project_id].eq(@project.id)) # rubocop:disable Gitlab/ModuleWithInstanceVariables
- .where(issue_table[:deleted_at].eq(nil))
.where(issue_table[:created_at].gteq(@options[:from])) # rubocop:disable Gitlab/ModuleWithInstanceVariables
# Load merge_requests
diff --git a/lib/gitlab/hook_data/issue_builder.rb b/lib/gitlab/hook_data/issue_builder.rb
index e29dd0d5b0e..f9b1a3caf5e 100644
--- a/lib/gitlab/hook_data/issue_builder.rb
+++ b/lib/gitlab/hook_data/issue_builder.rb
@@ -7,7 +7,6 @@ module Gitlab
closed_at
confidential
created_at
- deleted_at
description
due_date
id
diff --git a/lib/gitlab/hook_data/merge_request_builder.rb b/lib/gitlab/hook_data/merge_request_builder.rb
index ae9b68eb648..aff786864f2 100644
--- a/lib/gitlab/hook_data/merge_request_builder.rb
+++ b/lib/gitlab/hook_data/merge_request_builder.rb
@@ -5,7 +5,6 @@ module Gitlab
assignee_id
author_id
created_at
- deleted_at
description
head_pipeline_id
id
diff --git a/spec/fixtures/api/schemas/entities/issue.json b/spec/fixtures/api/schemas/entities/issue.json
index 3d3329a3406..38467b4ca20 100644
--- a/spec/fixtures/api/schemas/entities/issue.json
+++ b/spec/fixtures/api/schemas/entities/issue.json
@@ -28,7 +28,6 @@
"confidential": { "type": "boolean" },
"discussion_locked": { "type": ["boolean", "null"] },
"updated_by_id": { "type": ["string", "null"] },
- "deleted_at": { "type": ["string", "null"] },
"time_estimate": { "type": "integer" },
"total_time_spent": { "type": "integer" },
"human_time_estimate": { "type": ["integer", "null"] },
diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index 7f662098216..05461787f06 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -13,7 +13,6 @@
"updated_by_id": { "type": ["string", "null"] },
"created_at": { "type": "string" },
"updated_at": { "type": "string" },
- "deleted_at": { "type": ["string", "null"] },
"time_estimate": { "type": "integer" },
"total_time_spent": { "type": "integer" },
"human_time_estimate": { "type": ["integer", "null"] },
diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js
index 6b608adff15..b020a1020df 100644
--- a/spec/javascripts/notes/mock_data.js
+++ b/spec/javascripts/notes/mock_data.js
@@ -29,7 +29,6 @@ export const noteableDataMock = {
can_create_note: true,
can_update: true,
},
- deleted_at: null,
description: '',
due_date: null,
human_time_estimate: null,
@@ -283,7 +282,6 @@ export const loggedOutnoteableData = {
"updated_by_id": 1,
"created_at": "2017-02-07T10:11:18.395Z",
"updated_at": "2017-08-08T10:22:51.564Z",
- "deleted_at": null,
"time_estimate": 0,
"total_time_spent": 0,
"human_time_estimate": null,
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
index 3b094d20838..7bc591d2d47 100644
--- a/spec/javascripts/sidebar/mock_data.js
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -15,7 +15,6 @@ const RESPONSE_MAP = {
updated_by_id: 1,
created_at: '2017-02-02T21: 49: 49.664Z',
updated_at: '2017-05-03T22: 26: 03.760Z',
- deleted_at: null,
time_estimate: 0,
total_time_spent: 0,
human_time_estimate: null,
@@ -153,7 +152,6 @@ const RESPONSE_MAP = {
updated_by_id: 1,
created_at: '2017-06-27T19:54:42.437Z',
updated_at: '2017-08-18T03:39:49.222Z',
- deleted_at: null,
time_estimate: 0,
total_time_spent: 0,
human_time_estimate: null,
diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js
index ca29c9fee32..ae494267659 100644
--- a/spec/javascripts/vue_mr_widget/mock_data.js
+++ b/spec/javascripts/vue_mr_widget/mock_data.js
@@ -14,7 +14,6 @@ export default {
"updated_by_id": null,
"created_at": "2017-04-07T12:27:26.718Z",
"updated_at": "2017-04-07T15:39:25.852Z",
- "deleted_at": null,
"time_estimate": 0,
"total_time_spent": 0,
"human_time_estimate": null,
diff --git a/spec/lib/gitlab/hook_data/issue_builder_spec.rb b/spec/lib/gitlab/hook_data/issue_builder_spec.rb
index aeacd577d18..506b2c0be20 100644
--- a/spec/lib/gitlab/hook_data/issue_builder_spec.rb
+++ b/spec/lib/gitlab/hook_data/issue_builder_spec.rb
@@ -14,7 +14,6 @@ describe Gitlab::HookData::IssueBuilder do
closed_at
confidential
created_at
- deleted_at
description
due_date
id
diff --git a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
index 78475403f9e..b61614e4790 100644
--- a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
+++ b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
@@ -12,7 +12,6 @@ describe Gitlab::HookData::MergeRequestBuilder do
assignee_id
author_id
created_at
- deleted_at
description
head_pipeline_id
id
diff --git a/spec/lib/gitlab/import_export/project.group.json b/spec/lib/gitlab/import_export/project.group.json
index 82a1fbd2fc5..1a561e81e4a 100644
--- a/spec/lib/gitlab/import_export/project.group.json
+++ b/spec/lib/gitlab/import_export/project.group.json
@@ -54,7 +54,6 @@
"iid": 1,
"updated_by_id": 1,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"lock_version": null,
@@ -134,7 +133,6 @@
"iid": 2,
"updated_by_id": 1,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"lock_version": null,
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 7580b62cfc0..4cf33778d15 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -56,7 +56,6 @@
"iid": 10,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"test_ee_field": "test",
@@ -350,7 +349,6 @@
"iid": 9,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"milestone": {
@@ -586,7 +584,6 @@
"iid": 8,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"label_links": [
@@ -820,7 +817,6 @@
"iid": 7,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1033,7 +1029,6 @@
"iid": 6,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1246,7 +1241,6 @@
"iid": 5,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1459,7 +1453,6 @@
"iid": 4,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1672,7 +1665,6 @@
"iid": 3,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1885,7 +1877,6 @@
"iid": 2,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -2098,7 +2089,6 @@
"iid": 1,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -2504,7 +2494,6 @@
"merge_when_pipeline_succeeds": true,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 671,
@@ -2948,7 +2937,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 679,
@@ -3228,7 +3216,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 777,
@@ -3508,7 +3495,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 785,
@@ -4198,7 +4184,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 793,
@@ -4734,7 +4719,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 801,
@@ -5223,7 +5207,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 809,
@@ -5478,7 +5461,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 817,
@@ -6168,7 +6150,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 825,
@@ -6968,7 +6949,6 @@
"id": 123,
"token": "cdbfasdf44a5958c83654733449e585",
"project_id": 5,
- "deleted_at": null,
"created_at": "2017-01-16T15:25:28.637Z",
"updated_at": "2017-01-16T15:25:28.637Z"
}
diff --git a/spec/lib/gitlab/import_export/project.light.json b/spec/lib/gitlab/import_export/project.light.json
index 02450478a77..5dbf0ed289b 100644
--- a/spec/lib/gitlab/import_export/project.light.json
+++ b/spec/lib/gitlab/import_export/project.light.json
@@ -54,7 +54,6 @@
"iid": 20,
"updated_by_id": 1,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"lock_version": null,
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index ec577903eb5..c940fade6bd 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -14,7 +14,6 @@ Issue:
- iid
- updated_by_id
- confidential
-- deleted_at
- closed_at
- due_date
- moved_to_id
@@ -159,7 +158,6 @@ MergeRequest:
- merge_when_pipeline_succeeds
- merge_user_id
- merge_commit_sha
-- deleted_at
- in_progress_merge_commit_sha
- lock_version
- milestone_id
@@ -293,7 +291,6 @@ Ci::Trigger:
- id
- token
- project_id
-- deleted_at
- created_at
- updated_at
- owner_id
@@ -309,7 +306,6 @@ Ci::PipelineSchedule:
- project_id
- owner_id
- active
-- deleted_at
- created_at
- updated_at
Clusters::Cluster:
diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb
index 9a278212efc..8ee15f0e734 100644
--- a/spec/models/ci/pipeline_schedule_spec.rb
+++ b/spec/models/ci/pipeline_schedule_spec.rb
@@ -12,7 +12,6 @@ describe Ci::PipelineSchedule do
it { is_expected.to respond_to(:cron_timezone) }
it { is_expected.to respond_to(:description) }
it { is_expected.to respond_to(:next_run_at) }
- it { is_expected.to respond_to(:deleted_at) }
describe 'validations' do
it 'does not allow invalid cron patters' do
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 5ced000cdb6..f5c9f551e65 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -18,11 +18,6 @@ describe Issue do
subject { create(:issue) }
- describe "act_as_paranoid" do
- it { is_expected.to have_db_column(:deleted_at) }
- it { is_expected.to have_db_index(:deleted_at) }
- end
-
describe 'callbacks' do
describe '#ensure_metrics' do
it 'creates metrics after saving' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 07b3e1c1758..27e9c477d61 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -24,11 +24,6 @@ describe MergeRequest do
it { is_expected.to include_module(Taskable) }
end
- describe "act_as_paranoid" do
- it { is_expected.to have_db_column(:deleted_at) }
- it { is_expected.to have_db_index(:deleted_at) }
- end
-
describe 'validation' do
it { is_expected.to validate_presence_of(:target_branch) }
it { is_expected.to validate_presence_of(:source_branch) }
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index b3f160f3119..c3673a0e2a3 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -410,17 +410,6 @@ describe Namespace do
end
end
- describe '#soft_delete_without_removing_associations' do
- let(:project1) { create(:project_empty_repo, namespace: namespace) }
-
- it 'updates the deleted_at timestamp but preserves projects' do
- namespace.soft_delete_without_removing_associations
-
- expect(Project.all).to include(project1)
- expect(namespace.deleted_at).not_to be_nil
- end
- end
-
describe '#user_ids_for_project_authorizations' do
it 'returns the user IDs for which to refresh authorizations' do
expect(namespace.user_ids_for_project_authorizations)
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index aeba9cd60bc..bb3d73edf8e 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -15,7 +15,7 @@ describe Users::DestroyService do
expect { user_data['email'].to eq(user.email) }
expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
- expect { Namespace.with_deleted.find(namespace.id) }.to raise_error(ActiveRecord::RecordNotFound)
+ expect { Namespace.find(namespace.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'will delete the project' do
--
cgit v1.2.1
From be8b9021f2578ced36295557a4476119270463fc Mon Sep 17 00:00:00 2001
From: Mattia Rizzolo
Date: Sun, 7 Jan 2018 14:58:34 +0000
Subject: Update irker documentation to mention an irker bug with key-protected
channels.
Signed-off-by: Mattia Rizzolo
---
doc/user/project/integrations/irker.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/doc/user/project/integrations/irker.md b/doc/user/project/integrations/irker.md
index c63ea1316fe..ecdd83ce8f0 100644
--- a/doc/user/project/integrations/irker.md
+++ b/doc/user/project/integrations/irker.md
@@ -47,4 +47,8 @@ Irker accepts channel names of the form `chan` and `#chan`, both for the
case, `Aorimn` is treated as a nick and no more as a channel name.
Irker can also join password-protected channels. Users need to append
-`?key=thesecretpassword` to the chan name.
+`?key=thesecretpassword` to the chan name. When using this feature remember to
+**not** put the `#` sign in front of the channel name; failing to do so will
+result on irker joining a channel literally named `#chan?key=password` henceforth
+leaking the channel key through the `/whois` IRC command (depending on IRC server
+configuration). This is due to a long standing irker bug.
--
cgit v1.2.1
From 97311688b5d1b33b1fa0b3958d88af19bc8089b8 Mon Sep 17 00:00:00 2001
From: Onuwa Nnachi Isaac
Date: Mon, 8 Jan 2018 18:11:25 +0100
Subject: Fix: remove unnecessary line
---
doc/development/architecture.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index 54029e00507..d1ba7d3dfc3 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -133,8 +133,6 @@ Usage: /etc/init.d/postgresql {start|stop|restart|reload|force-reload|status} [v
### Log locations of the services
-Note: `/home/git/` is shorthand for `/home/git`.
-
gitlabhq (includes Unicorn and Sidekiq logs)
- `/home/git/gitlab/log/` contains `application.log`, `production.log`, `sidekiq.log`, `unicorn.stdout.log`, `githost.log` and `unicorn.stderr.log` normally.
--
cgit v1.2.1
From 259d452dfdad2af2592527a94eda0ef2152d84c3 Mon Sep 17 00:00:00 2001
From: Oswaldo Ferreira
Date: Mon, 8 Jan 2018 16:53:58 -0200
Subject: Remove unnecessary queries on Merge Request Metrics population
scheduler
---
...ulate_merge_request_metrics_with_events_data.rb | 32 +---------------------
1 file changed, 1 insertion(+), 31 deletions(-)
diff --git a/db/post_migrate/20171128214150_schedule_populate_merge_request_metrics_with_events_data.rb b/db/post_migrate/20171128214150_schedule_populate_merge_request_metrics_with_events_data.rb
index 547cc68e10e..fce1829c982 100644
--- a/db/post_migrate/20171128214150_schedule_populate_merge_request_metrics_with_events_data.rb
+++ b/db/post_migrate/20171128214150_schedule_populate_merge_request_metrics_with_events_data.rb
@@ -15,8 +15,6 @@ class SchedulePopulateMergeRequestMetricsWithEventsData < ActiveRecord::Migratio
end
def up
- merge_requests = MergeRequest.where("id IN (#{updatable_merge_requests_union_sql})").reorder(:id)
-
say 'Scheduling `PopulateMergeRequestMetricsWithEventsData` jobs'
# It will update around 4_000_000 records in batches of 10_000 merge
# requests (running between 10 minutes) and should take around 66 hours to complete.
@@ -25,7 +23,7 @@ class SchedulePopulateMergeRequestMetricsWithEventsData < ActiveRecord::Migratio
#
# More information about the updates in `PopulateMergeRequestMetricsWithEventsData` class.
#
- merge_requests.each_batch(of: BATCH_SIZE) do |relation, index|
+ MergeRequest.all.each_batch(of: BATCH_SIZE) do |relation, index|
range = relation.pluck('MIN(id)', 'MAX(id)').first
BackgroundMigrationWorker.perform_in(index * 10.minutes, MIGRATION, range)
@@ -37,32 +35,4 @@ class SchedulePopulateMergeRequestMetricsWithEventsData < ActiveRecord::Migratio
execute "update merge_request_metrics set latest_closed_by_id = null"
execute "update merge_request_metrics set merged_by_id = null"
end
-
- private
-
- # On staging:
- # Planning time: 0.682 ms
- # Execution time: 22033.158 ms
- #
- def updatable_merge_requests_union_sql
- metrics_not_exists_clause =
- 'NOT EXISTS (SELECT 1 FROM merge_request_metrics WHERE merge_request_metrics.merge_request_id = merge_requests.id)'
-
- without_metrics_data = <<-SQL.strip_heredoc
- merge_request_metrics.merged_by_id IS NULL OR
- merge_request_metrics.latest_closed_by_id IS NULL OR
- merge_request_metrics.latest_closed_at IS NULL
- SQL
-
- mrs_without_metrics_record = MergeRequest
- .where(metrics_not_exists_clause)
- .select(:id)
-
- mrs_without_events_data = MergeRequest
- .joins('INNER JOIN merge_request_metrics ON merge_requests.id = merge_request_metrics.merge_request_id')
- .where(without_metrics_data)
- .select(:id)
-
- Gitlab::SQL::Union.new([mrs_without_metrics_record, mrs_without_events_data]).to_sql
- end
end
--
cgit v1.2.1
From 5abc1682153b0e45cc60a4762baf584228dd1f05 Mon Sep 17 00:00:00 2001
From: Annabel Dunstone Gray
Date: Fri, 5 Jan 2018 14:39:52 -0700
Subject: Change pipeline charts colors to match legend
---
app/assets/javascripts/pipelines/pipelines_charts.js | 12 ++++++------
app/assets/stylesheets/pages/pipelines.scss | 8 ++++++++
app/views/projects/pipelines/charts/_pipelines.haml | 4 ++--
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/app/assets/javascripts/pipelines/pipelines_charts.js b/app/assets/javascripts/pipelines/pipelines_charts.js
index 001faf4be33..821aa7e229f 100644
--- a/app/assets/javascripts/pipelines/pipelines_charts.js
+++ b/app/assets/javascripts/pipelines/pipelines_charts.js
@@ -6,16 +6,16 @@ document.addEventListener('DOMContentLoaded', () => {
const data = {
labels: chartScope.labels,
datasets: [{
- fillColor: '#7f8fa4',
- strokeColor: '#7f8fa4',
- pointColor: '#7f8fa4',
+ fillColor: '#707070',
+ strokeColor: '#707070',
+ pointColor: '#707070',
pointStrokeColor: '#EEE',
data: chartScope.totalValues,
},
{
- fillColor: '#44aa22',
- strokeColor: '#44aa22',
- pointColor: '#44aa22',
+ fillColor: '#1aaa55',
+ strokeColor: '#1aaa55',
+ pointColor: '#1aaa55',
pointStrokeColor: '#fff',
data: chartScope.successValues,
},
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 05c1033c5f7..dffde736e24 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -993,3 +993,11 @@ button.mini-pipeline-graph-dropdown-toggle {
font-weight: $gl-font-weight-normal;
line-height: 1.5;
}
+
+.legend-all {
+ color: $gl-text-color-secondary;
+}
+
+.legend-success {
+ color: $green-500;
+}
diff --git a/app/views/projects/pipelines/charts/_pipelines.haml b/app/views/projects/pipelines/charts/_pipelines.haml
index 7a100843f5e..41dc2f6cf9d 100644
--- a/app/views/projects/pipelines/charts/_pipelines.haml
+++ b/app/views/projects/pipelines/charts/_pipelines.haml
@@ -4,11 +4,11 @@
%h4= _("Pipelines charts")
%p
- %span.cgreen
+ %span.legend-success
= icon("circle")
= s_("Pipeline|success")
- %span.cgray
+ %span.legend-all
= icon("circle")
= s_("Pipeline|all")
--
cgit v1.2.1
From 349d06688fa956732390e15cefc9006a1dd1bf8c Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Mon, 8 Jan 2018 20:01:49 +0000
Subject: Fix more eslint rules
---
.../clusters/components/application_row.vue | 9 +-
.../cycle_analytics/components/banner.vue | 3 +-
.../components/total_time_component.vue | 2 +-
.../environments/components/empty_state.vue | 3 +-
.../environments/components/environments_table.vue | 22 ++-
.../javascripts/groups/components/group_item.vue | 12 +-
app/assets/javascripts/ide/components/ide.vue | 106 ++++++------
.../javascripts/ide/components/ide_repo_tree.vue | 49 +++---
.../javascripts/ide/components/ide_side_bar.vue | 124 +++++++-------
.../ide/components/repo_commit_section.vue | 3 +-
.../javascripts/ide/components/repo_file.vue | 10 +-
app/assets/javascripts/jobs/components/header.vue | 2 +-
.../javascripts/monitoring/components/graph.vue | 124 +++++++-------
.../monitoring/components/graph/deployment.vue | 22 +--
.../monitoring/components/graph/flag.vue | 45 +++---
.../javascripts/notes/components/comment_form.vue | 6 +-
.../javascripts/notes/components/note_form.vue | 3 +-
.../components/pipeline_schedules_callout.vue | 4 +-
.../pipelines/components/empty_state.vue | 4 +-
.../javascripts/pipelines/components/pipelines.vue | 5 +-
.../permissions/components/settings_panel.vue | 3 +
.../components/projects_list_item.vue | 4 +-
app/assets/javascripts/registry/components/app.vue | 3 +-
.../components/states/mr_widget_rebase.vue | 4 +-
.../vue_shared/components/header_ci_component.vue | 178 +++++++++++----------
.../vue_shared/components/issue/issue_warning.vue | 3 +-
.../vue_shared/components/loading_icon.vue | 2 +-
27 files changed, 402 insertions(+), 353 deletions(-)
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index 4deedb29ecd..32d6813e74b 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -71,7 +71,8 @@
// Avoid the potential for the real-time data to say APPLICATION_INSTALLABLE but
// we already made a request to install and are just waiting for the real-time
// to sync up.
- return (this.status !== APPLICATION_INSTALLABLE && this.status !== APPLICATION_ERROR) ||
+ return (this.status !== APPLICATION_INSTALLABLE
+ && this.status !== APPLICATION_ERROR) ||
this.requestStatus === REQUEST_LOADING ||
this.requestStatus === REQUEST_SUCCESS;
},
@@ -83,7 +84,8 @@
this.status === APPLICATION_ERROR
) {
label = s__('ClusterIntegration|Install');
- } else if (this.status === APPLICATION_SCHEDULED || this.status === APPLICATION_INSTALLING) {
+ } else if (this.status === APPLICATION_SCHEDULED ||
+ this.status === APPLICATION_INSTALLING) {
label = s__('ClusterIntegration|Installing');
} else if (this.status === APPLICATION_INSTALLED) {
label = s__('ClusterIntegration|Installed');
@@ -92,7 +94,8 @@
return label;
},
hasError() {
- return this.status === APPLICATION_ERROR || this.requestStatus === REQUEST_FAILURE;
+ return this.status === APPLICATION_ERROR ||
+ this.requestStatus === REQUEST_FAILURE;
},
generalErrorDescription() {
return sprintf(
diff --git a/app/assets/javascripts/cycle_analytics/components/banner.vue b/app/assets/javascripts/cycle_analytics/components/banner.vue
index 049ecab5365..3204b8dd8e7 100644
--- a/app/assets/javascripts/cycle_analytics/components/banner.vue
+++ b/app/assets/javascripts/cycle_analytics/components/banner.vue
@@ -43,7 +43,8 @@
{{ __('Introducing Cycle Analytics') }}
- {{ __('Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.') }}
+ {{ __(`Cycle Analytics gives an overview
+of how much time it takes to go from idea to production in your project.`) }}
@@ -82,7 +85,8 @@ export default {
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.
+ You can select a file in the left sidebar to begin
+ editing and use the right sidebar to commit your changes.
+ :style="paddingBottomRootSvg"
+ >
+ ref="baseSvg"
+ >
-
+ :transform="axisTransform"
+ />
-
+ transform="translate(70, 20)"
+ />
-
-
-
-
+ ref="graphData"
+ >
+
+
+
-
+ fill="url(#shadow-gradient)"
+ />
-
+ stroke="#000"
+ />
+ width="0"
+ >
+ id="shadow-gradient"
+ >
-
+ stop-opacity="0.4"
+ />
-
+ stop-opacity="0"
+ />
diff --git a/app/assets/javascripts/monitoring/components/graph/flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue
index 62ebc3f419c..07aa6a3e5de 100644
--- a/app/assets/javascripts/monitoring/components/graph/flag.vue
+++ b/app/assets/javascripts/monitoring/components/graph/flag.vue
@@ -1,9 +1,12 @@
@@ -84,7 +82,7 @@ export default {
- {{itemName}} #{{itemId}}
+ {{ itemName }} #{{ itemId }}
@@ -103,16 +101,17 @@ export default {
v-tooltip
:href="user.path"
:title="user.email"
- class="js-user-link commit-committer-link">
+ class="js-user-link commit-committer-link"
+ >
+ />
- {{user.name}}
+ {{ user.name }}
@@ -121,12 +120,15 @@ export default {
class="header-action-buttons"
v-if="actions.length">
+ v-for="(action, i) in actions"
+ >
- {{action.label}}
+ :class="action.cssClass"
+ :key="i"
+ >
+ {{ action.label }}
- {{action.label}}
+ :class="action.cssClass"
+ :key="i"
+ >
+ {{ action.label }}
- {{action.label}}
+ type="button"
+ :key="i"
+ >
+ {{ action.label }}
+ aria-hidden="true"
+ >
+ id="toggleSidebar"
+ >
+ aria-labelledby="toggleSidebar"
+ >
diff --git a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
index 168799b9a58..b48828ae81f 100644
--- a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
+++ b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
@@ -45,7 +45,8 @@
{{ __('This issue is confidential and locked.') }}
- {{ __('People without permission will never get a notification and won\'t be able to comment.') }}
+ {{ __(`People without permission will never
+get a notification and won't be able to comment.`) }}
diff --git a/app/assets/javascripts/vue_shared/components/loading_icon.vue b/app/assets/javascripts/vue_shared/components/loading_icon.vue
index 3d2b6c44384..1eba117b18f 100644
--- a/app/assets/javascripts/vue_shared/components/loading_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/loading_icon.vue
@@ -32,7 +32,7 @@
Date: Tue, 1 Mar 2016 17:53:01 +0000
Subject: Backport authorized_keys branch 'find-key-by-fingerprint'
Add find key by base64 key or fingerprint to the internal API
See merge request !250
Squashed changes:
Add unique index to fingerprint
Add new index to schema
Add internal api to get ssh key by fingerprint
Change API endpoint to authorized_keys
Add InsecureKeyFingerprint that calculates the fingerprint without shelling out
Add require for gitlab key fingerprint
Remove uniqueness of fingerprint index
Remove unique option from migration
Fix spec style in fingerprint test
Fix rubocop complain
Extract insecure key fingerprint to separate file
Change migration to support building index concurrently
Remove those hideous tabs
---
db/migrate/20160301174731_add_fingerprint_index.rb | 16 ++++++++
lib/api/internal.rb | 12 ++++++
lib/gitlab/insecure_key_fingerprint.rb | 23 +++++++++++
spec/lib/gitlab/insecure_key_fingerprint_spec.rb | 18 ++++++++
spec/requests/api/internal_spec.rb | 48 ++++++++++++++++++++++
5 files changed, 117 insertions(+)
create mode 100644 db/migrate/20160301174731_add_fingerprint_index.rb
create mode 100644 lib/gitlab/insecure_key_fingerprint.rb
create mode 100644 spec/lib/gitlab/insecure_key_fingerprint_spec.rb
diff --git a/db/migrate/20160301174731_add_fingerprint_index.rb b/db/migrate/20160301174731_add_fingerprint_index.rb
new file mode 100644
index 00000000000..b7c4f7d140a
--- /dev/null
+++ b/db/migrate/20160301174731_add_fingerprint_index.rb
@@ -0,0 +1,16 @@
+# rubocop:disable all
+class AddFingerprintIndex < ActiveRecord::Migration
+ disable_ddl_transaction!
+
+ DOWNTIME = false
+
+ def change
+ args = [:keys, :fingerprint]
+
+ if Gitlab::Database.postgresql?
+ args << { algorithm: :concurrently }
+ end
+
+ add_index(*args)
+ end
+end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 79b302aae70..8bf53939751 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -81,6 +81,18 @@ module API
merge_request_urls
end
+ #
+ # Get a ssh key using the fingerprint
+ #
+ get "/authorized_keys" do
+ fingerprint = params.fetch(:fingerprint) do
+ Gitlab::InsecureKeyFingerprint.new(params.fetch(:key)).fingerprint
+ end
+ key = Key.find_by(fingerprint: fingerprint)
+ not_found!("Key") if key.nil?
+ present key, with: Entities::SSHKey
+ end
+
#
# Discover user by ssh key or user id
#
diff --git a/lib/gitlab/insecure_key_fingerprint.rb b/lib/gitlab/insecure_key_fingerprint.rb
new file mode 100644
index 00000000000..f85b6e9197f
--- /dev/null
+++ b/lib/gitlab/insecure_key_fingerprint.rb
@@ -0,0 +1,23 @@
+module Gitlab
+ #
+ # Calculates the fingerprint of a given key without using
+ # openssh key validations. For this reason, only use
+ # for calculating the fingerprint to find the key with it.
+ #
+ # DO NOT use it for checking the validity of a ssh key.
+ #
+ class InsecureKeyFingerprint
+ attr_accessor :key
+
+ #
+ # Gets the base64 encoded string representing a rsa or dsa key
+ #
+ def initialize(key_base64)
+ @key = key_base64
+ end
+
+ def fingerprint
+ OpenSSL::Digest::MD5.hexdigest(Base64.decode64(@key)).scan(/../).join(':')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/insecure_key_fingerprint_spec.rb b/spec/lib/gitlab/insecure_key_fingerprint_spec.rb
new file mode 100644
index 00000000000..6532579b1c9
--- /dev/null
+++ b/spec/lib/gitlab/insecure_key_fingerprint_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Gitlab::InsecureKeyFingerprint do
+ let(:key) do
+ 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn' \
+ '1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qk' \
+ 'r8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMg' \
+ 'Jw0='
+ end
+
+ let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" }
+
+ describe "#fingerprint" do
+ it "generates the key's fingerprint" do
+ expect(described_class.new(key.split[1]).fingerprint).to eq(fingerprint)
+ end
+ end
+end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 7b25047ea8f..7b5fddde456 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -192,6 +192,54 @@ describe API::Internal do
end
end
+ describe "GET /internal/authorized_keys" do
+ context "unsing an existing key's fingerprint" do
+ it "finds the key" do
+ get(api('/internal/authorized_keys'), fingerprint: key.fingerprint, secret_token: secret_token)
+
+ expect(response.status).to eq(200)
+ expect(json_response["key"]).to eq(key.key)
+ end
+ end
+
+ context "non existing key's fingerprint" do
+ it "returns 404" do
+ get(api('/internal/authorized_keys'), fingerprint: "no:t-:va:li:d0", secret_token: secret_token)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context "using a partial fingerprint" do
+ it "returns 404" do
+ get(api('/internal/authorized_keys'), fingerprint: "#{key.fingerprint[0..5]}%", secret_token: secret_token)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context "sending the key" do
+ it "finds the key" do
+ get(api('/internal/authorized_keys'), key: key.key.split[1], secret_token: secret_token)
+
+ expect(response.status).to eq(200)
+ expect(json_response["key"]).to eq(key.key)
+ end
+
+ it "returns 404 with a partial key" do
+ get(api('/internal/authorized_keys'), key: key.key.split[1][0...-3], secret_token: secret_token)
+
+ expect(response.status).to eq(404)
+ end
+
+ it "returns 404 with an not valid base64 string" do
+ get(api('/internal/authorized_keys'), key: "whatever!", secret_token: secret_token)
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
describe "POST /internal/allowed", :clean_gitlab_redis_shared_state do
context "access granted" do
around do |example|
--
cgit v1.2.1
From 255a0f85e3b62845b58f5a4aa189e57f36992c77 Mon Sep 17 00:00:00 2001
From: Michael Kozono
Date: Tue, 30 May 2017 16:24:45 -0700
Subject: Backport option to disable writing to `authorized_keys` file
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Originally branch 'mk-toggle-writing-to-auth-keys-1631'
See merge request !2004
Squashed commits:
Add authorized_keys_enabled to Application Settings
Ensure default settings are exposed in UI
Without this change, `authorized_keys_enabled` is unchecked when it is nil, even if it should be checked by default.
Add “Speed up SSH operations” documentation
Clarify the reasons for disabling writes
Add "How to go back" section
Tweak copy
Update Application Setting screenshot
---
.../admin/application_settings_controller.rb | 2 +-
app/helpers/application_settings_helper.rb | 1 +
app/models/application_setting.rb | 1 +
.../admin/application_settings/_form.html.haml | 16 +++
...horized_keys_enabled_to_application_settings.rb | 15 +++
db/schema.rb | 1 +
.../img/write_to_authorized_keys_setting.png | Bin 0 -> 94218 bytes
doc/administration/operations/index.md | 3 +-
doc/administration/operations/speed_up_ssh.md | 69 +++++++++++++
lib/gitlab/shell.rb | 12 +++
spec/lib/gitlab/shell_spec.rb | 110 ++++++++++++++++++---
11 files changed, 217 insertions(+), 13 deletions(-)
create mode 100644 db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb
create mode 100644 doc/administration/operations/img/write_to_authorized_keys_setting.png
create mode 100644 doc/administration/operations/speed_up_ssh.md
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 4dfb397e82c..4de808eb71f 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -52,7 +52,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
private
def set_application_setting
- @application_setting = ApplicationSetting.current
+ @application_setting = current_application_settings
end
def application_setting_params
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index b12ea760668..45f7d29eb05 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -146,6 +146,7 @@ module ApplicationSettingsHelper
:after_sign_up_text,
:akismet_api_key,
:akismet_enabled,
+ :authorized_keys_enabled,
:auto_devops_enabled,
:circuitbreaker_access_retries,
:circuitbreaker_check_interval,
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 253e213af81..8ab338d873d 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -261,6 +261,7 @@ class ApplicationSetting < ActiveRecord::Base
{
after_sign_up_text: nil,
akismet_enabled: false,
+ authorized_keys_enabled: true, # TODO default to false if the instance is configured to use AuthorizedKeysCommand
container_registry_token_expire_delay: 5,
default_artifacts_expire_in: '30 days',
default_branch_protection: Settings.gitlab['default_branch_protection'],
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 3e2dbb07a6c..ba4ca88a8a9 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -774,6 +774,22 @@
installations. Set to 0 to completely disable polling.
= link_to icon('question-circle'), help_page_path('administration/polling')
+ %fieldset
+ %legend Performance optimization
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :authorized_keys_enabled do
+ = f.check_box :authorized_keys_enabled
+ Write to "authorized_keys" file
+ .help-block
+ By default, we write to the "authorized_keys" file to support Git
+ over SSH without additional configuration. GitLab can be optimized
+ to authenticate SSH keys via the database file. Only uncheck this
+ if you have configured your OpenSSH server to use the
+ AuthorizedKeysCommand. Click on the help icon for more details.
+ = link_to icon('question-circle'), help_page_path('administration/operations/fast_ssh_key_lookup')
+
%fieldset
%legend User and IP Rate Limits
.form-group
diff --git a/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb b/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb
new file mode 100644
index 00000000000..fdae309946c
--- /dev/null
+++ b/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb
@@ -0,0 +1,15 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddAuthorizedKeysEnabledToApplicationSettings < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ def change
+ # allow_null: true because we want to set the default based on if the
+ # instance is configured to use AuthorizedKeysCommand
+ add_column :application_settings, :authorized_keys_enabled, :boolean, allow_null: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 740e80ccfd4..11273d2a82e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -154,6 +154,7 @@ ActiveRecord::Schema.define(version: 20171230123729) do
t.integer "gitaly_timeout_default", default: 55, null: false
t.integer "gitaly_timeout_medium", default: 30, null: false
t.integer "gitaly_timeout_fast", default: 10, null: false
+ t.boolean "authorized_keys_enabled"
end
create_table "audit_events", force: :cascade do |t|
diff --git a/doc/administration/operations/img/write_to_authorized_keys_setting.png b/doc/administration/operations/img/write_to_authorized_keys_setting.png
new file mode 100644
index 00000000000..232765f1917
Binary files /dev/null and b/doc/administration/operations/img/write_to_authorized_keys_setting.png differ
diff --git a/doc/administration/operations/index.md b/doc/administration/operations/index.md
index 320d71a9527..f96a084c853 100644
--- a/doc/administration/operations/index.md
+++ b/doc/administration/operations/index.md
@@ -13,4 +13,5 @@ by GitLab to another file system or another server.
that to prioritize important jobs.
- [Sidekiq MemoryKiller](sidekiq_memory_killer.md): Configure Sidekiq MemoryKiller
to restart Sidekiq.
-- [Unicorn](unicorn.md): Understand Unicorn and unicorn-worker-killer.
\ No newline at end of file
+- [Unicorn](unicorn.md): Understand Unicorn and unicorn-worker-killer.
+- [Speed up SSH operations](speed_up_ssh.md)
diff --git a/doc/administration/operations/speed_up_ssh.md b/doc/administration/operations/speed_up_ssh.md
new file mode 100644
index 00000000000..9b260beb34f
--- /dev/null
+++ b/doc/administration/operations/speed_up_ssh.md
@@ -0,0 +1,69 @@
+# Speed up SSH operations
+
+## The problem
+
+SSH operations become slow as the number of users grows.
+
+## The reason
+
+OpenSSH searches for a key to authorize a user via a linear search. In the worst case, such as when the user is not authorized to access GitLab, OpenSSH will scan the entire file to search for a key. This can take significant time and disk I/O, which will delay users attempting to push or pull to a repository. Making matters worse, if users add or remove keys frequently, the operating system may not be able to cache the authorized_keys file, which causes the disk to be accessed repeatedly.
+
+## The solution
+
+GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to check whether the user is authorized to access GitLab.
+
+> **Warning:** OpenSSH version 6.9+ is required because `AuthorizedKeysCommand` must be able to accept a fingerprint. These instructions will break installations using older versions of OpenSSH, such as those included with CentOS as of May 2017.
+
+Create this file at `/opt/gitlab-shell/authorized_keys`:
+
+```
+#!/bin/bash
+
+if [[ "$1" == "git" ]]; then
+ /opt/gitlab/embedded/service/gitlab-shell/bin/authorized_keys $2
+fi
+```
+
+Set appropriate ownership and permissions:
+
+```
+sudo chown root:git /opt/gitlab-shell/authorized_keys
+sudo chmod 0650 /opt/gitlab-shell/authorized_keys
+```
+
+Add the following to `/etc/ssh/sshd_config`:
+
+```
+AuthorizedKeysCommand /opt/gitlab-shell/authorized_keys %u %k
+AuthorizedKeysCommandUser git
+```
+
+Reload the sshd service:
+
+```
+sudo service sshd reload
+```
+
+Confirm that SSH is working by removing your user's SSH key in the UI, adding a new one, and attempting to pull a repo.
+
+> **Warning:** Do not disable writes until SSH is confirmed to be working perfectly because the file will quickly become out-of-date.
+
+In the case of lookup failures (which are not uncommon), the `authorized_keys` file will still be scanned. So git SSH performance will still be slow for many users as long as a large file exists.
+
+You can disable any more writes to the `authorized_keys` file by unchecking `Write to "authorized_keys" file` in the Application Settings of your GitLab installation.
+
+![Write to authorized keys setting](img/write_to_authorized_keys_setting.png)
+
+Again, confirm that SSH is working by removing your user's SSH key in the UI, adding a new one, and attempting to pull a repo.
+
+Then you can backup and delete your `authorized_keys` file for best performance.
+
+## How to go back to using the `authorized_keys` file
+
+This is a brief overview. Please refer to the above instructions for more context.
+
+1. Rebuild the `authorized_keys` file. See https://docs.gitlab.com/ce/administration/raketasks/maintenance.html#rebuild-authorized_keys-file
+1. Enable writes to the `authorized_keys` file
+1. Remove the `AuthorizedKeysCommand` lines from `/etc/ssh/sshd_config`
+1. Reload the sshd service
+1. Remove the `/opt/gitlab-shell/authorized_keys` file
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 564047bbd34..20df19c734d 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -183,6 +183,8 @@ module Gitlab
# add_key("key-42", "sha-rsa ...")
#
def add_key(key_id, key_content)
+ return unless self.authorized_keys_enabled?
+
gitlab_shell_fast_execute([gitlab_shell_keys_path,
'add-key', key_id, self.class.strip_key(key_content)])
end
@@ -192,6 +194,8 @@ module Gitlab
# Ex.
# batch_add_keys { |adder| adder.add_key("key-42", "sha-rsa ...") }
def batch_add_keys(&block)
+ return unless self.authorized_keys_enabled?
+
IO.popen(%W(#{gitlab_shell_path}/bin/gitlab-keys batch-add-keys), 'w') do |io|
yield(KeyAdder.new(io))
end
@@ -203,6 +207,8 @@ module Gitlab
# remove_key("key-342", "sha-rsa ...")
#
def remove_key(key_id, key_content)
+ return unless self.authorized_keys_enabled?
+
args = [gitlab_shell_keys_path, 'rm-key', key_id]
args << key_content if key_content
@@ -215,6 +221,8 @@ module Gitlab
# remove_all_keys
#
def remove_all_keys
+ return unless self.authorized_keys_enabled?
+
gitlab_shell_fast_execute([gitlab_shell_keys_path, 'clear'])
end
@@ -410,5 +418,9 @@ module Gitlab
# need to do the same here...
raise Error, e
end
+
+ def authorized_keys_enabled?
+ current_application_settings.authorized_keys_enabled
+ end
end
end
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 81d9e6a8f82..6d50f537430 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -51,6 +51,105 @@ describe Gitlab::Shell do
end
end
+ describe '#add_key' do
+ context 'when authorized_keys_enabled is true' do
+ it 'removes trailing garbage' do
+ allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
+ expect(Gitlab::Utils).to receive(:system_silent).with(
+ [:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
+ )
+
+ gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
+ end
+ end
+
+ context 'when authorized_keys_enabled is false' do
+ before do
+ stub_application_setting(authorized_keys_enabled: false)
+ end
+
+ it 'does nothing' do
+ expect(Gitlab::Utils).not_to receive(:system_silent)
+
+ gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
+ end
+ end
+ end
+
+ describe '#batch_add_keys' do
+ context 'when authorized_keys_enabled is true' do
+ it 'instantiates KeyAdder' do
+ expect_any_instance_of(Gitlab::Shell::KeyAdder).to receive(:add_key).with('key-123', 'ssh-rsa foobar')
+
+ gitlab_shell.batch_add_keys do |adder|
+ adder.add_key('key-123', 'ssh-rsa foobar')
+ end
+ end
+ end
+
+ context 'when authorized_keys_enabled is false' do
+ before do
+ stub_application_setting(authorized_keys_enabled: false)
+ end
+
+ it 'does nothing' do
+ expect_any_instance_of(Gitlab::Shell::KeyAdder).not_to receive(:add_key)
+
+ gitlab_shell.batch_add_keys do |adder|
+ adder.add_key('key-123', 'ssh-rsa foobar')
+ end
+ end
+ end
+ end
+
+ describe '#remove_key' do
+ context 'when authorized_keys_enabled is true' do
+ it 'removes trailing garbage' do
+ allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
+ expect(Gitlab::Utils).to receive(:system_silent).with(
+ [:gitlab_shell_keys_path, 'rm-key', 'key-123', 'ssh-rsa foobar']
+ )
+
+ gitlab_shell.remove_key('key-123', 'ssh-rsa foobar')
+ end
+ end
+
+ context 'when authorized_keys_enabled is false' do
+ before do
+ stub_application_setting(authorized_keys_enabled: false)
+ end
+
+ it 'does nothing' do
+ expect(Gitlab::Utils).not_to receive(:system_silent)
+
+ gitlab_shell.remove_key('key-123', 'ssh-rsa foobar')
+ end
+ end
+ end
+
+ describe '#remove_all_keys' do
+ context 'when authorized_keys_enabled is true' do
+ it 'removes trailing garbage' do
+ allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
+ expect(Gitlab::Utils).to receive(:system_silent).with([:gitlab_shell_keys_path, 'clear'])
+
+ gitlab_shell.remove_all_keys
+ end
+ end
+
+ context 'when authorized_keys_enabled is false' do
+ before do
+ stub_application_setting(authorized_keys_enabled: false)
+ end
+
+ it 'does nothing' do
+ expect(Gitlab::Utils).not_to receive(:system_silent)
+
+ gitlab_shell.remove_all_keys
+ end
+ end
+ end
+
describe Gitlab::Shell::KeyAdder do
describe '#add_key' do
it 'removes trailing garbage' do
@@ -96,17 +195,6 @@ describe Gitlab::Shell do
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
end
- describe '#add_key' do
- it 'removes trailing garbage' do
- allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
- [:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
- )
-
- gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
- end
- end
-
describe '#add_repository' do
shared_examples '#add_repository' do
let(:repository_storage) { 'default' }
--
cgit v1.2.1
From 07bd79cd721a13fc012b77b09e56cd709e5a22f3 Mon Sep 17 00:00:00 2001
From: Ernst van Nierop
Date: Fri, 15 Dec 2017 12:39:44 +0000
Subject: Combine ssh docs and rename the doc
Backport to CE, originally branch 'evn-ssh-clarify-docs
See merge request gitlab-org/gitlab-ee!3753
---
.../operations/fast_ssh_key_lookup.md | 192 +++++++++++++++++++++
doc/administration/operations/index.md | 2 +-
doc/administration/operations/speed_up_ssh.md | 70 +-------
3 files changed, 194 insertions(+), 70 deletions(-)
create mode 100644 doc/administration/operations/fast_ssh_key_lookup.md
diff --git a/doc/administration/operations/fast_ssh_key_lookup.md b/doc/administration/operations/fast_ssh_key_lookup.md
new file mode 100644
index 00000000000..b86168f935a
--- /dev/null
+++ b/doc/administration/operations/fast_ssh_key_lookup.md
@@ -0,0 +1,192 @@
+# Fast lookup of authorized SSH keys in the database
+
+Regular SSH operations become slow as the number of users grows because OpenSSH
+searches for a key to authorize a user via a linear search. In the worst case,
+such as when the user is not authorized to access GitLab, OpenSSH will scan the
+entire file to search for a key. This can take significant time and disk I/O,
+which will delay users attempting to push or pull to a repository. Making
+matters worse, if users add or remove keys frequently, the operating system may
+not be able to cache the `authorized_keys` file, which causes the disk to be
+accessed repeatedly.
+
+GitLab Shell solves this by providing a way to authorize SSH users via a fast,
+indexed lookup in the GitLab database. This page describes how to enable the fast
+lookup of authorized SSH keys.
+
+> **Warning:** OpenSSH version 6.9+ is required because
+`AuthorizedKeysCommand` must be able to accept a fingerprint. These
+instructions will break installations using older versions of OpenSSH, such as
+those included with CentOS 6 as of September 2017. If you want to use this
+feature for CentOS 6, follow [the instructions on how to build and install a custom OpenSSH package](#compiling-a-custom-version-of-openssh-for-centos-6) before continuing.
+
+## Setting up fast lookup via GitLab Shell
+
+GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup
+to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to
+check whether the user is authorized to access GitLab.
+
+Create the directory `/opt/gitlab-shell` first:
+
+```bash
+sudo mkdir -p /opt/gitlab-shell
+```
+
+Create this file at `/opt/gitlab-shell/authorized_keys`:
+
+```
+#!/bin/bash
+
+if [[ "$1" == "git" ]]; then
+ /opt/gitlab/embedded/service/gitlab-shell/bin/authorized_keys $2
+fi
+```
+
+Set appropriate ownership and permissions:
+
+```
+sudo chown root:git /opt/gitlab-shell/authorized_keys
+sudo chmod 0650 /opt/gitlab-shell/authorized_keys
+```
+
+Add the following to `/etc/ssh/sshd_config` or to `/assets/sshd_config` if you
+are using Omnibus Docker:
+
+```
+AuthorizedKeysCommand /opt/gitlab-shell/authorized_keys %u %k
+AuthorizedKeysCommandUser git
+```
+
+Reload OpenSSH:
+
+```bash
+# Debian or Ubuntu installations
+sudo service ssh reload
+
+# CentOS installations
+sudo service sshd reload
+```
+
+Confirm that SSH is working by removing your user's SSH key in the UI, adding a
+new one, and attempting to pull a repo.
+
+> **Warning:** Do not disable writes until SSH is confirmed to be working
+perfectly because the file will quickly become out-of-date.
+
+In the case of lookup failures (which are not uncommon), the `authorized_keys`
+file will still be scanned. So git SSH performance will still be slow for many
+users as long as a large file exists.
+
+You can disable any more writes to the `authorized_keys` file by unchecking
+`Write to "authorized_keys" file` in the Application Settings of your GitLab
+installation.
+
+![Write to authorized keys setting](img/write_to_authorized_keys_setting.png)
+
+Again, confirm that SSH is working by removing your user's SSH key in the UI,
+adding a new one, and attempting to pull a repo.
+
+Then you can backup and delete your `authorized_keys` file for best performance.
+
+## How to go back to using the `authorized_keys` file
+
+This is a brief overview. Please refer to the above instructions for more context.
+
+1. [Rebuild the `authorized_keys` file](../raketasks/maintenance.md#rebuild-authorized_keys-file)
+1. Enable writes to the `authorized_keys` file in Application Settings
+1. Remove the `AuthorizedKeysCommand` lines from `/etc/ssh/sshd_config` or from `/assets/sshd_config` if you are using Omnibus Docker.
+1. Reload sshd: `sudo service sshd reload`
+1. Remove the `/opt/gitlab-shell/authorized_keys` file
+
+## Compiling a custom version of OpenSSH for CentOS 6
+
+Building a custom version of OpenSSH is not necessary for Ubuntu 16.04 users,
+since Ubuntu 16.04 ships with OpenSSH 7.2.
+
+It is also unnecessary for CentOS 7.4 users, as that version ships with
+OpenSSH 7.4. If you are using CentOS 7.0 - 7.3, we strongly recommend that you
+upgrade to CentOS 7.4 instead of following this procedure. This should be as
+simple as running `yum update`.
+
+CentOS 6 users must build their own OpenSSH package to enable SSH lookups via
+the database. The following instructions can be used to build OpenSSH 7.5:
+
+1. First, download the package and install the required packages:
+
+ ```
+ sudo su -
+ cd /tmp
+ curl --remote-name https://mirrors.evowise.com/pub/OpenBSD/OpenSSH/portable/openssh-7.5p1.tar.gz
+ tar xzvf openssh-7.5p1.tar.gz
+ yum install rpm-build gcc make wget openssl-devel krb5-devel pam-devel libX11-devel xmkmf libXt-devel
+ ```
+
+3. Prepare the build by copying files to the right place:
+
+ ```
+ mkdir -p /root/rpmbuild/{SOURCES,SPECS}
+ cp ./openssh-7.5p1/contrib/redhat/openssh.spec /root/rpmbuild/SPECS/
+ cp openssh-7.5p1.tar.gz /root/rpmbuild/SOURCES/
+ cd /root/rpmbuild/SPECS
+ ```
+
+3. Next, set the spec settings properly:
+
+ ```
+ sed -i -e "s/%define no_gnome_askpass 0/%define no_gnome_askpass 1/g" openssh.spec
+ sed -i -e "s/%define no_x11_askpass 0/%define no_x11_askpass 1/g" openssh.spec
+ sed -i -e "s/BuildPreReq/BuildRequires/g" openssh.spec
+ ```
+
+3. Build the RPMs:
+
+ ```
+ rpmbuild -bb openssh.spec
+ ```
+
+4. Ensure the RPMs were built:
+
+ ```
+ ls -al /root/rpmbuild/RPMS/x86_64/
+ ```
+
+ You should see something as the following:
+
+ ```
+ total 1324
+ drwxr-xr-x. 2 root root 4096 Jun 20 19:37 .
+ drwxr-xr-x. 3 root root 19 Jun 20 19:37 ..
+ -rw-r--r--. 1 root root 470828 Jun 20 19:37 openssh-7.5p1-1.x86_64.rpm
+ -rw-r--r--. 1 root root 490716 Jun 20 19:37 openssh-clients-7.5p1-1.x86_64.rpm
+ -rw-r--r--. 1 root root 17020 Jun 20 19:37 openssh-debuginfo-7.5p1-1.x86_64.rpm
+ -rw-r--r--. 1 root root 367516 Jun 20 19:37 openssh-server-7.5p1-1.x86_64.rpm
+ ```
+
+5. Install the packages. OpenSSH packages will replace `/etc/pam.d/sshd`
+ with its own version, which may prevent users from logging in, so be sure
+ that the file is backed up and restored after installation:
+
+ ```
+ timestamp=$(date +%s)
+ cp /etc/pam.d/sshd pam-ssh-conf-$timestamp
+ rpm -Uvh /root/rpmbuild/RPMS/x86_64/*.rpm
+ yes | cp pam-ssh-conf-$timestamp /etc/pam.d/sshd
+ ```
+
+6. Verify the installed version. In another window, attempt to login to the server:
+
+ ```
+ ssh -v
+ ```
+
+ You should see a line that reads: "debug1: Remote protocol version 2.0, remote software version OpenSSH_7.5"
+
+ If not, you may need to restart sshd (e.g. `systemctl restart sshd.service`).
+
+7. *IMPORTANT!* Open a new SSH session to your server before exiting to make
+ sure everything is working! If you need to downgrade, simple install the
+ older package:
+
+ ```
+ # Only run this if you run into a problem logging in
+ yum downgrade openssh-server openssh openssh-clients
+ ```
diff --git a/doc/administration/operations/index.md b/doc/administration/operations/index.md
index f96a084c853..5655b7efec6 100644
--- a/doc/administration/operations/index.md
+++ b/doc/administration/operations/index.md
@@ -14,4 +14,4 @@ that to prioritize important jobs.
- [Sidekiq MemoryKiller](sidekiq_memory_killer.md): Configure Sidekiq MemoryKiller
to restart Sidekiq.
- [Unicorn](unicorn.md): Understand Unicorn and unicorn-worker-killer.
-- [Speed up SSH operations](speed_up_ssh.md)
+- [Speed up SSH operations](fast_ssh_key_lookup.md): Authorize SSH users via a fast, indexed lookup to the GitLab database.
diff --git a/doc/administration/operations/speed_up_ssh.md b/doc/administration/operations/speed_up_ssh.md
index 9b260beb34f..89265b3018b 100644
--- a/doc/administration/operations/speed_up_ssh.md
+++ b/doc/administration/operations/speed_up_ssh.md
@@ -1,69 +1 @@
-# Speed up SSH operations
-
-## The problem
-
-SSH operations become slow as the number of users grows.
-
-## The reason
-
-OpenSSH searches for a key to authorize a user via a linear search. In the worst case, such as when the user is not authorized to access GitLab, OpenSSH will scan the entire file to search for a key. This can take significant time and disk I/O, which will delay users attempting to push or pull to a repository. Making matters worse, if users add or remove keys frequently, the operating system may not be able to cache the authorized_keys file, which causes the disk to be accessed repeatedly.
-
-## The solution
-
-GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to check whether the user is authorized to access GitLab.
-
-> **Warning:** OpenSSH version 6.9+ is required because `AuthorizedKeysCommand` must be able to accept a fingerprint. These instructions will break installations using older versions of OpenSSH, such as those included with CentOS as of May 2017.
-
-Create this file at `/opt/gitlab-shell/authorized_keys`:
-
-```
-#!/bin/bash
-
-if [[ "$1" == "git" ]]; then
- /opt/gitlab/embedded/service/gitlab-shell/bin/authorized_keys $2
-fi
-```
-
-Set appropriate ownership and permissions:
-
-```
-sudo chown root:git /opt/gitlab-shell/authorized_keys
-sudo chmod 0650 /opt/gitlab-shell/authorized_keys
-```
-
-Add the following to `/etc/ssh/sshd_config`:
-
-```
-AuthorizedKeysCommand /opt/gitlab-shell/authorized_keys %u %k
-AuthorizedKeysCommandUser git
-```
-
-Reload the sshd service:
-
-```
-sudo service sshd reload
-```
-
-Confirm that SSH is working by removing your user's SSH key in the UI, adding a new one, and attempting to pull a repo.
-
-> **Warning:** Do not disable writes until SSH is confirmed to be working perfectly because the file will quickly become out-of-date.
-
-In the case of lookup failures (which are not uncommon), the `authorized_keys` file will still be scanned. So git SSH performance will still be slow for many users as long as a large file exists.
-
-You can disable any more writes to the `authorized_keys` file by unchecking `Write to "authorized_keys" file` in the Application Settings of your GitLab installation.
-
-![Write to authorized keys setting](img/write_to_authorized_keys_setting.png)
-
-Again, confirm that SSH is working by removing your user's SSH key in the UI, adding a new one, and attempting to pull a repo.
-
-Then you can backup and delete your `authorized_keys` file for best performance.
-
-## How to go back to using the `authorized_keys` file
-
-This is a brief overview. Please refer to the above instructions for more context.
-
-1. Rebuild the `authorized_keys` file. See https://docs.gitlab.com/ce/administration/raketasks/maintenance.html#rebuild-authorized_keys-file
-1. Enable writes to the `authorized_keys` file
-1. Remove the `AuthorizedKeysCommand` lines from `/etc/ssh/sshd_config`
-1. Reload the sshd service
-1. Remove the `/opt/gitlab-shell/authorized_keys` file
+This document was moved to [another location](fast_ssh_key_lookup.md).
--
cgit v1.2.1
From bcffeade9df825d40a4fe9cf9c1401b326c1fa9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Coutable?=
Date: Wed, 11 Oct 2017 16:45:56 +0200
Subject: Use ApplicationSetting.current in
Admin::ApplicationSettingsController
See merge request gitlab-org/gitlab-ee!3323
Backported as part of authorized_keys in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/16014
---
app/controllers/admin/application_settings_controller.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 4de808eb71f..4dfb397e82c 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -52,7 +52,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
private
def set_application_setting
- @application_setting = current_application_settings
+ @application_setting = ApplicationSetting.current
end
def application_setting_params
--
cgit v1.2.1
From 797fe0a6e6ce2f1241d2bd22c4b491c367e796fd Mon Sep 17 00:00:00 2001
From: Michael Kozono
Date: Mon, 26 Jun 2017 14:40:08 -0700
Subject: Backport authorized_keys_enabled defaults to true'
Originally from branch 'fix-authorized-keys-enabled-default-2738' via merge request https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2240
Removed background migrations which were intended to fix state after using Gitlab
without a default having been set
Squashed commits:
Locally, if Spring was not restarted, `current_application_settings` was still cached, which prevented the migration from editing the file. This will also ensure that any app server somehow hitting old cache data will properly default this setting regardless.
Retroactively fix migration
This allows us to identify customers who ran the broken migration. Their `authorized_keys_enabled` column does not have a default at this point.
We will fix the column after we fix the `authorized_keys` file.
Fix authorized_keys file if needed
Add default to authorized_keys_enabled setting
Reminder: The original migration was fixed retroactively a few commits ago, so people who did not ever run GitLab 9.3.0 already have a column that defaults to true and disallows nulls. I have tested on PostgreSQL and MySQL that it is safe to run this migration regardless.
Affected customers who did run 9.3.0 are the ones who need this migration to fix the authorized_keys_enabled column.
The reason for the retroactive fix plus this migration is that it allows us to run a migration in between to fix the authorized_keys file only for those who ran 9.3.0.
Tweaks to address feedback
Extract work into background migration
Move batch-add-logic to background migration
Do the work synchronously to avoid multiple workers attempting to add batches of keys at the same time.
Also, make the delete portion wait until after adding is done.
Do read and delete work in background migration
Fix Rubocop offenses
Add changelog entry
Inform the user of actions taken or not taken
Prevent unnecessary `select`s and `remove_key`s
Add logs for action taken
Fix optimization
Reuse `Gitlab::ShellAdapter`
Guarantee the earliest key
Fix migration spec for MySQL
---
...horized_keys_enabled_to_application_settings.rb | 12 +-
db/schema.rb | 2 +-
lib/gitlab/shell.rb | 58 +++++-
spec/lib/gitlab/shell_spec.rb | 212 +++++++++++++++++++++
spec/workers/gitlab_shell_worker_spec.rb | 12 ++
5 files changed, 289 insertions(+), 7 deletions(-)
create mode 100644 spec/workers/gitlab_shell_worker_spec.rb
diff --git a/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb b/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb
index fdae309946c..1d86a531eb3 100644
--- a/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb
+++ b/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb
@@ -7,9 +7,13 @@ class AddAuthorizedKeysEnabledToApplicationSettings < ActiveRecord::Migration
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
- def change
- # allow_null: true because we want to set the default based on if the
- # instance is configured to use AuthorizedKeysCommand
- add_column :application_settings, :authorized_keys_enabled, :boolean, allow_null: true
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default :application_settings, :authorized_keys_enabled, :boolean, default: true, allow_null: false
+ end
+
+ def down
+ remove_column :application_settings, :authorized_keys_enabled
end
end
diff --git a/db/schema.rb b/db/schema.rb
index 11273d2a82e..840abffd9f4 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -154,7 +154,7 @@ ActiveRecord::Schema.define(version: 20171230123729) do
t.integer "gitaly_timeout_default", default: 55, null: false
t.integer "gitaly_timeout_medium", default: 30, null: false
t.integer "gitaly_timeout_fast", default: 10, null: false
- t.boolean "authorized_keys_enabled"
+ t.boolean "authorized_keys_enabled", default: true, null: false
end
create_table "audit_events", force: :cascade do |t|
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 20df19c734d..65a9e58adf1 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -206,12 +206,11 @@ module Gitlab
# Ex.
# remove_key("key-342", "sha-rsa ...")
#
- def remove_key(key_id, key_content)
+ def remove_key(key_id, key_content = nil)
return unless self.authorized_keys_enabled?
args = [gitlab_shell_keys_path, 'rm-key', key_id]
args << key_content if key_content
-
gitlab_shell_fast_execute(args)
end
@@ -226,6 +225,57 @@ module Gitlab
gitlab_shell_fast_execute([gitlab_shell_keys_path, 'clear'])
end
+ # Remove ssh keys from gitlab shell that are not in the DB
+ #
+ # Ex.
+ # remove_keys_not_found_in_db
+ #
+ def remove_keys_not_found_in_db
+ return unless self.authorized_keys_enabled?
+
+ Rails.logger.info("Removing keys not found in DB")
+
+ batch_read_key_ids do |ids_in_file|
+ ids_in_file.uniq!
+ keys_in_db = Key.where(id: ids_in_file)
+
+ next unless ids_in_file.size > keys_in_db.count # optimization
+
+ ids_to_remove = ids_in_file - keys_in_db.pluck(:id)
+ ids_to_remove.each do |id|
+ Rails.logger.info("Removing key-#{id} not found in DB")
+ remove_key("key-#{id}")
+ end
+ end
+ end
+
+ # Iterate over all ssh key IDs from gitlab shell, in batches
+ #
+ # Ex.
+ # batch_read_key_ids { |batch| keys = Key.where(id: batch) }
+ #
+ def batch_read_key_ids(batch_size: 100, &block)
+ return unless self.authorized_keys_enabled?
+
+ list_key_ids do |key_id_stream|
+ key_id_stream.lazy.each_slice(batch_size) do |lines|
+ key_ids = lines.map { |l| l.chomp.to_i }
+ yield(key_ids)
+ end
+ end
+ end
+
+ # Stream all ssh key IDs from gitlab shell, separated by newlines
+ #
+ # Ex.
+ # list_key_ids
+ #
+ def list_key_ids(&block)
+ return unless self.authorized_keys_enabled?
+
+ IO.popen(%W(#{gitlab_shell_path}/bin/gitlab-keys list-key-ids), &block)
+ end
+
# Add empty directory for storing repositories
#
# Ex.
@@ -420,6 +470,10 @@ module Gitlab
end
def authorized_keys_enabled?
+ # Return true if nil to ensure the authorized_keys methods work while
+ # fixing the authorized_keys file during migration.
+ return true if current_application_settings.authorized_keys_enabled.nil?
+
current_application_settings.authorized_keys_enabled
end
end
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 6d50f537430..e452fbb757d 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -74,6 +74,21 @@ describe Gitlab::Shell do
gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
end
end
+
+ context 'when authorized_keys_enabled is nil' do
+ before do
+ stub_application_setting(authorized_keys_enabled: nil)
+ end
+
+ it 'removes trailing garbage' do
+ allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
+ expect(Gitlab::Utils).to receive(:system_silent).with(
+ [:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
+ )
+
+ gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
+ end
+ end
end
describe '#batch_add_keys' do
@@ -100,6 +115,20 @@ describe Gitlab::Shell do
end
end
end
+
+ context 'when authorized_keys_enabled is nil' do
+ before do
+ stub_application_setting(authorized_keys_enabled: nil)
+ end
+
+ it 'instantiates KeyAdder' do
+ expect_any_instance_of(Gitlab::Shell::KeyAdder).to receive(:add_key).with('key-123', 'ssh-rsa foobar')
+
+ gitlab_shell.batch_add_keys do |adder|
+ adder.add_key('key-123', 'ssh-rsa foobar')
+ end
+ end
+ end
end
describe '#remove_key' do
@@ -125,6 +154,32 @@ describe Gitlab::Shell do
gitlab_shell.remove_key('key-123', 'ssh-rsa foobar')
end
end
+
+ context 'when authorized_keys_enabled is nil' do
+ before do
+ stub_application_setting(authorized_keys_enabled: nil)
+ end
+
+ it 'removes trailing garbage' do
+ allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
+ expect(Gitlab::Utils).to receive(:system_silent).with(
+ [:gitlab_shell_keys_path, 'rm-key', 'key-123', 'ssh-rsa foobar']
+ )
+
+ gitlab_shell.remove_key('key-123', 'ssh-rsa foobar')
+ end
+ end
+
+ context 'when key content is not given' do
+ it 'calls rm-key with only one argument' do
+ allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
+ expect(Gitlab::Utils).to receive(:system_silent).with(
+ [:gitlab_shell_keys_path, 'rm-key', 'key-123']
+ )
+
+ gitlab_shell.remove_key('key-123')
+ end
+ end
end
describe '#remove_all_keys' do
@@ -148,6 +203,155 @@ describe Gitlab::Shell do
gitlab_shell.remove_all_keys
end
end
+
+ context 'when authorized_keys_enabled is nil' do
+ before do
+ stub_application_setting(authorized_keys_enabled: nil)
+ end
+
+ it 'removes trailing garbage' do
+ allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
+ expect(Gitlab::Utils).to receive(:system_silent).with([:gitlab_shell_keys_path, 'clear'])
+
+ gitlab_shell.remove_all_keys
+ end
+ end
+ end
+
+ describe '#remove_keys_not_found_in_db' do
+ context 'when keys are in the file that are not in the DB' do
+ before do
+ gitlab_shell.remove_all_keys
+ gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF')
+ gitlab_shell.add_key('key-9876', 'ssh-rsa ASDFASDF')
+ @another_key = create(:key) # this one IS in the DB
+ end
+
+ it 'removes the keys' do
+ expect(find_in_authorized_keys_file(1234)).to be_truthy
+ expect(find_in_authorized_keys_file(9876)).to be_truthy
+ expect(find_in_authorized_keys_file(@another_key.id)).to be_truthy
+ gitlab_shell.remove_keys_not_found_in_db
+ expect(find_in_authorized_keys_file(1234)).to be_falsey
+ expect(find_in_authorized_keys_file(9876)).to be_falsey
+ expect(find_in_authorized_keys_file(@another_key.id)).to be_truthy
+ end
+ end
+
+ context 'when keys there are duplicate keys in the file that are not in the DB' do
+ before do
+ gitlab_shell.remove_all_keys
+ gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF')
+ gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF')
+ end
+
+ it 'removes the keys' do
+ expect(find_in_authorized_keys_file(1234)).to be_truthy
+ gitlab_shell.remove_keys_not_found_in_db
+ expect(find_in_authorized_keys_file(1234)).to be_falsey
+ end
+
+ it 'does not run remove more than once per key (in a batch)' do
+ expect(gitlab_shell).to receive(:remove_key).with('key-1234').once
+ gitlab_shell.remove_keys_not_found_in_db
+ end
+ end
+
+ context 'when keys there are duplicate keys in the file that ARE in the DB' do
+ before do
+ gitlab_shell.remove_all_keys
+ @key = create(:key)
+ gitlab_shell.add_key(@key.shell_id, @key.key)
+ end
+
+ it 'does not remove the key' do
+ gitlab_shell.remove_keys_not_found_in_db
+ expect(find_in_authorized_keys_file(@key.id)).to be_truthy
+ end
+
+ it 'does not need to run a SELECT query for that batch, on account of that key' do
+ expect_any_instance_of(ActiveRecord::Relation).not_to receive(:pluck)
+ gitlab_shell.remove_keys_not_found_in_db
+ end
+ end
+
+ unless ENV['CI'] # Skip in CI, it takes 1 minute
+ context 'when the first batch can be skipped, but the next batch has keys that are not in the DB' do
+ before do
+ gitlab_shell.remove_all_keys
+ 100.times { |i| create(:key) } # first batch is all in the DB
+ gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF')
+ end
+
+ it 'removes the keys not in the DB' do
+ expect(find_in_authorized_keys_file(1234)).to be_truthy
+ gitlab_shell.remove_keys_not_found_in_db
+ expect(find_in_authorized_keys_file(1234)).to be_falsey
+ end
+ end
+ end
+ end
+
+ describe '#batch_read_key_ids' do
+ context 'when there are keys in the authorized_keys file' do
+ before do
+ gitlab_shell.remove_all_keys
+ (1..4).each do |i|
+ gitlab_shell.add_key("key-#{i}", "ssh-rsa ASDFASDF#{i}")
+ end
+ end
+
+ it 'iterates over the key IDs in the file, in batches' do
+ loop_count = 0
+ first_batch = [1, 2]
+ second_batch = [3, 4]
+
+ gitlab_shell.batch_read_key_ids(batch_size: 2) do |batch|
+ expected = (loop_count == 0 ? first_batch : second_batch)
+ expect(batch).to eq(expected)
+ loop_count += 1
+ end
+ end
+ end
+ end
+
+ describe '#list_key_ids' do
+ context 'when there are keys in the authorized_keys file' do
+ before do
+ gitlab_shell.remove_all_keys
+ (1..4).each do |i|
+ gitlab_shell.add_key("key-#{i}", "ssh-rsa ASDFASDF#{i}")
+ end
+ end
+
+ it 'outputs the key IDs in the file, separated by newlines' do
+ ids = []
+ gitlab_shell.list_key_ids do |io|
+ io.each do |line|
+ ids << line
+ end
+ end
+
+ expect(ids).to eq(%W{1\n 2\n 3\n 4\n})
+ end
+ end
+
+ context 'when there are no keys in the authorized_keys file' do
+ before do
+ gitlab_shell.remove_all_keys
+ end
+
+ it 'outputs nothing, not even an empty string' do
+ ids = []
+ gitlab_shell.list_key_ids do |io|
+ io.each do |line|
+ ids << line
+ end
+ end
+
+ expect(ids).to eq([])
+ end
+ end
end
describe Gitlab::Shell::KeyAdder do
@@ -484,4 +688,12 @@ describe Gitlab::Shell do
end
end
end
+
+ def find_in_authorized_keys_file(key_id)
+ gitlab_shell.batch_read_key_ids do |ids|
+ return true if ids.include?(key_id)
+ end
+
+ false
+ end
end
diff --git a/spec/workers/gitlab_shell_worker_spec.rb b/spec/workers/gitlab_shell_worker_spec.rb
new file mode 100644
index 00000000000..6b222af454d
--- /dev/null
+++ b/spec/workers/gitlab_shell_worker_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe GitlabShellWorker do
+ let(:worker) { described_class.new }
+
+ describe '#perform with add_key' do
+ it 'calls add_key on Gitlab::Shell' do
+ expect_any_instance_of(Gitlab::Shell).to receive(:add_key).with('foo', 'bar')
+ worker.perform(:add_key, 'foo', 'bar')
+ end
+ end
+end
--
cgit v1.2.1
From d2f4e8f97da171998c2bf4a88765b29528e748b7 Mon Sep 17 00:00:00 2001
From: Paco Guzman
Date: Fri, 8 Jul 2016 07:32:15 +0200
Subject: Avoid adding index if already exists
---
db/migrate/20160301174731_add_fingerprint_index.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/db/migrate/20160301174731_add_fingerprint_index.rb b/db/migrate/20160301174731_add_fingerprint_index.rb
index b7c4f7d140a..f2c3d1ba1ea 100644
--- a/db/migrate/20160301174731_add_fingerprint_index.rb
+++ b/db/migrate/20160301174731_add_fingerprint_index.rb
@@ -4,6 +4,7 @@ class AddFingerprintIndex < ActiveRecord::Migration
DOWNTIME = false
+ # https://gitlab.com/gitlab-org/gitlab-ee/issues/764
def change
args = [:keys, :fingerprint]
@@ -11,6 +12,6 @@ class AddFingerprintIndex < ActiveRecord::Migration
args << { algorithm: :concurrently }
end
- add_index(*args)
+ add_index(*args) unless index_exists?(:keys, :fingerprint)
end
end
--
cgit v1.2.1
From 01319e5933314616077c6a23cceccdec6ab815af Mon Sep 17 00:00:00 2001
From: Sean McGivern
Date: Fri, 1 Sep 2017 16:20:49 +0100
Subject: Make Gitlab::CurrentSettings available when getting settings
---
lib/gitlab/shell.rb | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 65a9e58adf1..bbe7199c009 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -391,6 +391,14 @@ module Gitlab
File.join(gitlab_shell_path, 'bin', 'gitlab-keys')
end
+ def authorized_keys_enabled?
+ # Return true if nil to ensure the authorized_keys methods work while
+ # fixing the authorized_keys file during migration.
+ return true if Gitlab::CurrentSettings.current_application_settings.authorized_keys_enabled.nil?
+
+ Gitlab::CurrentSettings.current_application_settings.authorized_keys_enabled
+ end
+
private
def gitlab_projects(shard_path, disk_path)
@@ -468,13 +476,5 @@ module Gitlab
# need to do the same here...
raise Error, e
end
-
- def authorized_keys_enabled?
- # Return true if nil to ensure the authorized_keys methods work while
- # fixing the authorized_keys file during migration.
- return true if current_application_settings.authorized_keys_enabled.nil?
-
- current_application_settings.authorized_keys_enabled
- end
end
end
--
cgit v1.2.1
From d9557e43e4eb91eede069c045a962e417ae6e852 Mon Sep 17 00:00:00 2001
From: Valery Sizov
Date: Tue, 4 Jul 2017 19:06:18 +0300
Subject: Backport spec fixes in spec/lib/gitlab/shell_spec.rb
---
spec/lib/gitlab/shell_spec.rb | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index e452fbb757d..24fc17861dd 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -55,7 +55,7 @@ describe Gitlab::Shell do
context 'when authorized_keys_enabled is true' do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(Gitlab::Utils).to receive(:system_silent).with(
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
)
@@ -69,7 +69,7 @@ describe Gitlab::Shell do
end
it 'does nothing' do
- expect(Gitlab::Utils).not_to receive(:system_silent)
+ expect(Gitlab::Utils).not_to receive(:gitlab_shell_fast_execute)
gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
end
@@ -82,7 +82,7 @@ describe Gitlab::Shell do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(Gitlab::Utils).to receive(:system_silent).with(
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
)
@@ -135,7 +135,7 @@ describe Gitlab::Shell do
context 'when authorized_keys_enabled is true' do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(Gitlab::Utils).to receive(:system_silent).with(
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'rm-key', 'key-123', 'ssh-rsa foobar']
)
@@ -149,7 +149,7 @@ describe Gitlab::Shell do
end
it 'does nothing' do
- expect(Gitlab::Utils).not_to receive(:system_silent)
+ expect(gitlab_shell).not_to receive(:gitlab_shell_fast_execute)
gitlab_shell.remove_key('key-123', 'ssh-rsa foobar')
end
@@ -162,7 +162,7 @@ describe Gitlab::Shell do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(Gitlab::Utils).to receive(:system_silent).with(
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'rm-key', 'key-123', 'ssh-rsa foobar']
)
@@ -173,7 +173,7 @@ describe Gitlab::Shell do
context 'when key content is not given' do
it 'calls rm-key with only one argument' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(Gitlab::Utils).to receive(:system_silent).with(
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'rm-key', 'key-123']
)
@@ -186,7 +186,7 @@ describe Gitlab::Shell do
context 'when authorized_keys_enabled is true' do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(Gitlab::Utils).to receive(:system_silent).with([:gitlab_shell_keys_path, 'clear'])
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with([:gitlab_shell_keys_path, 'clear'])
gitlab_shell.remove_all_keys
end
@@ -198,7 +198,7 @@ describe Gitlab::Shell do
end
it 'does nothing' do
- expect(Gitlab::Utils).not_to receive(:system_silent)
+ expect(gitlab_shell).not_to receive(:gitlab_shell_fast_execute)
gitlab_shell.remove_all_keys
end
@@ -211,7 +211,9 @@ describe Gitlab::Shell do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(Gitlab::Utils).to receive(:system_silent).with([:gitlab_shell_keys_path, 'clear'])
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
+ [:gitlab_shell_keys_path, 'clear']
+ )
gitlab_shell.remove_all_keys
end
--
cgit v1.2.1
From 40e3d9f37b31283c5b63ae6ab161ac87e39185d3 Mon Sep 17 00:00:00 2001
From: James Edwards-Jones
Date: Mon, 8 Jan 2018 18:24:51 +0000
Subject: Fix typo in spec/requests/api/internal_spec.rb
---
spec/requests/api/internal_spec.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 7b5fddde456..2783c51b8df 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -193,7 +193,7 @@ describe API::Internal do
end
describe "GET /internal/authorized_keys" do
- context "unsing an existing key's fingerprint" do
+ context "using an existing key's fingerprint" do
it "finds the key" do
get(api('/internal/authorized_keys'), fingerprint: key.fingerprint, secret_token: secret_token)
--
cgit v1.2.1
From bd9ead683c3bade57a59d06530a1973768622a78 Mon Sep 17 00:00:00 2001
From: James Edwards-Jones
Date: Mon, 8 Jan 2018 19:43:32 +0000
Subject: Fix spec in shell_spec.rb
The spec for "#add_key does nothing" would always have passed,
since the expectation was on both the wrong object and message.
---
spec/lib/gitlab/shell_spec.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 24fc17861dd..eb90f53468f 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -69,7 +69,7 @@ describe Gitlab::Shell do
end
it 'does nothing' do
- expect(Gitlab::Utils).not_to receive(:gitlab_shell_fast_execute)
+ expect(gitlab_shell).not_to receive(:gitlab_shell_fast_execute)
gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
end
--
cgit v1.2.1
From 9edd9a5ea21a1b95ffc7b399c5c11bc9a7c4c318 Mon Sep 17 00:00:00 2001
From: James Edwards-Jones
Date: Mon, 8 Jan 2018 19:54:04 +0000
Subject: Adds changelog for backport of authorized_keys DB lookup from EE
---
changelogs/unreleased/jej-backport-authorized-keys-to-ce.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 changelogs/unreleased/jej-backport-authorized-keys-to-ce.yml
diff --git a/changelogs/unreleased/jej-backport-authorized-keys-to-ce.yml b/changelogs/unreleased/jej-backport-authorized-keys-to-ce.yml
new file mode 100644
index 00000000000..4386c631f59
--- /dev/null
+++ b/changelogs/unreleased/jej-backport-authorized-keys-to-ce.yml
@@ -0,0 +1,5 @@
+---
+title: Backport fast database lookup of SSH authorized_keys from EE
+merge_request: 16014
+author:
+type: added
--
cgit v1.2.1
From 7e3405d76cbd683ea557835c4cd96af9bda9cf4c Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Mon, 8 Jan 2018 20:45:34 +0000
Subject: Fix last eslint rules
---
.eslintrc | 3 +-
app/assets/javascripts/commit/image_file.js | 194 +++++++++++----------
.../javascripts/groups/components/item_actions.vue | 90 +++++-----
.../javascripts/notebook/cells/output/index.vue | 25 +--
.../javascripts/notes/components/comment_form.vue | 3 +-
.../javascripts/vue_shared/components/modal.vue | 2 +-
.../javascripts/vue_shared/components/pikaday.vue | 3 +
.../sidebar/collapsed_grouped_date_picker.vue | 2 +
.../vue_shared/components/sidebar/date_picker.vue | 3 +
9 files changed, 169 insertions(+), 156 deletions(-)
diff --git a/.eslintrc b/.eslintrc
index 6dbe269e594..d9161e97747 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -16,7 +16,8 @@
"localStorage": false
},
"parserOptions": {
- "parser": "babel-eslint"
+ "parser": "babel-eslint",
+ "ecmaVersion": 2017
},
"plugins": [
"filenames",
diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js
index b6a0ece7907..18edd8755c3 100644
--- a/app/assets/javascripts/commit/image_file.js
+++ b/app/assets/javascripts/commit/image_file.js
@@ -94,102 +94,104 @@ export default class ImageFile {
});
return [maxWidth, maxHeight];
}
-
- views = {
- 'two-up': function() {
- return $('.two-up.view .wrap', this.file).each((function(_this) {
- return function(index, wrap) {
- $('img', wrap).each(function() {
- var currentWidth;
- currentWidth = $(this).width();
- if (currentWidth > availWidth / 2) {
- return $(this).width(availWidth / 2);
- }
- });
- return _this.requestImageInfo($('img', wrap), function(width, height) {
- $('.image-info .meta-width', wrap).text(width + "px");
- $('.image-info .meta-height', wrap).text(height + "px");
- return $('.image-info', wrap).removeClass('hide');
- });
- };
- })(this));
- },
- 'swipe': function() {
- var maxHeight, maxWidth;
- maxWidth = 0;
- maxHeight = 0;
- return $('.swipe.view', this.file).each((function(_this) {
- return function(index, view) {
- var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref;
- ref = _this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1];
- $swipeFrame = $('.swipe-frame', view);
- $swipeWrap = $('.swipe-wrap', view);
- $swipeBar = $('.swipe-bar', view);
-
- $swipeFrame.css({
- width: maxWidth + 16,
- height: maxHeight + 28
- });
- $swipeWrap.css({
- width: maxWidth + 1,
- height: maxHeight + 2
- });
- // Set swipeBar left position to match image frame
- $swipeBar.css({
- left: 1
- });
-
- wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
-
- _this.initDraggable($swipeBar, wrapPadding, function(e, left) {
- if (left > 0 && left < $swipeFrame.width() - (wrapPadding * 2)) {
- $swipeWrap.width((maxWidth + 1) - left);
- $swipeBar.css('left', left);
- }
- });
- };
- })(this));
- },
- 'onion-skin': function() {
- var dragTrackWidth, maxHeight, maxWidth;
- maxWidth = 0;
- maxHeight = 0;
- dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width();
- return $('.onion-skin.view', this.file).each((function(_this) {
- return function(index, view) {
- var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false;
- ref = _this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1];
- $frame = $('.onion-skin-frame', view);
- $frameAdded = $('.frame.added', view);
- $track = $('.drag-track', view);
- $dragger = $('.dragger', $track);
-
- $frame.css({
- width: maxWidth + 16,
- height: maxHeight + 28
- });
- $('.swipe-wrap', view).css({
- width: maxWidth + 1,
- height: maxHeight + 2
- });
- $dragger.css({
- left: dragTrackWidth
- });
-
- $frameAdded.css('opacity', 1);
- framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10);
-
- _this.initDraggable($dragger, framePadding, function(e, left) {
- var opacity = left / dragTrackWidth;
-
- if (opacity >= 0 && opacity <= 1) {
- $dragger.css('left', left);
- $frameAdded.css('opacity', opacity);
- }
- });
- };
- })(this));
- }
+ // eslint-disable-next-line class-methods-use-this
+ views() {
+ return {
+ 'two-up': function() {
+ return $('.two-up.view .wrap', this.file).each((function(_this) {
+ return function(index, wrap) {
+ $('img', wrap).each(function() {
+ var currentWidth;
+ currentWidth = $(this).width();
+ if (currentWidth > availWidth / 2) {
+ return $(this).width(availWidth / 2);
+ }
+ });
+ return _this.requestImageInfo($('img', wrap), function(width, height) {
+ $('.image-info .meta-width', wrap).text(width + "px");
+ $('.image-info .meta-height', wrap).text(height + "px");
+ return $('.image-info', wrap).removeClass('hide');
+ });
+ };
+ })(this));
+ },
+ 'swipe': function() {
+ var maxHeight, maxWidth;
+ maxWidth = 0;
+ maxHeight = 0;
+ return $('.swipe.view', this.file).each((function(_this) {
+ return function(index, view) {
+ var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref;
+ ref = _this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1];
+ $swipeFrame = $('.swipe-frame', view);
+ $swipeWrap = $('.swipe-wrap', view);
+ $swipeBar = $('.swipe-bar', view);
+
+ $swipeFrame.css({
+ width: maxWidth + 16,
+ height: maxHeight + 28
+ });
+ $swipeWrap.css({
+ width: maxWidth + 1,
+ height: maxHeight + 2
+ });
+ // Set swipeBar left position to match image frame
+ $swipeBar.css({
+ left: 1
+ });
+
+ wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
+
+ _this.initDraggable($swipeBar, wrapPadding, function(e, left) {
+ if (left > 0 && left < $swipeFrame.width() - (wrapPadding * 2)) {
+ $swipeWrap.width((maxWidth + 1) - left);
+ $swipeBar.css('left', left);
+ }
+ });
+ };
+ })(this));
+ },
+ 'onion-skin': function() {
+ var dragTrackWidth, maxHeight, maxWidth;
+ maxWidth = 0;
+ maxHeight = 0;
+ dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width();
+ return $('.onion-skin.view', this.file).each((function(_this) {
+ return function(index, view) {
+ var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false;
+ ref = _this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1];
+ $frame = $('.onion-skin-frame', view);
+ $frameAdded = $('.frame.added', view);
+ $track = $('.drag-track', view);
+ $dragger = $('.dragger', $track);
+
+ $frame.css({
+ width: maxWidth + 16,
+ height: maxHeight + 28
+ });
+ $('.swipe-wrap', view).css({
+ width: maxWidth + 1,
+ height: maxHeight + 2
+ });
+ $dragger.css({
+ left: dragTrackWidth
+ });
+
+ $frameAdded.css('opacity', 1);
+ framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10);
+
+ _this.initDraggable($dragger, framePadding, function(e, left) {
+ var opacity = left / dragTrackWidth;
+
+ if (opacity >= 0 && opacity <= 1) {
+ $dragger.css('left', left);
+ $frameAdded.css('opacity', opacity);
+ }
+ });
+ };
+ })(this));
+ }
+ };
}
requestImageInfo(img, callback) {
diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue
index 0dd0783ce06..1bde6ae5185 100644
--- a/app/assets/javascripts/groups/components/item_actions.vue
+++ b/app/assets/javascripts/groups/components/item_actions.vue
@@ -1,56 +1,56 @@
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index 5bde30799b0..91b2269a83a 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -26,30 +26,18 @@
default: () => ({}),
},
},
- data() {
- return {
- outputType: '',
- };
- },
computed: {
componentName() {
if (this.output.text) {
return 'code-cell';
} else if (this.output.data['image/png']) {
- this.outputType = 'image/png';
-
return 'image-output';
} else if (this.output.data['text/html']) {
- this.outputType = 'text/html';
-
return 'html-output';
} else if (this.output.data['image/svg+xml']) {
- this.outputType = 'image/svg+xml';
-
return 'html-output';
}
- this.outputType = 'text/plain';
return 'code-cell';
},
rawCode() {
@@ -59,6 +47,19 @@
return this.dataForType(this.outputType);
},
+ outputType() {
+ if (this.output.text) {
+ return '';
+ } else if (this.output.data['image/png']) {
+ return 'image/png';
+ } else if (this.output.data['text/html']) {
+ return 'text/html';
+ } else if (this.output.data['image/svg+xml']) {
+ return 'image/svg+xml';
+ }
+
+ return 'text/plain';
+ },
},
methods: {
dataForType(type) {
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 8ffa6adc4af..1f18c196137 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -305,7 +305,8 @@ js-gfm-input js-autosize markdown-area js-vue-textarea"
-
-
{{ this.text }}
+
{{ text }}
Date: Mon, 8 Jan 2018 17:33:51 -0200
Subject: Add rake task to check integrity of uploaded files
---
lib/tasks/gitlab/uploads.rake | 44 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
create mode 100644 lib/tasks/gitlab/uploads.rake
diff --git a/lib/tasks/gitlab/uploads.rake b/lib/tasks/gitlab/uploads.rake
new file mode 100644
index 00000000000..fd5ef78103b
--- /dev/null
+++ b/lib/tasks/gitlab/uploads.rake
@@ -0,0 +1,44 @@
+namespace :gitlab do
+ namespace :uploads do
+ desc 'GitLab | Uploads | Check integrity of uploaded files'
+ task check: :environment do
+ puts 'Starting checking integrity of uploaded files'
+
+ uploads_batches do |batch|
+ batch.each do |upload|
+ puts "- Checking file (#{upload.id}): #{upload.absolute_path}".color(:green)
+
+ if upload.exist?
+ check_checksum(upload)
+ else
+ puts " * File does not exist on the file system".color(:red)
+ end
+ end
+ end
+
+ puts 'Done!'
+ end
+
+ def batch_size
+ ENV.fetch('BATCH', 200).to_i
+ end
+
+ def calculate_checksum(absolute_path)
+ Digest::SHA256.file(absolute_path).hexdigest
+ end
+
+ def check_checksum(upload)
+ checksum = calculate_checksum(upload.absolute_path)
+
+ if checksum != upload.checksum
+ puts " * File checksum (#{checksum}) does not match the one in the database (#{upload.checksum})".color(:red)
+ end
+ end
+
+ def uploads_batches(&block)
+ Upload.all.in_batches(of: batch_size, start: ENV['ID_FROM'], finish: ENV['ID_TO']) do |relation| # rubocop: disable Cop/InBatches
+ yield relation
+ end
+ end
+ end
+end
--
cgit v1.2.1
From 4b1546159c29ef46f106bb1393a542187b950c4e Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Mon, 8 Jan 2018 18:29:33 -0200
Subject: Add spec for gitlab:uploads rake tasks
---
spec/tasks/gitlab/uploads_rake_spec.rb | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 spec/tasks/gitlab/uploads_rake_spec.rb
diff --git a/spec/tasks/gitlab/uploads_rake_spec.rb b/spec/tasks/gitlab/uploads_rake_spec.rb
new file mode 100644
index 00000000000..9330539f8c9
--- /dev/null
+++ b/spec/tasks/gitlab/uploads_rake_spec.rb
@@ -0,0 +1,28 @@
+require 'rake_helper'
+
+describe 'gitlab:uploads rake tasks' do
+ describe 'check' do
+ before do
+ Rake.application.rake_require 'tasks/gitlab/uploads'
+ end
+
+ it 'outputs the integrity check for each uploaded file' do
+ uploaded_file = create(:upload)
+
+ expect { run_rake_task('gitlab:uploads:check') }.to output(/Checking file \(#{uploaded_file.id}\): #{Regexp.quote(uploaded_file.absolute_path)}/).to_stdout
+ end
+
+ it 'errors out about missing files on the file system' do
+ uploaded_file = create(:upload)
+
+ expect { run_rake_task('gitlab:uploads:check') }.to output(/File does not exist on the file system/).to_stdout
+ end
+
+ it 'errors out about invalid checksum' do
+ uploaded_file = create(:upload, path: Rails.root.join('spec/fixtures/banana_sample.gif'))
+ uploaded_file.update_column(:checksum, '01a3156db2cf4f67ec823680b40b7302f89ab39179124ad219f94919b8a1769e')
+
+ expect { run_rake_task('gitlab:uploads:check') }.to output(/File checksum \(9e697aa09fe196909813ee36103e34f721fe47a5fdc8aac0e4e4ac47b9b38282\) does not match the one in the database \(#{uploaded_file.checksum}\)/).to_stdout
+ end
+ end
+end
--
cgit v1.2.1
From 17c44f2bd836c7dc5e28c3bac1f24f8b90c27a8b Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Mon, 8 Jan 2018 18:59:02 -0200
Subject: Add CHANGELOG
---
changelogs/unreleased/da-verify-integrity-of-uploaded-files.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 changelogs/unreleased/da-verify-integrity-of-uploaded-files.yml
diff --git a/changelogs/unreleased/da-verify-integrity-of-uploaded-files.yml b/changelogs/unreleased/da-verify-integrity-of-uploaded-files.yml
new file mode 100644
index 00000000000..5b850c92d17
--- /dev/null
+++ b/changelogs/unreleased/da-verify-integrity-of-uploaded-files.yml
@@ -0,0 +1,5 @@
+---
+title: Add rake task to check integrity of uploaded files
+merge_request:
+author:
+type: added
--
cgit v1.2.1
From e1008da2a81a1c77c63b4f28ea8cb2aa498bc372 Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Mon, 8 Jan 2018 19:22:17 -0200
Subject: Add docs for the gitlab:uploads:check rake task
---
doc/administration/raketasks/check.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index c39cb49b1c6..7e452ae503d 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -76,6 +76,26 @@ Example output:
![gitlab:user:check_repos output](../img/raketasks/check_repos_output.png)
+## Uploaded Files Integrity
+
+The uploads check Rake task will loop through all uploads in the database
+and runs two checks to determine the integrity of each file:
+
+1. Check if the file exist in the file system.
+1. Check if the checksum of the file in the file system matches the checksum in the database.
+
+**Omnibus Installation**
+
+```
+sudo gitlab-rake gitlab:uploads:check
+```
+
+**Source Installation**
+
+```bash
+sudo -u git -H bundle exec rake gitlab:uploads:check RAILS_ENV=production
+```
+
## LDAP Check
The LDAP check Rake task will test the bind_dn and password credentials
--
cgit v1.2.1
From 45ec26536e96a0d663e7c6b2332a3671fcec1c69 Mon Sep 17 00:00:00 2001
From: Jacob Schatz
Date: Mon, 8 Jan 2018 16:27:32 -0500
Subject: Refactor `explore:*`
---
app/assets/javascripts/dispatcher.js | 751 +++++++++++----------
.../javascripts/pages/explore/groups/index.js | 14 +
.../javascripts/pages/explore/projects/index.js | 5 +
3 files changed, 428 insertions(+), 342 deletions(-)
create mode 100644 app/assets/javascripts/pages/explore/groups/index.js
create mode 100644 app/assets/javascripts/pages/explore/projects/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 42f61d33f6e..87e225a88a0 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -1,97 +1,95 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
-import { s__ } from './locale';
-import projectSelect from './project_select';
-import IssuableIndex from './issuable_index';
-import Milestone from './milestone';
-import IssuableForm from './issuable_form';
-import LabelsSelect from './labels_select';
-import MilestoneSelect from './milestone_select';
-import NewBranchForm from './new_branch_form';
-import NotificationsForm from './notifications_form';
-import notificationsDropdown from './notifications_dropdown';
-import groupAvatar from './group_avatar';
-import GroupLabelSubscription from './group_label_subscription';
-import LineHighlighter from './line_highlighter';
-import BuildArtifacts from './build_artifacts';
-import CILintEditor from './ci_lint_editor';
-import groupsSelect from './groups_select';
-import Search from './search';
-import initAdmin from './admin';
-import NamespaceSelect from './namespace_select';
-import NewCommitForm from './new_commit_form';
-import Project from './project';
-import projectAvatar from './project_avatar';
-import MergeRequest from './merge_request';
-import Compare from './compare';
-import initCompareAutocomplete from './compare_autocomplete';
-import ProjectFindFile from './project_find_file';
-import ProjectNew from './project_new';
-import projectImport from './project_import';
-import Labels from './labels';
-import LabelManager from './label_manager';
-import Sidebar from './right_sidebar';
-import IssuableTemplateSelectors from './templates/issuable_template_selectors';
-import Flash from './flash';
-import CommitsList from './commits';
-import Issue from './issue';
-import BindInOut from './behaviors/bind_in_out';
-import SecretValues from './behaviors/secret_values';
-import DeleteModal from './branches/branches_delete_modal';
-import Group from './group';
-import GroupsList from './groups_list';
-import ProjectsList from './projects_list';
-import setupProjectEdit from './project_edit';
-import MiniPipelineGraph from './mini_pipeline_graph_dropdown';
-import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater';
-import Landing from './landing';
-import BlobForkSuggestion from './blob/blob_fork_suggestion';
-import UserCallout from './user_callout';
-import ShortcutsWiki from './shortcuts_wiki';
-import Pipelines from './pipelines';
-import BlobViewer from './blob/viewer/index';
-import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
-import UsersSelect from './users_select';
-import RefSelectDropdown from './ref_select_dropdown';
-import GfmAutoComplete from './gfm_auto_complete';
-import ShortcutsBlob from './shortcuts_blob';
-import SigninTabsMemoizer from './signin_tabs_memoizer';
-import Star from './star';
-import Todos from './todos';
-import TreeView from './tree';
-import UsagePing from './usage_ping';
-import UsernameValidator from './username_validator';
-import VersionCheckImage from './version_check_image';
-import Wikis from './wikis';
-import ZenMode from './zen_mode';
-import initSettingsPanels from './settings_panels';
-import initExperimentalFlags from './experimental_flags';
-import OAuthRememberMe from './oauth_remember_me';
-import PerformanceBar from './performance_bar';
-import initBroadcastMessagesForm from './broadcast_message';
-import initNotes from './init_notes';
-import initLegacyFilters from './init_legacy_filters';
-import initIssuableSidebar from './init_issuable_sidebar';
-import initProjectVisibilitySelector from './project_visibility';
-import GpgBadges from './gpg_badges';
-import initChangesDropdown from './init_changes_dropdown';
-import NewGroupChild from './groups/new_group_child';
-import AbuseReports from './abuse_reports';
-import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
-import AjaxLoadingSpinner from './ajax_loading_spinner';
-import GlFieldErrors from './gl_field_errors';
-import GLForm from './gl_form';
-import Shortcuts from './shortcuts';
-import ShortcutsNavigation from './shortcuts_navigation';
-import ShortcutsFindFile from './shortcuts_find_file';
-import ShortcutsIssuable from './shortcuts_issuable';
-import U2FAuthenticate from './u2f/authenticate';
-import Members from './members';
-import memberExpirationDate from './member_expiration_date';
-import DueDateSelectors from './due_date_select';
-import Diff from './diff';
-import ProjectLabelSubscription from './project_label_subscription';
-import SearchAutocomplete from './search_autocomplete';
-import Activities from './activities';
+import { s__ } from "./locale";
+import projectSelect from "./project_select";
+import IssuableIndex from "./issuable_index";
+import Milestone from "./milestone";
+import IssuableForm from "./issuable_form";
+import LabelsSelect from "./labels_select";
+import MilestoneSelect from "./milestone_select";
+import NewBranchForm from "./new_branch_form";
+import NotificationsForm from "./notifications_form";
+import notificationsDropdown from "./notifications_dropdown";
+import groupAvatar from "./group_avatar";
+import GroupLabelSubscription from "./group_label_subscription";
+import LineHighlighter from "./line_highlighter";
+import BuildArtifacts from "./build_artifacts";
+import CILintEditor from "./ci_lint_editor";
+import groupsSelect from "./groups_select";
+import Search from "./search";
+import initAdmin from "./admin";
+import NamespaceSelect from "./namespace_select";
+import NewCommitForm from "./new_commit_form";
+import Project from "./project";
+import projectAvatar from "./project_avatar";
+import MergeRequest from "./merge_request";
+import Compare from "./compare";
+import initCompareAutocomplete from "./compare_autocomplete";
+import ProjectFindFile from "./project_find_file";
+import ProjectNew from "./project_new";
+import projectImport from "./project_import";
+import Labels from "./labels";
+import LabelManager from "./label_manager";
+import Sidebar from "./right_sidebar";
+import IssuableTemplateSelectors from "./templates/issuable_template_selectors";
+import Flash from "./flash";
+import CommitsList from "./commits";
+import Issue from "./issue";
+import BindInOut from "./behaviors/bind_in_out";
+import SecretValues from "./behaviors/secret_values";
+import DeleteModal from "./branches/branches_delete_modal";
+import Group from "./group";
+import ProjectsList from "./projects_list";
+import setupProjectEdit from "./project_edit";
+import MiniPipelineGraph from "./mini_pipeline_graph_dropdown";
+import BlobLinePermalinkUpdater from "./blob/blob_line_permalink_updater";
+import BlobForkSuggestion from "./blob/blob_fork_suggestion";
+import UserCallout from "./user_callout";
+import ShortcutsWiki from "./shortcuts_wiki";
+import Pipelines from "./pipelines";
+import BlobViewer from "./blob/viewer/index";
+import AutoWidthDropdownSelect from "./issuable/auto_width_dropdown_select";
+import UsersSelect from "./users_select";
+import RefSelectDropdown from "./ref_select_dropdown";
+import GfmAutoComplete from "./gfm_auto_complete";
+import ShortcutsBlob from "./shortcuts_blob";
+import SigninTabsMemoizer from "./signin_tabs_memoizer";
+import Star from "./star";
+import Todos from "./todos";
+import TreeView from "./tree";
+import UsagePing from "./usage_ping";
+import UsernameValidator from "./username_validator";
+import VersionCheckImage from "./version_check_image";
+import Wikis from "./wikis";
+import ZenMode from "./zen_mode";
+import initSettingsPanels from "./settings_panels";
+import initExperimentalFlags from "./experimental_flags";
+import OAuthRememberMe from "./oauth_remember_me";
+import PerformanceBar from "./performance_bar";
+import initBroadcastMessagesForm from "./broadcast_message";
+import initNotes from "./init_notes";
+import initLegacyFilters from "./init_legacy_filters";
+import initIssuableSidebar from "./init_issuable_sidebar";
+import initProjectVisibilitySelector from "./project_visibility";
+import GpgBadges from "./gpg_badges";
+import initChangesDropdown from "./init_changes_dropdown";
+import NewGroupChild from "./groups/new_group_child";
+import AbuseReports from "./abuse_reports";
+import { ajaxGet, convertPermissionToBoolean } from "./lib/utils/common_utils";
+import AjaxLoadingSpinner from "./ajax_loading_spinner";
+import GlFieldErrors from "./gl_field_errors";
+import GLForm from "./gl_form";
+import Shortcuts from "./shortcuts";
+import ShortcutsNavigation from "./shortcuts_navigation";
+import ShortcutsFindFile from "./shortcuts_find_file";
+import ShortcutsIssuable from "./shortcuts_issuable";
+import U2FAuthenticate from "./u2f/authenticate";
+import Members from "./members";
+import memberExpirationDate from "./member_expiration_date";
+import DueDateSelectors from "./due_date_select";
+import Diff from "./diff";
+import ProjectLabelSubscription from "./project_label_subscription";
+import SearchAutocomplete from "./search_autocomplete";
+import Activities from "./activities";
(function() {
var Dispatcher;
@@ -104,27 +102,34 @@ import Activities from './activities';
}
Dispatcher.prototype.initPageScripts = function() {
- var path, shortcut_handler, fileBlobPermalinkUrlElement, fileBlobPermalinkUrl;
- const page = $('body').attr('data-page');
+ var path,
+ shortcut_handler,
+ fileBlobPermalinkUrlElement,
+ fileBlobPermalinkUrl;
+ const page = $("body").attr("data-page");
if (!page) {
return false;
}
- const fail = () => Flash('Error loading dynamic module');
+ const fail = () => Flash("Error loading dynamic module");
- path = page.split(':');
+ path = page.split(":");
shortcut_handler = null;
- $('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
- const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
- const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
+ $(".js-gfm-input:not(.js-vue-textarea)").each((i, el) => {
+ const gfm = new GfmAutoComplete(
+ gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources
+ );
+ const enableGFM = convertPermissionToBoolean(
+ el.dataset.supportsAutocomplete
+ );
gfm.setup($(el), {
emojis: true,
members: enableGFM,
issues: enableGFM,
milestones: enableGFM,
mergeRequests: enableGFM,
- labels: enableGFM,
+ labels: enableGFM
});
});
@@ -132,287 +137,335 @@ import Activities from './activities';
new LineHighlighter();
new BlobLinePermalinkUpdater(
- document.querySelector('#blob-content-holder'),
- '.diff-line-num[data-line-number]',
- document.querySelectorAll('.js-data-file-blob-permalink-url, .js-blob-blame-link'),
+ document.querySelector("#blob-content-holder"),
+ ".diff-line-num[data-line-number]",
+ document.querySelectorAll(
+ ".js-data-file-blob-permalink-url, .js-blob-blame-link"
+ )
);
shortcut_handler = new ShortcutsNavigation();
- fileBlobPermalinkUrlElement = document.querySelector('.js-data-file-blob-permalink-url');
- fileBlobPermalinkUrl = fileBlobPermalinkUrlElement && fileBlobPermalinkUrlElement.getAttribute('href');
+ fileBlobPermalinkUrlElement = document.querySelector(
+ ".js-data-file-blob-permalink-url"
+ );
+ fileBlobPermalinkUrl =
+ fileBlobPermalinkUrlElement &&
+ fileBlobPermalinkUrlElement.getAttribute("href");
new ShortcutsBlob({
skipResetBindings: true,
- fileBlobPermalinkUrl,
+ fileBlobPermalinkUrl
});
new BlobForkSuggestion({
- openButtons: document.querySelectorAll('.js-edit-blob-link-fork-toggler'),
- forkButtons: document.querySelectorAll('.js-fork-suggestion-button'),
- cancelButtons: document.querySelectorAll('.js-cancel-fork-suggestion-button'),
- suggestionSections: document.querySelectorAll('.js-file-fork-suggestion-section'),
- actionTextPieces: document.querySelectorAll('.js-file-fork-suggestion-section-action'),
- })
- .init();
+ openButtons: document.querySelectorAll(
+ ".js-edit-blob-link-fork-toggler"
+ ),
+ forkButtons: document.querySelectorAll(".js-fork-suggestion-button"),
+ cancelButtons: document.querySelectorAll(
+ ".js-cancel-fork-suggestion-button"
+ ),
+ suggestionSections: document.querySelectorAll(
+ ".js-file-fork-suggestion-section"
+ ),
+ actionTextPieces: document.querySelectorAll(
+ ".js-file-fork-suggestion-section-action"
+ )
+ }).init();
}
- const filteredSearchEnabled = gl.FilteredSearchManager && document.querySelector('.filtered-search');
+ const filteredSearchEnabled =
+ gl.FilteredSearchManager && document.querySelector(".filtered-search");
switch (page) {
- case 'profiles:preferences:show':
+ case "profiles:preferences:show":
initExperimentalFlags();
break;
- case 'sessions:new':
+ case "sessions:new":
new UsernameValidator();
new SigninTabsMemoizer();
- new OAuthRememberMe({ container: $(".omniauth-container") }).bindEvents();
+ new OAuthRememberMe({
+ container: $(".omniauth-container")
+ }).bindEvents();
break;
- case 'projects:boards:show':
- case 'projects:boards:index':
+ case "projects:boards:show":
+ case "projects:boards:index":
shortcut_handler = new ShortcutsNavigation();
new UsersSelect();
break;
- case 'projects:merge_requests:index':
- case 'projects:issues:index':
+ case "projects:merge_requests:index":
+ case "projects:issues:index":
if (filteredSearchEnabled) {
- const filteredSearchManager = new gl.FilteredSearchManager(page === 'projects:issues:index' ? 'issues' : 'merge_requests');
+ const filteredSearchManager = new gl.FilteredSearchManager(
+ page === "projects:issues:index" ? "issues" : "merge_requests"
+ );
filteredSearchManager.setup();
}
- const pagePrefix = page === 'projects:merge_requests:index' ? 'merge_request_' : 'issue_';
+ const pagePrefix =
+ page === "projects:merge_requests:index"
+ ? "merge_request_"
+ : "issue_";
new IssuableIndex(pagePrefix);
shortcut_handler = new ShortcutsNavigation();
new UsersSelect();
break;
- case 'projects:issues:show':
+ case "projects:issues:show":
new Issue();
shortcut_handler = new ShortcutsIssuable();
new ZenMode();
initIssuableSidebar();
break;
- case 'dashboard:milestones:index':
+ case "dashboard:milestones:index":
projectSelect();
break;
- case 'projects:milestones:show':
- case 'groups:milestones:show':
- case 'dashboard:milestones:show':
+ case "projects:milestones:show":
+ case "groups:milestones:show":
+ case "dashboard:milestones:show":
new Milestone();
new Sidebar();
break;
- case 'dashboard:issues':
- case 'dashboard:merge_requests':
+ case "dashboard:issues":
+ case "dashboard:merge_requests":
projectSelect();
initLegacyFilters();
break;
- case 'groups:issues':
- case 'groups:merge_requests':
+ case "groups:issues":
+ case "groups:merge_requests":
if (filteredSearchEnabled) {
- const filteredSearchManager = new gl.FilteredSearchManager(page === 'groups:issues' ? 'issues' : 'merge_requests');
+ const filteredSearchManager = new gl.FilteredSearchManager(
+ page === "groups:issues" ? "issues" : "merge_requests"
+ );
filteredSearchManager.setup();
}
projectSelect();
break;
- case 'dashboard:todos:index':
+ case "dashboard:todos:index":
new Todos();
break;
- case 'dashboard:projects:index':
- case 'dashboard:projects:starred':
- case 'explore:projects:index':
- case 'explore:projects:trending':
- case 'explore:projects:starred':
- case 'admin:projects:index':
+ case "explore:projects:index":
+ case "explore:projects:trending":
+ case "explore:projects:starred":
+ import("./pages/explore/projects")
+ .then(module => module.default())
+ .catch(fail);
+ break;
+ case "dashboard:projects:index":
+ case "dashboard:projects:starred":
+ case "admin:projects:index":
new ProjectsList();
break;
- case 'explore:groups:index':
- new GroupsList();
- const landingElement = document.querySelector('.js-explore-groups-landing');
- if (!landingElement) break;
- const exploreGroupsLanding = new Landing(
- landingElement,
- landingElement.querySelector('.dismiss-button'),
- 'explore_groups_landing_dismissed',
- );
- exploreGroupsLanding.toggle();
+ case "explore:groups:index":
+ import("./pages/explore/groups")
+ .then(module => module.default())
+ .catch(fail);
break;
- case 'projects:milestones:new':
- case 'projects:milestones:edit':
- case 'projects:milestones:update':
+ case "projects:milestones:new":
+ case "projects:milestones:edit":
+ case "projects:milestones:update":
new ZenMode();
new DueDateSelectors();
- new GLForm($('.milestone-form'), true);
+ new GLForm($(".milestone-form"), true);
break;
- case 'groups:milestones:new':
- case 'groups:milestones:edit':
- case 'groups:milestones:update':
+ case "groups:milestones:new":
+ case "groups:milestones:edit":
+ case "groups:milestones:update":
new ZenMode();
new DueDateSelectors();
- new GLForm($('.milestone-form'), false);
+ new GLForm($(".milestone-form"), false);
break;
- case 'projects:compare:show':
+ case "projects:compare:show":
new Diff();
const paddingTop = 16;
- initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - paddingTop);
+ initChangesDropdown(
+ document.querySelector(".navbar-gitlab").offsetHeight - paddingTop
+ );
break;
- case 'projects:branches:new':
- case 'projects:branches:create':
- new NewBranchForm($('.js-create-branch-form'), JSON.parse(document.getElementById('availableRefs').innerHTML));
+ case "projects:branches:new":
+ case "projects:branches:create":
+ new NewBranchForm(
+ $(".js-create-branch-form"),
+ JSON.parse(document.getElementById("availableRefs").innerHTML)
+ );
break;
- case 'projects:branches:index':
+ case "projects:branches:index":
AjaxLoadingSpinner.init();
new DeleteModal();
break;
- case 'projects:issues:new':
- case 'projects:issues:edit':
+ case "projects:issues:new":
+ case "projects:issues:edit":
shortcut_handler = new ShortcutsNavigation();
- new GLForm($('.issue-form'), true);
- new IssuableForm($('.issue-form'));
+ new GLForm($(".issue-form"), true);
+ new IssuableForm($(".issue-form"));
new LabelsSelect();
new MilestoneSelect();
new IssuableTemplateSelectors();
break;
- case 'projects:merge_requests:creations:new':
- const mrNewCompareNode = document.querySelector('.js-merge-request-new-compare');
+ case "projects:merge_requests:creations:new":
+ const mrNewCompareNode = document.querySelector(
+ ".js-merge-request-new-compare"
+ );
if (mrNewCompareNode) {
new Compare({
targetProjectUrl: mrNewCompareNode.dataset.targetProjectUrl,
sourceBranchUrl: mrNewCompareNode.dataset.sourceBranchUrl,
- targetBranchUrl: mrNewCompareNode.dataset.targetBranchUrl,
+ targetBranchUrl: mrNewCompareNode.dataset.targetBranchUrl
});
} else {
- const mrNewSubmitNode = document.querySelector('.js-merge-request-new-submit');
+ const mrNewSubmitNode = document.querySelector(
+ ".js-merge-request-new-submit"
+ );
new MergeRequest({
- action: mrNewSubmitNode.dataset.mrSubmitAction,
+ action: mrNewSubmitNode.dataset.mrSubmitAction
});
}
- case 'projects:merge_requests:creations:diffs':
- case 'projects:merge_requests:edit':
+ case "projects:merge_requests:creations:diffs":
+ case "projects:merge_requests:edit":
new Diff();
shortcut_handler = new ShortcutsNavigation();
- new GLForm($('.merge-request-form'), true);
- new IssuableForm($('.merge-request-form'));
+ new GLForm($(".merge-request-form"), true);
+ new IssuableForm($(".merge-request-form"));
new LabelsSelect();
new MilestoneSelect();
new IssuableTemplateSelectors();
- new AutoWidthDropdownSelect($('.js-target-branch-select')).init();
+ new AutoWidthDropdownSelect($(".js-target-branch-select")).init();
break;
- case 'projects:tags:new':
+ case "projects:tags:new":
new ZenMode();
- new GLForm($('.tag-form'), true);
- new RefSelectDropdown($('.js-branch-select'));
+ new GLForm($(".tag-form"), true);
+ new RefSelectDropdown($(".js-branch-select"));
break;
- case 'projects:snippets:show':
+ case "projects:snippets:show":
initNotes();
new ZenMode();
break;
- case 'projects:snippets:new':
- case 'projects:snippets:edit':
- case 'projects:snippets:create':
- case 'projects:snippets:update':
- new GLForm($('.snippet-form'), true);
+ case "projects:snippets:new":
+ case "projects:snippets:edit":
+ case "projects:snippets:create":
+ case "projects:snippets:update":
+ new GLForm($(".snippet-form"), true);
new ZenMode();
break;
- case 'snippets:new':
- case 'snippets:edit':
- case 'snippets:create':
- case 'snippets:update':
- new GLForm($('.snippet-form'), false);
+ case "snippets:new":
+ case "snippets:edit":
+ case "snippets:create":
+ case "snippets:update":
+ new GLForm($(".snippet-form"), false);
new ZenMode();
break;
- case 'projects:releases:edit':
+ case "projects:releases:edit":
new ZenMode();
- new GLForm($('.release-form'), true);
+ new GLForm($(".release-form"), true);
break;
- case 'projects:merge_requests:show':
+ case "projects:merge_requests:show":
new Diff();
new ZenMode();
initIssuableSidebar();
initNotes();
- const mrShowNode = document.querySelector('.merge-request');
+ const mrShowNode = document.querySelector(".merge-request");
window.mergeRequest = new MergeRequest({
- action: mrShowNode.dataset.mrAction,
+ action: mrShowNode.dataset.mrAction
});
shortcut_handler = new ShortcutsIssuable(true);
break;
- case 'dashboard:activity':
+ case "dashboard:activity":
new Activities();
break;
- case 'projects:commit:show':
+ case "projects:commit:show":
new Diff();
new ZenMode();
shortcut_handler = new ShortcutsNavigation();
new MiniPipelineGraph({
- container: '.js-commit-pipeline-graph',
+ container: ".js-commit-pipeline-graph"
}).bindEvents();
initNotes();
const stickyBarPaddingTop = 16;
- initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - stickyBarPaddingTop);
- $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
+ initChangesDropdown(
+ document.querySelector(".navbar-gitlab").offsetHeight -
+ stickyBarPaddingTop
+ );
+ $(".commit-info.branches").load(
+ document.querySelector(".js-commit-box").dataset.commitPath
+ );
break;
- case 'projects:commit:pipelines':
+ case "projects:commit:pipelines":
new MiniPipelineGraph({
- container: '.js-commit-pipeline-graph',
+ container: ".js-commit-pipeline-graph"
}).bindEvents();
- $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
+ $(".commit-info.branches").load(
+ document.querySelector(".js-commit-box").dataset.commitPath
+ );
break;
- case 'projects:activity':
+ case "projects:activity":
new Activities();
shortcut_handler = new ShortcutsNavigation();
break;
- case 'projects:commits:show':
- CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
+ case "projects:commits:show":
+ CommitsList.init(
+ document.querySelector(".js-project-commits-show").dataset
+ .commitsLimit
+ );
shortcut_handler = new ShortcutsNavigation();
GpgBadges.fetch();
break;
- case 'projects:show':
+ case "projects:show":
shortcut_handler = new ShortcutsNavigation();
new NotificationsForm();
new UserCallout({
setCalloutPerProject: true,
- className: 'js-autodevops-banner',
+ className: "js-autodevops-banner"
});
- if ($('#tree-slider').length) new TreeView();
- if ($('.blob-viewer').length) new BlobViewer();
- if ($('.project-show-activity').length) new Activities();
- $('#tree-slider').waitForImages(function() {
- ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
+ if ($("#tree-slider").length) new TreeView();
+ if ($(".blob-viewer").length) new BlobViewer();
+ if ($(".project-show-activity").length) new Activities();
+ $("#tree-slider").waitForImages(function() {
+ ajaxGet(
+ document.querySelector(".js-tree-content").dataset.logsPath
+ );
});
break;
- case 'projects:edit':
+ case "projects:edit":
setupProjectEdit();
// Initialize expandable settings panels
initSettingsPanels();
break;
- case 'projects:imports:show':
+ case "projects:imports:show":
projectImport();
break;
- case 'projects:pipelines:new':
- case 'projects:pipelines:create':
- new NewBranchForm($('.js-new-pipeline-form'));
- break;
- case 'projects:pipelines:builds':
- case 'projects:pipelines:failures':
- case 'projects:pipelines:show':
- const { controllerAction } = document.querySelector('.js-pipeline-container').dataset;
- const pipelineStatusUrl = `${document.querySelector('.js-pipeline-tab-link a').getAttribute('href')}/status.json`;
+ case "projects:pipelines:new":
+ case "projects:pipelines:create":
+ new NewBranchForm($(".js-new-pipeline-form"));
+ break;
+ case "projects:pipelines:builds":
+ case "projects:pipelines:failures":
+ case "projects:pipelines:show":
+ const { controllerAction } = document.querySelector(
+ ".js-pipeline-container"
+ ).dataset;
+ const pipelineStatusUrl = `${document
+ .querySelector(".js-pipeline-tab-link a")
+ .getAttribute("href")}/status.json`;
new Pipelines({
initTabs: true,
pipelineStatusUrl,
tabsOptions: {
action: controllerAction,
- defaultAction: 'pipelines',
- parentEl: '.pipelines-tabs',
- },
+ defaultAction: "pipelines",
+ parentEl: ".pipelines-tabs"
+ }
});
break;
- case 'groups:activity':
+ case "groups:activity":
new Activities();
break;
- case 'groups:show':
- const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
+ case "groups:show":
+ const newGroupChildWrapper = document.querySelector(
+ ".js-new-project-subgroup"
+ );
shortcut_handler = new ShortcutsNavigation();
new NotificationsForm();
notificationsDropdown();
@@ -422,259 +475,273 @@ import Activities from './activities';
new NewGroupChild(newGroupChildWrapper);
}
break;
- case 'groups:group_members:index':
+ case "groups:group_members:index":
memberExpirationDate();
new Members();
new UsersSelect();
break;
- case 'projects:project_members:index':
- memberExpirationDate('.js-access-expiration-date-groups');
+ case "projects:project_members:index":
+ memberExpirationDate(".js-access-expiration-date-groups");
groupsSelect();
memberExpirationDate();
new Members();
new UsersSelect();
break;
- case 'groups:new':
- case 'admin:groups:new':
- case 'groups:create':
- case 'admin:groups:create':
+ case "groups:new":
+ case "admin:groups:new":
+ case "groups:create":
+ case "admin:groups:create":
BindInOut.initAll();
new Group();
groupAvatar();
break;
- case 'groups:edit':
- case 'admin:groups:edit':
+ case "groups:edit":
+ case "admin:groups:edit":
groupAvatar();
break;
- case 'projects:tree:show':
+ case "projects:tree:show":
shortcut_handler = new ShortcutsNavigation();
new TreeView();
new BlobViewer();
- new NewCommitForm($('.js-create-dir-form'));
- $('#tree-slider').waitForImages(function() {
- ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
+ new NewCommitForm($(".js-create-dir-form"));
+ $("#tree-slider").waitForImages(function() {
+ ajaxGet(
+ document.querySelector(".js-tree-content").dataset.logsPath
+ );
});
break;
- case 'projects:find_file:show':
- const findElement = document.querySelector('.js-file-finder');
- const projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
- url: findElement.dataset.fileFindUrl,
- treeUrl: findElement.dataset.findTreeUrl,
- blobUrlTemplate: findElement.dataset.blobUrlTemplate,
- });
+ case "projects:find_file:show":
+ const findElement = document.querySelector(".js-file-finder");
+ const projectFindFile = new ProjectFindFile(
+ $(".file-finder-holder"),
+ {
+ url: findElement.dataset.fileFindUrl,
+ treeUrl: findElement.dataset.findTreeUrl,
+ blobUrlTemplate: findElement.dataset.blobUrlTemplate
+ }
+ );
new ShortcutsFindFile(projectFindFile);
shortcut_handler = true;
break;
- case 'projects:blob:show':
+ case "projects:blob:show":
new BlobViewer();
initBlob();
break;
- case 'projects:blame:show':
+ case "projects:blame:show":
initBlob();
break;
- case 'groups:labels:new':
- case 'groups:labels:edit':
- case 'projects:labels:new':
- case 'projects:labels:edit':
+ case "groups:labels:new":
+ case "groups:labels:edit":
+ case "projects:labels:new":
+ case "projects:labels:edit":
new Labels();
break;
- case 'groups:labels:index':
- case 'projects:labels:index':
- if ($('.prioritized-labels').length) {
+ case "groups:labels:index":
+ case "projects:labels:index":
+ if ($(".prioritized-labels").length) {
new LabelManager();
}
- $('.label-subscription').each((i, el) => {
+ $(".label-subscription").each((i, el) => {
const $el = $(el);
- if ($el.find('.dropdown-group-label').length) {
+ if ($el.find(".dropdown-group-label").length) {
new GroupLabelSubscription($el);
} else {
new ProjectLabelSubscription($el);
}
});
break;
- case 'projects:network:show':
+ case "projects:network:show":
// Ensure we don't create a particular shortcut handler here. This is
// already created, where the network graph is created.
shortcut_handler = true;
break;
- case 'projects:forks:new':
- import(/* webpackChunkName: 'project_fork' */ './project_fork')
+ case "projects:forks:new":
+ import(/* webpackChunkName: 'project_fork' */ "./project_fork")
.then(fork => fork.default())
.catch(() => {});
break;
- case 'projects:artifacts:browse':
+ case "projects:artifacts:browse":
new ShortcutsNavigation();
new BuildArtifacts();
break;
- case 'projects:artifacts:file':
+ case "projects:artifacts:file":
new ShortcutsNavigation();
new BlobViewer();
break;
- case 'help:index':
- VersionCheckImage.bindErrorEvent($('img.js-version-status-badge'));
+ case "help:index":
+ VersionCheckImage.bindErrorEvent($("img.js-version-status-badge"));
break;
- case 'search:show':
+ case "search:show":
new Search();
break;
- case 'projects:settings:repository:show':
+ case "projects:settings:repository:show":
// Initialize expandable settings panels
initSettingsPanels();
break;
- case 'projects:settings:ci_cd:show':
+ case "projects:settings:ci_cd:show":
// Initialize expandable settings panels
initSettingsPanels();
- const runnerToken = document.querySelector('.js-secret-runner-token');
+ const runnerToken = document.querySelector(".js-secret-runner-token");
if (runnerToken) {
const runnerTokenSecretValue = new SecretValues(runnerToken);
runnerTokenSecretValue.init();
}
- case 'groups:settings:ci_cd:show':
- const secretVariableTable = document.querySelector('.js-secret-variable-table');
+ case "groups:settings:ci_cd:show":
+ const secretVariableTable = document.querySelector(
+ ".js-secret-variable-table"
+ );
if (secretVariableTable) {
- const secretVariableTableValues = new SecretValues(secretVariableTable);
+ const secretVariableTableValues = new SecretValues(
+ secretVariableTable
+ );
secretVariableTableValues.init();
}
break;
- case 'ci:lints:create':
- case 'ci:lints:show':
+ case "ci:lints:create":
+ case "ci:lints:show":
new CILintEditor();
break;
- case 'users:show':
- import('./pages/users/show').then(m => m.default()).catch(fail);
+ case "users:show":
+ import("./pages/users/show")
+ .then(m => m.default())
+ .catch(fail);
break;
- case 'admin:conversational_development_index:show':
+ case "admin:conversational_development_index:show":
new UserCallout();
break;
- case 'snippets:show':
+ case "snippets:show":
new LineHighlighter();
new BlobViewer();
initNotes();
new ZenMode();
break;
- case 'import:fogbugz:new_user_map':
+ case "import:fogbugz:new_user_map":
new UsersSelect();
break;
- case 'profiles:personal_access_tokens:index':
- case 'admin:impersonation_tokens:index':
+ case "profiles:personal_access_tokens:index":
+ case "admin:impersonation_tokens:index":
new DueDateSelectors();
break;
- case 'projects:clusters:show':
- import(/* webpackChunkName: "clusters" */ './clusters/clusters_bundle')
+ case "projects:clusters:show":
+ import(/* webpackChunkName: "clusters" */ "./clusters/clusters_bundle")
.then(cluster => new cluster.default()) // eslint-disable-line new-cap
- .catch((err) => {
- Flash(s__('ClusterIntegration|Problem setting up the cluster'));
+ .catch(err => {
+ Flash(s__("ClusterIntegration|Problem setting up the cluster"));
throw err;
});
break;
- case 'projects:clusters:index':
- import(/* webpackChunkName: "clusters_index" */ './clusters/clusters_index')
+ case "projects:clusters:index":
+ import(/* webpackChunkName: "clusters_index" */ "./clusters/clusters_index")
.then(clusterIndex => clusterIndex.default())
- .catch((err) => {
- Flash(s__('ClusterIntegration|Problem setting up the clusters list'));
+ .catch(err => {
+ Flash(
+ s__("ClusterIntegration|Problem setting up the clusters list")
+ );
throw err;
});
break;
}
switch (path[0]) {
- case 'sessions':
- case 'omniauth_callbacks':
+ case "sessions":
+ case "omniauth_callbacks":
if (!gon.u2f) break;
const u2fAuthenticate = new U2FAuthenticate(
- $('#js-authenticate-u2f'),
- '#js-login-u2f-form',
+ $("#js-authenticate-u2f"),
+ "#js-login-u2f-form",
gon.u2f,
- document.querySelector('#js-login-2fa-device'),
- document.querySelector('.js-2fa-form'),
+ document.querySelector("#js-login-2fa-device"),
+ document.querySelector(".js-2fa-form")
);
u2fAuthenticate.start();
// needed in rspec
gl.u2fAuthenticate = u2fAuthenticate;
- case 'admin':
+ case "admin":
initAdmin();
switch (path[1]) {
- case 'broadcast_messages':
+ case "broadcast_messages":
initBroadcastMessagesForm();
break;
- case 'cohorts':
+ case "cohorts":
new UsagePing();
break;
- case 'groups':
+ case "groups":
new UsersSelect();
break;
- case 'projects':
- document.querySelectorAll('.js-namespace-select')
+ case "projects":
+ document
+ .querySelectorAll(".js-namespace-select")
.forEach(dropdown => new NamespaceSelect({ dropdown }));
break;
- case 'labels':
+ case "labels":
switch (path[2]) {
- case 'new':
- case 'edit':
+ case "new":
+ case "edit":
new Labels();
}
- case 'abuse_reports':
+ case "abuse_reports":
new AbuseReports();
break;
}
break;
- case 'dashboard':
- case 'root':
+ case "dashboard":
+ case "root":
new UserCallout();
break;
- case 'profiles':
+ case "profiles":
new NotificationsForm();
notificationsDropdown();
break;
- case 'projects':
+ case "projects":
new Project();
projectAvatar();
switch (path[1]) {
- case 'compare':
+ case "compare":
initCompareAutocomplete();
break;
- case 'edit':
+ case "edit":
shortcut_handler = new ShortcutsNavigation();
new ProjectNew();
- import(/* webpackChunkName: 'project_permissions' */ './projects/permissions')
+ import(/* webpackChunkName: 'project_permissions' */ "./projects/permissions")
.then(permissions => permissions.default())
.catch(() => {});
break;
- case 'new':
+ case "new":
new ProjectNew();
initProjectVisibilitySelector();
break;
- case 'show':
+ case "show":
new Star();
new ProjectNew();
notificationsDropdown();
break;
- case 'wikis':
+ case "wikis":
new Wikis();
shortcut_handler = new ShortcutsWiki();
new ZenMode();
- new GLForm($('.wiki-form'), true);
+ new GLForm($(".wiki-form"), true);
break;
- case 'snippets':
+ case "snippets":
shortcut_handler = new ShortcutsNavigation();
- if (path[2] === 'show') {
+ if (path[2] === "show") {
new ZenMode();
new LineHighlighter();
new BlobViewer();
}
break;
- case 'labels':
- case 'graphs':
- case 'compare':
- case 'pipelines':
- case 'forks':
- case 'milestones':
- case 'project_members':
- case 'deploy_keys':
- case 'builds':
- case 'hooks':
- case 'services':
- case 'protected_branches':
+ case "labels":
+ case "graphs":
+ case "compare":
+ case "pipelines":
+ case "forks":
+ case "milestones":
+ case "project_members":
+ case "deploy_keys":
+ case "builds":
+ case "hooks":
+ case "services":
+ case "protected_branches":
shortcut_handler = new ShortcutsNavigation();
}
break;
@@ -684,20 +751,20 @@ import Activities from './activities';
new Shortcuts();
}
- if (document.querySelector('#peek')) {
- new PerformanceBar({ container: '#peek' });
+ if (document.querySelector("#peek")) {
+ new PerformanceBar({ container: "#peek" });
}
};
Dispatcher.prototype.initSearch = function() {
// Only when search form is present
- if ($('.search').length) {
+ if ($(".search").length) {
return new SearchAutocomplete();
}
};
Dispatcher.prototype.initFieldErrors = function() {
- $('.gl-show-field-errors').each((i, form) => {
+ $(".gl-show-field-errors").each((i, form) => {
new GlFieldErrors(form);
});
};
@@ -705,7 +772,7 @@ import Activities from './activities';
return Dispatcher;
})();
- $(window).on('load', function() {
+ $(window).on("load", function() {
new Dispatcher();
});
-}).call(window);
+}.call(window));
diff --git a/app/assets/javascripts/pages/explore/groups/index.js b/app/assets/javascripts/pages/explore/groups/index.js
new file mode 100644
index 00000000000..97c4e2dc869
--- /dev/null
+++ b/app/assets/javascripts/pages/explore/groups/index.js
@@ -0,0 +1,14 @@
+import GroupsList from "~/groups_list";
+import Landing from "~/landing";
+
+export default function() {
+ new GroupsList();
+ const landingElement = document.querySelector(".js-explore-groups-landing");
+ if (!landingElement) return;
+ const exploreGroupsLanding = new Landing(
+ landingElement,
+ landingElement.querySelector(".dismiss-button"),
+ "explore_groups_landing_dismissed"
+ );
+ exploreGroupsLanding.toggle();
+}
diff --git a/app/assets/javascripts/pages/explore/projects/index.js b/app/assets/javascripts/pages/explore/projects/index.js
new file mode 100644
index 00000000000..0bbb82b9daf
--- /dev/null
+++ b/app/assets/javascripts/pages/explore/projects/index.js
@@ -0,0 +1,5 @@
+import ProjectsList from "~/projects_list";
+
+export default function() {
+ new ProjectsList();
+}
--
cgit v1.2.1
From 1aff48068074409b7cc072f484638d8be1cdcb7c Mon Sep 17 00:00:00 2001
From: Jacob Schatz
Date: Mon, 8 Jan 2018 16:38:06 -0500
Subject: Updating dispatcher without code fixes
---
app/assets/javascripts/dispatcher.js | 755 ++++++++++-----------
.../javascripts/pages/explore/groups/index.js | 10 +-
.../javascripts/pages/explore/projects/index.js | 2 +-
3 files changed, 357 insertions(+), 410 deletions(-)
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 87e225a88a0..af516a8e7ff 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -1,95 +1,97 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
-import { s__ } from "./locale";
-import projectSelect from "./project_select";
-import IssuableIndex from "./issuable_index";
-import Milestone from "./milestone";
-import IssuableForm from "./issuable_form";
-import LabelsSelect from "./labels_select";
-import MilestoneSelect from "./milestone_select";
-import NewBranchForm from "./new_branch_form";
-import NotificationsForm from "./notifications_form";
-import notificationsDropdown from "./notifications_dropdown";
-import groupAvatar from "./group_avatar";
-import GroupLabelSubscription from "./group_label_subscription";
-import LineHighlighter from "./line_highlighter";
-import BuildArtifacts from "./build_artifacts";
-import CILintEditor from "./ci_lint_editor";
-import groupsSelect from "./groups_select";
-import Search from "./search";
-import initAdmin from "./admin";
-import NamespaceSelect from "./namespace_select";
-import NewCommitForm from "./new_commit_form";
-import Project from "./project";
-import projectAvatar from "./project_avatar";
-import MergeRequest from "./merge_request";
-import Compare from "./compare";
-import initCompareAutocomplete from "./compare_autocomplete";
-import ProjectFindFile from "./project_find_file";
-import ProjectNew from "./project_new";
-import projectImport from "./project_import";
-import Labels from "./labels";
-import LabelManager from "./label_manager";
-import Sidebar from "./right_sidebar";
-import IssuableTemplateSelectors from "./templates/issuable_template_selectors";
-import Flash from "./flash";
-import CommitsList from "./commits";
-import Issue from "./issue";
-import BindInOut from "./behaviors/bind_in_out";
-import SecretValues from "./behaviors/secret_values";
-import DeleteModal from "./branches/branches_delete_modal";
-import Group from "./group";
-import ProjectsList from "./projects_list";
-import setupProjectEdit from "./project_edit";
-import MiniPipelineGraph from "./mini_pipeline_graph_dropdown";
-import BlobLinePermalinkUpdater from "./blob/blob_line_permalink_updater";
-import BlobForkSuggestion from "./blob/blob_fork_suggestion";
-import UserCallout from "./user_callout";
-import ShortcutsWiki from "./shortcuts_wiki";
-import Pipelines from "./pipelines";
-import BlobViewer from "./blob/viewer/index";
-import AutoWidthDropdownSelect from "./issuable/auto_width_dropdown_select";
-import UsersSelect from "./users_select";
-import RefSelectDropdown from "./ref_select_dropdown";
-import GfmAutoComplete from "./gfm_auto_complete";
-import ShortcutsBlob from "./shortcuts_blob";
-import SigninTabsMemoizer from "./signin_tabs_memoizer";
-import Star from "./star";
-import Todos from "./todos";
-import TreeView from "./tree";
-import UsagePing from "./usage_ping";
-import UsernameValidator from "./username_validator";
-import VersionCheckImage from "./version_check_image";
-import Wikis from "./wikis";
-import ZenMode from "./zen_mode";
-import initSettingsPanels from "./settings_panels";
-import initExperimentalFlags from "./experimental_flags";
-import OAuthRememberMe from "./oauth_remember_me";
-import PerformanceBar from "./performance_bar";
-import initBroadcastMessagesForm from "./broadcast_message";
-import initNotes from "./init_notes";
-import initLegacyFilters from "./init_legacy_filters";
-import initIssuableSidebar from "./init_issuable_sidebar";
-import initProjectVisibilitySelector from "./project_visibility";
-import GpgBadges from "./gpg_badges";
-import initChangesDropdown from "./init_changes_dropdown";
-import NewGroupChild from "./groups/new_group_child";
-import AbuseReports from "./abuse_reports";
-import { ajaxGet, convertPermissionToBoolean } from "./lib/utils/common_utils";
-import AjaxLoadingSpinner from "./ajax_loading_spinner";
-import GlFieldErrors from "./gl_field_errors";
-import GLForm from "./gl_form";
-import Shortcuts from "./shortcuts";
-import ShortcutsNavigation from "./shortcuts_navigation";
-import ShortcutsFindFile from "./shortcuts_find_file";
-import ShortcutsIssuable from "./shortcuts_issuable";
-import U2FAuthenticate from "./u2f/authenticate";
-import Members from "./members";
-import memberExpirationDate from "./member_expiration_date";
-import DueDateSelectors from "./due_date_select";
-import Diff from "./diff";
-import ProjectLabelSubscription from "./project_label_subscription";
-import SearchAutocomplete from "./search_autocomplete";
-import Activities from "./activities";
+import { s__ } from './locale';
+import projectSelect from './project_select';
+import IssuableIndex from './issuable_index';
+import Milestone from './milestone';
+import IssuableForm from './issuable_form';
+import LabelsSelect from './labels_select';
+import MilestoneSelect from './milestone_select';
+import NewBranchForm from './new_branch_form';
+import NotificationsForm from './notifications_form';
+import notificationsDropdown from './notifications_dropdown';
+import groupAvatar from './group_avatar';
+import GroupLabelSubscription from './group_label_subscription';
+import LineHighlighter from './line_highlighter';
+import BuildArtifacts from './build_artifacts';
+import CILintEditor from './ci_lint_editor';
+import groupsSelect from './groups_select';
+import Search from './search';
+import initAdmin from './admin';
+import NamespaceSelect from './namespace_select';
+import NewCommitForm from './new_commit_form';
+import Project from './project';
+import projectAvatar from './project_avatar';
+import MergeRequest from './merge_request';
+import Compare from './compare';
+import initCompareAutocomplete from './compare_autocomplete';
+import ProjectFindFile from './project_find_file';
+import ProjectNew from './project_new';
+import projectImport from './project_import';
+import Labels from './labels';
+import LabelManager from './label_manager';
+import Sidebar from './right_sidebar';
+import IssuableTemplateSelectors from './templates/issuable_template_selectors';
+import Flash from './flash';
+import CommitsList from './commits';
+import Issue from './issue';
+import BindInOut from './behaviors/bind_in_out';
+import SecretValues from './behaviors/secret_values';
+import DeleteModal from './branches/branches_delete_modal';
+import Group from './group';
+import GroupsList from './groups_list';
+import ProjectsList from './projects_list';
+import setupProjectEdit from './project_edit';
+import MiniPipelineGraph from './mini_pipeline_graph_dropdown';
+import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater';
+import Landing from './landing';
+import BlobForkSuggestion from './blob/blob_fork_suggestion';
+import UserCallout from './user_callout';
+import ShortcutsWiki from './shortcuts_wiki';
+import Pipelines from './pipelines';
+import BlobViewer from './blob/viewer/index';
+import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
+import UsersSelect from './users_select';
+import RefSelectDropdown from './ref_select_dropdown';
+import GfmAutoComplete from './gfm_auto_complete';
+import ShortcutsBlob from './shortcuts_blob';
+import SigninTabsMemoizer from './signin_tabs_memoizer';
+import Star from './star';
+import Todos from './todos';
+import TreeView from './tree';
+import UsagePing from './usage_ping';
+import UsernameValidator from './username_validator';
+import VersionCheckImage from './version_check_image';
+import Wikis from './wikis';
+import ZenMode from './zen_mode';
+import initSettingsPanels from './settings_panels';
+import initExperimentalFlags from './experimental_flags';
+import OAuthRememberMe from './oauth_remember_me';
+import PerformanceBar from './performance_bar';
+import initBroadcastMessagesForm from './broadcast_message';
+import initNotes from './init_notes';
+import initLegacyFilters from './init_legacy_filters';
+import initIssuableSidebar from './init_issuable_sidebar';
+import initProjectVisibilitySelector from './project_visibility';
+import GpgBadges from './gpg_badges';
+import initChangesDropdown from './init_changes_dropdown';
+import NewGroupChild from './groups/new_group_child';
+import AbuseReports from './abuse_reports';
+import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
+import AjaxLoadingSpinner from './ajax_loading_spinner';
+import GlFieldErrors from './gl_field_errors';
+import GLForm from './gl_form';
+import Shortcuts from './shortcuts';
+import ShortcutsNavigation from './shortcuts_navigation';
+import ShortcutsFindFile from './shortcuts_find_file';
+import ShortcutsIssuable from './shortcuts_issuable';
+import U2FAuthenticate from './u2f/authenticate';
+import Members from './members';
+import memberExpirationDate from './member_expiration_date';
+import DueDateSelectors from './due_date_select';
+import Diff from './diff';
+import ProjectLabelSubscription from './project_label_subscription';
+import SearchAutocomplete from './search_autocomplete';
+import Activities from './activities';
(function() {
var Dispatcher;
@@ -102,34 +104,27 @@ import Activities from "./activities";
}
Dispatcher.prototype.initPageScripts = function() {
- var path,
- shortcut_handler,
- fileBlobPermalinkUrlElement,
- fileBlobPermalinkUrl;
- const page = $("body").attr("data-page");
+ var path, shortcut_handler, fileBlobPermalinkUrlElement, fileBlobPermalinkUrl;
+ const page = $('body').attr('data-page');
if (!page) {
return false;
}
- const fail = () => Flash("Error loading dynamic module");
+ const fail = () => Flash('Error loading dynamic module');
- path = page.split(":");
+ path = page.split(':');
shortcut_handler = null;
- $(".js-gfm-input:not(.js-vue-textarea)").each((i, el) => {
- const gfm = new GfmAutoComplete(
- gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources
- );
- const enableGFM = convertPermissionToBoolean(
- el.dataset.supportsAutocomplete
- );
+ $('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
+ const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
+ const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
gfm.setup($(el), {
emojis: true,
members: enableGFM,
issues: enableGFM,
milestones: enableGFM,
mergeRequests: enableGFM,
- labels: enableGFM
+ labels: enableGFM,
});
});
@@ -137,335 +132,301 @@ import Activities from "./activities";
new LineHighlighter();
new BlobLinePermalinkUpdater(
- document.querySelector("#blob-content-holder"),
- ".diff-line-num[data-line-number]",
- document.querySelectorAll(
- ".js-data-file-blob-permalink-url, .js-blob-blame-link"
- )
+ document.querySelector('#blob-content-holder'),
+ '.diff-line-num[data-line-number]',
+ document.querySelectorAll('.js-data-file-blob-permalink-url, .js-blob-blame-link'),
);
shortcut_handler = new ShortcutsNavigation();
- fileBlobPermalinkUrlElement = document.querySelector(
- ".js-data-file-blob-permalink-url"
- );
- fileBlobPermalinkUrl =
- fileBlobPermalinkUrlElement &&
- fileBlobPermalinkUrlElement.getAttribute("href");
+ fileBlobPermalinkUrlElement = document.querySelector('.js-data-file-blob-permalink-url');
+ fileBlobPermalinkUrl = fileBlobPermalinkUrlElement && fileBlobPermalinkUrlElement.getAttribute('href');
new ShortcutsBlob({
skipResetBindings: true,
- fileBlobPermalinkUrl
+ fileBlobPermalinkUrl,
});
new BlobForkSuggestion({
- openButtons: document.querySelectorAll(
- ".js-edit-blob-link-fork-toggler"
- ),
- forkButtons: document.querySelectorAll(".js-fork-suggestion-button"),
- cancelButtons: document.querySelectorAll(
- ".js-cancel-fork-suggestion-button"
- ),
- suggestionSections: document.querySelectorAll(
- ".js-file-fork-suggestion-section"
- ),
- actionTextPieces: document.querySelectorAll(
- ".js-file-fork-suggestion-section-action"
- )
- }).init();
+ openButtons: document.querySelectorAll('.js-edit-blob-link-fork-toggler'),
+ forkButtons: document.querySelectorAll('.js-fork-suggestion-button'),
+ cancelButtons: document.querySelectorAll('.js-cancel-fork-suggestion-button'),
+ suggestionSections: document.querySelectorAll('.js-file-fork-suggestion-section'),
+ actionTextPieces: document.querySelectorAll('.js-file-fork-suggestion-section-action'),
+ })
+ .init();
}
- const filteredSearchEnabled =
- gl.FilteredSearchManager && document.querySelector(".filtered-search");
+ const filteredSearchEnabled = gl.FilteredSearchManager && document.querySelector('.filtered-search');
switch (page) {
- case "profiles:preferences:show":
+ case 'profiles:preferences:show':
initExperimentalFlags();
break;
- case "sessions:new":
+ case 'sessions:new':
new UsernameValidator();
new SigninTabsMemoizer();
- new OAuthRememberMe({
- container: $(".omniauth-container")
- }).bindEvents();
+ new OAuthRememberMe({ container: $(".omniauth-container") }).bindEvents();
break;
- case "projects:boards:show":
- case "projects:boards:index":
+ case 'projects:boards:show':
+ case 'projects:boards:index':
shortcut_handler = new ShortcutsNavigation();
new UsersSelect();
break;
- case "projects:merge_requests:index":
- case "projects:issues:index":
+ case 'projects:merge_requests:index':
+ case 'projects:issues:index':
if (filteredSearchEnabled) {
- const filteredSearchManager = new gl.FilteredSearchManager(
- page === "projects:issues:index" ? "issues" : "merge_requests"
- );
+ const filteredSearchManager = new gl.FilteredSearchManager(page === 'projects:issues:index' ? 'issues' : 'merge_requests');
filteredSearchManager.setup();
}
- const pagePrefix =
- page === "projects:merge_requests:index"
- ? "merge_request_"
- : "issue_";
+ const pagePrefix = page === 'projects:merge_requests:index' ? 'merge_request_' : 'issue_';
new IssuableIndex(pagePrefix);
shortcut_handler = new ShortcutsNavigation();
new UsersSelect();
break;
- case "projects:issues:show":
+ case 'projects:issues:show':
new Issue();
shortcut_handler = new ShortcutsIssuable();
new ZenMode();
initIssuableSidebar();
break;
- case "dashboard:milestones:index":
+ case 'dashboard:milestones:index':
projectSelect();
break;
- case "projects:milestones:show":
- case "groups:milestones:show":
- case "dashboard:milestones:show":
+ case 'projects:milestones:show':
+ case 'groups:milestones:show':
+ case 'dashboard:milestones:show':
new Milestone();
new Sidebar();
break;
- case "dashboard:issues":
- case "dashboard:merge_requests":
+ case 'dashboard:issues':
+ case 'dashboard:merge_requests':
projectSelect();
initLegacyFilters();
break;
- case "groups:issues":
- case "groups:merge_requests":
+ case 'groups:issues':
+ case 'groups:merge_requests':
if (filteredSearchEnabled) {
- const filteredSearchManager = new gl.FilteredSearchManager(
- page === "groups:issues" ? "issues" : "merge_requests"
- );
+ const filteredSearchManager = new gl.FilteredSearchManager(page === 'groups:issues' ? 'issues' : 'merge_requests');
filteredSearchManager.setup();
}
projectSelect();
break;
- case "dashboard:todos:index":
+ case 'dashboard:todos:index':
new Todos();
break;
- case "explore:projects:index":
- case "explore:projects:trending":
- case "explore:projects:starred":
- import("./pages/explore/projects")
+
+ case 'explore:projects:index':
+ case 'explore:projects:trending':
+ case 'explore:projects:starred':
+ import('./pages/explore/projects')
.then(module => module.default())
.catch(fail);
break;
- case "dashboard:projects:index":
- case "dashboard:projects:starred":
- case "admin:projects:index":
+ case 'dashboard:projects:index':
+ case 'dashboard:projects:starred':
+ case 'admin:projects:index':
new ProjectsList();
break;
- case "explore:groups:index":
- import("./pages/explore/groups")
+ case 'explore:groups:index':
+ import('./pages/explore/groups')
.then(module => module.default())
.catch(fail);
break;
- case "projects:milestones:new":
- case "projects:milestones:edit":
- case "projects:milestones:update":
+
+ case 'admin:projects:index':
+ new ProjectsList();
+ break;
+ case 'explore:groups:index':
+ new GroupsList();
+ const landingElement = document.querySelector('.js-explore-groups-landing');
+ if (!landingElement) break;
+ const exploreGroupsLanding = new Landing(
+ landingElement,
+ landingElement.querySelector('.dismiss-button'),
+ 'explore_groups_landing_dismissed',
+ );
+ exploreGroupsLanding.toggle();
+ break;
+ case 'projects:milestones:new':
+ case 'projects:milestones:edit':
+ case 'projects:milestones:update':
new ZenMode();
new DueDateSelectors();
- new GLForm($(".milestone-form"), true);
+ new GLForm($('.milestone-form'), true);
break;
- case "groups:milestones:new":
- case "groups:milestones:edit":
- case "groups:milestones:update":
+ case 'groups:milestones:new':
+ case 'groups:milestones:edit':
+ case 'groups:milestones:update':
new ZenMode();
new DueDateSelectors();
- new GLForm($(".milestone-form"), false);
+ new GLForm($('.milestone-form'), false);
break;
- case "projects:compare:show":
+ case 'projects:compare:show':
new Diff();
const paddingTop = 16;
- initChangesDropdown(
- document.querySelector(".navbar-gitlab").offsetHeight - paddingTop
- );
+ initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - paddingTop);
break;
- case "projects:branches:new":
- case "projects:branches:create":
- new NewBranchForm(
- $(".js-create-branch-form"),
- JSON.parse(document.getElementById("availableRefs").innerHTML)
- );
+ case 'projects:branches:new':
+ case 'projects:branches:create':
+ new NewBranchForm($('.js-create-branch-form'), JSON.parse(document.getElementById('availableRefs').innerHTML));
break;
- case "projects:branches:index":
+ case 'projects:branches:index':
AjaxLoadingSpinner.init();
new DeleteModal();
break;
- case "projects:issues:new":
- case "projects:issues:edit":
+ case 'projects:issues:new':
+ case 'projects:issues:edit':
shortcut_handler = new ShortcutsNavigation();
- new GLForm($(".issue-form"), true);
- new IssuableForm($(".issue-form"));
+ new GLForm($('.issue-form'), true);
+ new IssuableForm($('.issue-form'));
new LabelsSelect();
new MilestoneSelect();
new IssuableTemplateSelectors();
break;
- case "projects:merge_requests:creations:new":
- const mrNewCompareNode = document.querySelector(
- ".js-merge-request-new-compare"
- );
+ case 'projects:merge_requests:creations:new':
+ const mrNewCompareNode = document.querySelector('.js-merge-request-new-compare');
if (mrNewCompareNode) {
new Compare({
targetProjectUrl: mrNewCompareNode.dataset.targetProjectUrl,
sourceBranchUrl: mrNewCompareNode.dataset.sourceBranchUrl,
- targetBranchUrl: mrNewCompareNode.dataset.targetBranchUrl
+ targetBranchUrl: mrNewCompareNode.dataset.targetBranchUrl,
});
} else {
- const mrNewSubmitNode = document.querySelector(
- ".js-merge-request-new-submit"
- );
+ const mrNewSubmitNode = document.querySelector('.js-merge-request-new-submit');
new MergeRequest({
- action: mrNewSubmitNode.dataset.mrSubmitAction
+ action: mrNewSubmitNode.dataset.mrSubmitAction,
});
}
- case "projects:merge_requests:creations:diffs":
- case "projects:merge_requests:edit":
+ case 'projects:merge_requests:creations:diffs':
+ case 'projects:merge_requests:edit':
new Diff();
shortcut_handler = new ShortcutsNavigation();
- new GLForm($(".merge-request-form"), true);
- new IssuableForm($(".merge-request-form"));
+ new GLForm($('.merge-request-form'), true);
+ new IssuableForm($('.merge-request-form'));
new LabelsSelect();
new MilestoneSelect();
new IssuableTemplateSelectors();
- new AutoWidthDropdownSelect($(".js-target-branch-select")).init();
+ new AutoWidthDropdownSelect($('.js-target-branch-select')).init();
break;
- case "projects:tags:new":
+ case 'projects:tags:new':
new ZenMode();
- new GLForm($(".tag-form"), true);
- new RefSelectDropdown($(".js-branch-select"));
+ new GLForm($('.tag-form'), true);
+ new RefSelectDropdown($('.js-branch-select'));
break;
- case "projects:snippets:show":
+ case 'projects:snippets:show':
initNotes();
new ZenMode();
break;
- case "projects:snippets:new":
- case "projects:snippets:edit":
- case "projects:snippets:create":
- case "projects:snippets:update":
- new GLForm($(".snippet-form"), true);
+ case 'projects:snippets:new':
+ case 'projects:snippets:edit':
+ case 'projects:snippets:create':
+ case 'projects:snippets:update':
+ new GLForm($('.snippet-form'), true);
new ZenMode();
break;
- case "snippets:new":
- case "snippets:edit":
- case "snippets:create":
- case "snippets:update":
- new GLForm($(".snippet-form"), false);
+ case 'snippets:new':
+ case 'snippets:edit':
+ case 'snippets:create':
+ case 'snippets:update':
+ new GLForm($('.snippet-form'), false);
new ZenMode();
break;
- case "projects:releases:edit":
+ case 'projects:releases:edit':
new ZenMode();
- new GLForm($(".release-form"), true);
+ new GLForm($('.release-form'), true);
break;
- case "projects:merge_requests:show":
+ case 'projects:merge_requests:show':
new Diff();
new ZenMode();
initIssuableSidebar();
initNotes();
- const mrShowNode = document.querySelector(".merge-request");
+ const mrShowNode = document.querySelector('.merge-request');
window.mergeRequest = new MergeRequest({
- action: mrShowNode.dataset.mrAction
+ action: mrShowNode.dataset.mrAction,
});
shortcut_handler = new ShortcutsIssuable(true);
break;
- case "dashboard:activity":
+ case 'dashboard:activity':
new Activities();
break;
- case "projects:commit:show":
+ case 'projects:commit:show':
new Diff();
new ZenMode();
shortcut_handler = new ShortcutsNavigation();
new MiniPipelineGraph({
- container: ".js-commit-pipeline-graph"
+ container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
const stickyBarPaddingTop = 16;
- initChangesDropdown(
- document.querySelector(".navbar-gitlab").offsetHeight -
- stickyBarPaddingTop
- );
- $(".commit-info.branches").load(
- document.querySelector(".js-commit-box").dataset.commitPath
- );
+ initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - stickyBarPaddingTop);
+ $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break;
- case "projects:commit:pipelines":
+ case 'projects:commit:pipelines':
new MiniPipelineGraph({
- container: ".js-commit-pipeline-graph"
+ container: '.js-commit-pipeline-graph',
}).bindEvents();
- $(".commit-info.branches").load(
- document.querySelector(".js-commit-box").dataset.commitPath
- );
+ $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break;
- case "projects:activity":
+ case 'projects:activity':
new Activities();
shortcut_handler = new ShortcutsNavigation();
break;
- case "projects:commits:show":
- CommitsList.init(
- document.querySelector(".js-project-commits-show").dataset
- .commitsLimit
- );
+ case 'projects:commits:show':
+ CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
shortcut_handler = new ShortcutsNavigation();
GpgBadges.fetch();
break;
- case "projects:show":
+ case 'projects:show':
shortcut_handler = new ShortcutsNavigation();
new NotificationsForm();
new UserCallout({
setCalloutPerProject: true,
- className: "js-autodevops-banner"
+ className: 'js-autodevops-banner',
});
- if ($("#tree-slider").length) new TreeView();
- if ($(".blob-viewer").length) new BlobViewer();
- if ($(".project-show-activity").length) new Activities();
- $("#tree-slider").waitForImages(function() {
- ajaxGet(
- document.querySelector(".js-tree-content").dataset.logsPath
- );
+ if ($('#tree-slider').length) new TreeView();
+ if ($('.blob-viewer').length) new BlobViewer();
+ if ($('.project-show-activity').length) new Activities();
+ $('#tree-slider').waitForImages(function() {
+ ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
});
break;
- case "projects:edit":
+ case 'projects:edit':
setupProjectEdit();
// Initialize expandable settings panels
initSettingsPanels();
break;
- case "projects:imports:show":
+ case 'projects:imports:show':
projectImport();
break;
- case "projects:pipelines:new":
- case "projects:pipelines:create":
- new NewBranchForm($(".js-new-pipeline-form"));
- break;
- case "projects:pipelines:builds":
- case "projects:pipelines:failures":
- case "projects:pipelines:show":
- const { controllerAction } = document.querySelector(
- ".js-pipeline-container"
- ).dataset;
- const pipelineStatusUrl = `${document
- .querySelector(".js-pipeline-tab-link a")
- .getAttribute("href")}/status.json`;
+ case 'projects:pipelines:new':
+ case 'projects:pipelines:create':
+ new NewBranchForm($('.js-new-pipeline-form'));
+ break;
+ case 'projects:pipelines:builds':
+ case 'projects:pipelines:failures':
+ case 'projects:pipelines:show':
+ const { controllerAction } = document.querySelector('.js-pipeline-container').dataset;
+ const pipelineStatusUrl = `${document.querySelector('.js-pipeline-tab-link a').getAttribute('href')}/status.json`;
new Pipelines({
initTabs: true,
pipelineStatusUrl,
tabsOptions: {
action: controllerAction,
- defaultAction: "pipelines",
- parentEl: ".pipelines-tabs"
- }
+ defaultAction: 'pipelines',
+ parentEl: '.pipelines-tabs',
+ },
});
break;
- case "groups:activity":
+ case 'groups:activity':
new Activities();
break;
- case "groups:show":
- const newGroupChildWrapper = document.querySelector(
- ".js-new-project-subgroup"
- );
+ case 'groups:show':
+ const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
shortcut_handler = new ShortcutsNavigation();
new NotificationsForm();
notificationsDropdown();
@@ -475,273 +436,259 @@ import Activities from "./activities";
new NewGroupChild(newGroupChildWrapper);
}
break;
- case "groups:group_members:index":
+ case 'groups:group_members:index':
memberExpirationDate();
new Members();
new UsersSelect();
break;
- case "projects:project_members:index":
- memberExpirationDate(".js-access-expiration-date-groups");
+ case 'projects:project_members:index':
+ memberExpirationDate('.js-access-expiration-date-groups');
groupsSelect();
memberExpirationDate();
new Members();
new UsersSelect();
break;
- case "groups:new":
- case "admin:groups:new":
- case "groups:create":
- case "admin:groups:create":
+ case 'groups:new':
+ case 'admin:groups:new':
+ case 'groups:create':
+ case 'admin:groups:create':
BindInOut.initAll();
new Group();
groupAvatar();
break;
- case "groups:edit":
- case "admin:groups:edit":
+ case 'groups:edit':
+ case 'admin:groups:edit':
groupAvatar();
break;
- case "projects:tree:show":
+ case 'projects:tree:show':
shortcut_handler = new ShortcutsNavigation();
new TreeView();
new BlobViewer();
- new NewCommitForm($(".js-create-dir-form"));
- $("#tree-slider").waitForImages(function() {
- ajaxGet(
- document.querySelector(".js-tree-content").dataset.logsPath
- );
+ new NewCommitForm($('.js-create-dir-form'));
+ $('#tree-slider').waitForImages(function() {
+ ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
});
break;
- case "projects:find_file:show":
- const findElement = document.querySelector(".js-file-finder");
- const projectFindFile = new ProjectFindFile(
- $(".file-finder-holder"),
- {
- url: findElement.dataset.fileFindUrl,
- treeUrl: findElement.dataset.findTreeUrl,
- blobUrlTemplate: findElement.dataset.blobUrlTemplate
- }
- );
+ case 'projects:find_file:show':
+ const findElement = document.querySelector('.js-file-finder');
+ const projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
+ url: findElement.dataset.fileFindUrl,
+ treeUrl: findElement.dataset.findTreeUrl,
+ blobUrlTemplate: findElement.dataset.blobUrlTemplate,
+ });
new ShortcutsFindFile(projectFindFile);
shortcut_handler = true;
break;
- case "projects:blob:show":
+ case 'projects:blob:show':
new BlobViewer();
initBlob();
break;
- case "projects:blame:show":
+ case 'projects:blame:show':
initBlob();
break;
- case "groups:labels:new":
- case "groups:labels:edit":
- case "projects:labels:new":
- case "projects:labels:edit":
+ case 'groups:labels:new':
+ case 'groups:labels:edit':
+ case 'projects:labels:new':
+ case 'projects:labels:edit':
new Labels();
break;
- case "groups:labels:index":
- case "projects:labels:index":
- if ($(".prioritized-labels").length) {
+ case 'groups:labels:index':
+ case 'projects:labels:index':
+ if ($('.prioritized-labels').length) {
new LabelManager();
}
- $(".label-subscription").each((i, el) => {
+ $('.label-subscription').each((i, el) => {
const $el = $(el);
- if ($el.find(".dropdown-group-label").length) {
+ if ($el.find('.dropdown-group-label').length) {
new GroupLabelSubscription($el);
} else {
new ProjectLabelSubscription($el);
}
});
break;
- case "projects:network:show":
+ case 'projects:network:show':
// Ensure we don't create a particular shortcut handler here. This is
// already created, where the network graph is created.
shortcut_handler = true;
break;
- case "projects:forks:new":
- import(/* webpackChunkName: 'project_fork' */ "./project_fork")
+ case 'projects:forks:new':
+ import(/* webpackChunkName: 'project_fork' */ './project_fork')
.then(fork => fork.default())
.catch(() => {});
break;
- case "projects:artifacts:browse":
+ case 'projects:artifacts:browse':
new ShortcutsNavigation();
new BuildArtifacts();
break;
- case "projects:artifacts:file":
+ case 'projects:artifacts:file':
new ShortcutsNavigation();
new BlobViewer();
break;
- case "help:index":
- VersionCheckImage.bindErrorEvent($("img.js-version-status-badge"));
+ case 'help:index':
+ VersionCheckImage.bindErrorEvent($('img.js-version-status-badge'));
break;
- case "search:show":
+ case 'search:show':
new Search();
break;
- case "projects:settings:repository:show":
+ case 'projects:settings:repository:show':
// Initialize expandable settings panels
initSettingsPanels();
break;
- case "projects:settings:ci_cd:show":
+ case 'projects:settings:ci_cd:show':
// Initialize expandable settings panels
initSettingsPanels();
- const runnerToken = document.querySelector(".js-secret-runner-token");
+ const runnerToken = document.querySelector('.js-secret-runner-token');
if (runnerToken) {
const runnerTokenSecretValue = new SecretValues(runnerToken);
runnerTokenSecretValue.init();
}
- case "groups:settings:ci_cd:show":
- const secretVariableTable = document.querySelector(
- ".js-secret-variable-table"
- );
+ case 'groups:settings:ci_cd:show':
+ const secretVariableTable = document.querySelector('.js-secret-variable-table');
if (secretVariableTable) {
- const secretVariableTableValues = new SecretValues(
- secretVariableTable
- );
+ const secretVariableTableValues = new SecretValues(secretVariableTable);
secretVariableTableValues.init();
}
break;
- case "ci:lints:create":
- case "ci:lints:show":
+ case 'ci:lints:create':
+ case 'ci:lints:show':
new CILintEditor();
break;
- case "users:show":
- import("./pages/users/show")
- .then(m => m.default())
- .catch(fail);
+ case 'users:show':
+ import('./pages/users/show').then(m => m.default()).catch(fail);
break;
- case "admin:conversational_development_index:show":
+ case 'admin:conversational_development_index:show':
new UserCallout();
break;
- case "snippets:show":
+ case 'snippets:show':
new LineHighlighter();
new BlobViewer();
initNotes();
new ZenMode();
break;
- case "import:fogbugz:new_user_map":
+ case 'import:fogbugz:new_user_map':
new UsersSelect();
break;
- case "profiles:personal_access_tokens:index":
- case "admin:impersonation_tokens:index":
+ case 'profiles:personal_access_tokens:index':
+ case 'admin:impersonation_tokens:index':
new DueDateSelectors();
break;
- case "projects:clusters:show":
- import(/* webpackChunkName: "clusters" */ "./clusters/clusters_bundle")
+ case 'projects:clusters:show':
+ import(/* webpackChunkName: "clusters" */ './clusters/clusters_bundle')
.then(cluster => new cluster.default()) // eslint-disable-line new-cap
- .catch(err => {
- Flash(s__("ClusterIntegration|Problem setting up the cluster"));
+ .catch((err) => {
+ Flash(s__('ClusterIntegration|Problem setting up the cluster'));
throw err;
});
break;
- case "projects:clusters:index":
- import(/* webpackChunkName: "clusters_index" */ "./clusters/clusters_index")
+ case 'projects:clusters:index':
+ import(/* webpackChunkName: "clusters_index" */ './clusters/clusters_index')
.then(clusterIndex => clusterIndex.default())
- .catch(err => {
- Flash(
- s__("ClusterIntegration|Problem setting up the clusters list")
- );
+ .catch((err) => {
+ Flash(s__('ClusterIntegration|Problem setting up the clusters list'));
throw err;
});
break;
}
switch (path[0]) {
- case "sessions":
- case "omniauth_callbacks":
+ case 'sessions':
+ case 'omniauth_callbacks':
if (!gon.u2f) break;
const u2fAuthenticate = new U2FAuthenticate(
- $("#js-authenticate-u2f"),
- "#js-login-u2f-form",
+ $('#js-authenticate-u2f'),
+ '#js-login-u2f-form',
gon.u2f,
- document.querySelector("#js-login-2fa-device"),
- document.querySelector(".js-2fa-form")
+ document.querySelector('#js-login-2fa-device'),
+ document.querySelector('.js-2fa-form'),
);
u2fAuthenticate.start();
// needed in rspec
gl.u2fAuthenticate = u2fAuthenticate;
- case "admin":
+ case 'admin':
initAdmin();
switch (path[1]) {
- case "broadcast_messages":
+ case 'broadcast_messages':
initBroadcastMessagesForm();
break;
- case "cohorts":
+ case 'cohorts':
new UsagePing();
break;
- case "groups":
+ case 'groups':
new UsersSelect();
break;
- case "projects":
- document
- .querySelectorAll(".js-namespace-select")
+ case 'projects':
+ document.querySelectorAll('.js-namespace-select')
.forEach(dropdown => new NamespaceSelect({ dropdown }));
break;
- case "labels":
+ case 'labels':
switch (path[2]) {
- case "new":
- case "edit":
+ case 'new':
+ case 'edit':
new Labels();
}
- case "abuse_reports":
+ case 'abuse_reports':
new AbuseReports();
break;
}
break;
- case "dashboard":
- case "root":
+ case 'dashboard':
+ case 'root':
new UserCallout();
break;
- case "profiles":
+ case 'profiles':
new NotificationsForm();
notificationsDropdown();
break;
- case "projects":
+ case 'projects':
new Project();
projectAvatar();
switch (path[1]) {
- case "compare":
+ case 'compare':
initCompareAutocomplete();
break;
- case "edit":
+ case 'edit':
shortcut_handler = new ShortcutsNavigation();
new ProjectNew();
- import(/* webpackChunkName: 'project_permissions' */ "./projects/permissions")
+ import(/* webpackChunkName: 'project_permissions' */ './projects/permissions')
.then(permissions => permissions.default())
.catch(() => {});
break;
- case "new":
+ case 'new':
new ProjectNew();
initProjectVisibilitySelector();
break;
- case "show":
+ case 'show':
new Star();
new ProjectNew();
notificationsDropdown();
break;
- case "wikis":
+ case 'wikis':
new Wikis();
shortcut_handler = new ShortcutsWiki();
new ZenMode();
- new GLForm($(".wiki-form"), true);
+ new GLForm($('.wiki-form'), true);
break;
- case "snippets":
+ case 'snippets':
shortcut_handler = new ShortcutsNavigation();
- if (path[2] === "show") {
+ if (path[2] === 'show') {
new ZenMode();
new LineHighlighter();
new BlobViewer();
}
break;
- case "labels":
- case "graphs":
- case "compare":
- case "pipelines":
- case "forks":
- case "milestones":
- case "project_members":
- case "deploy_keys":
- case "builds":
- case "hooks":
- case "services":
- case "protected_branches":
+ case 'labels':
+ case 'graphs':
+ case 'compare':
+ case 'pipelines':
+ case 'forks':
+ case 'milestones':
+ case 'project_members':
+ case 'deploy_keys':
+ case 'builds':
+ case 'hooks':
+ case 'services':
+ case 'protected_branches':
shortcut_handler = new ShortcutsNavigation();
}
break;
@@ -751,20 +698,20 @@ import Activities from "./activities";
new Shortcuts();
}
- if (document.querySelector("#peek")) {
- new PerformanceBar({ container: "#peek" });
+ if (document.querySelector('#peek')) {
+ new PerformanceBar({ container: '#peek' });
}
};
Dispatcher.prototype.initSearch = function() {
// Only when search form is present
- if ($(".search").length) {
+ if ($('.search').length) {
return new SearchAutocomplete();
}
};
Dispatcher.prototype.initFieldErrors = function() {
- $(".gl-show-field-errors").each((i, form) => {
+ $('.gl-show-field-errors').each((i, form) => {
new GlFieldErrors(form);
});
};
@@ -772,7 +719,7 @@ import Activities from "./activities";
return Dispatcher;
})();
- $(window).on("load", function() {
+ $(window).on('load', function() {
new Dispatcher();
});
-}.call(window));
+}).call(window);
diff --git a/app/assets/javascripts/pages/explore/groups/index.js b/app/assets/javascripts/pages/explore/groups/index.js
index 97c4e2dc869..6515202a31b 100644
--- a/app/assets/javascripts/pages/explore/groups/index.js
+++ b/app/assets/javascripts/pages/explore/groups/index.js
@@ -1,14 +1,14 @@
-import GroupsList from "~/groups_list";
-import Landing from "~/landing";
+import GroupsList from '~/groups_list';
+import Landing from '~/landing';
export default function() {
new GroupsList();
- const landingElement = document.querySelector(".js-explore-groups-landing");
+ const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) return;
const exploreGroupsLanding = new Landing(
landingElement,
- landingElement.querySelector(".dismiss-button"),
- "explore_groups_landing_dismissed"
+ landingElement.querySelector('.dismiss-button'),
+ 'explore_groups_landing_dismissed'
);
exploreGroupsLanding.toggle();
}
diff --git a/app/assets/javascripts/pages/explore/projects/index.js b/app/assets/javascripts/pages/explore/projects/index.js
index 0bbb82b9daf..2259cb7a5cf 100644
--- a/app/assets/javascripts/pages/explore/projects/index.js
+++ b/app/assets/javascripts/pages/explore/projects/index.js
@@ -1,4 +1,4 @@
-import ProjectsList from "~/projects_list";
+import ProjectsList from '~/projects_list';
export default function() {
new ProjectsList();
--
cgit v1.2.1
From cc67e91415f562fd19cc9768c7e451bc937c8264 Mon Sep 17 00:00:00 2001
From: Jacob Schatz
Date: Mon, 8 Jan 2018 16:40:19 -0500
Subject: Fixes duplication
---
app/assets/javascripts/dispatcher.js | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index af516a8e7ff..96802f167ba 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -214,7 +214,6 @@ import Activities from './activities';
case 'dashboard:todos:index':
new Todos();
break;
-
case 'explore:projects:index':
case 'explore:projects:trending':
case 'explore:projects:starred':
@@ -232,21 +231,6 @@ import Activities from './activities';
.then(module => module.default())
.catch(fail);
break;
-
- case 'admin:projects:index':
- new ProjectsList();
- break;
- case 'explore:groups:index':
- new GroupsList();
- const landingElement = document.querySelector('.js-explore-groups-landing');
- if (!landingElement) break;
- const exploreGroupsLanding = new Landing(
- landingElement,
- landingElement.querySelector('.dismiss-button'),
- 'explore_groups_landing_dismissed',
- );
- exploreGroupsLanding.toggle();
- break;
case 'projects:milestones:new':
case 'projects:milestones:edit':
case 'projects:milestones:update':
--
cgit v1.2.1
From a75bbbd92ad28f8d731231104e65d6aeeca1256c Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Mon, 8 Jan 2018 19:40:23 -0200
Subject: Make Rubocop happy
---
spec/tasks/gitlab/uploads_rake_spec.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/tasks/gitlab/uploads_rake_spec.rb b/spec/tasks/gitlab/uploads_rake_spec.rb
index 9330539f8c9..0c779d8a135 100644
--- a/spec/tasks/gitlab/uploads_rake_spec.rb
+++ b/spec/tasks/gitlab/uploads_rake_spec.rb
@@ -13,7 +13,7 @@ describe 'gitlab:uploads rake tasks' do
end
it 'errors out about missing files on the file system' do
- uploaded_file = create(:upload)
+ create(:upload)
expect { run_rake_task('gitlab:uploads:check') }.to output(/File does not exist on the file system/).to_stdout
end
--
cgit v1.2.1
From 9afb77b6d409ce385b872de430c561b0ee9ae29a Mon Sep 17 00:00:00 2001
From: Douglas Barbosa Alexandre
Date: Mon, 8 Jan 2018 19:43:53 -0200
Subject: Refactoring spec for the gitlab:uploads:check rake task
---
spec/tasks/gitlab/uploads_rake_spec.rb | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/spec/tasks/gitlab/uploads_rake_spec.rb b/spec/tasks/gitlab/uploads_rake_spec.rb
index 0c779d8a135..ac0005e51e0 100644
--- a/spec/tasks/gitlab/uploads_rake_spec.rb
+++ b/spec/tasks/gitlab/uploads_rake_spec.rb
@@ -2,14 +2,14 @@ require 'rake_helper'
describe 'gitlab:uploads rake tasks' do
describe 'check' do
+ let!(:upload) { create(:upload, path: Rails.root.join('spec/fixtures/banana_sample.gif')) }
+
before do
Rake.application.rake_require 'tasks/gitlab/uploads'
end
it 'outputs the integrity check for each uploaded file' do
- uploaded_file = create(:upload)
-
- expect { run_rake_task('gitlab:uploads:check') }.to output(/Checking file \(#{uploaded_file.id}\): #{Regexp.quote(uploaded_file.absolute_path)}/).to_stdout
+ expect { run_rake_task('gitlab:uploads:check') }.to output(/Checking file \(#{upload.id}\): #{Regexp.quote(upload.absolute_path)}/).to_stdout
end
it 'errors out about missing files on the file system' do
@@ -19,10 +19,9 @@ describe 'gitlab:uploads rake tasks' do
end
it 'errors out about invalid checksum' do
- uploaded_file = create(:upload, path: Rails.root.join('spec/fixtures/banana_sample.gif'))
- uploaded_file.update_column(:checksum, '01a3156db2cf4f67ec823680b40b7302f89ab39179124ad219f94919b8a1769e')
+ upload.update_column(:checksum, '01a3156db2cf4f67ec823680b40b7302f89ab39179124ad219f94919b8a1769e')
- expect { run_rake_task('gitlab:uploads:check') }.to output(/File checksum \(9e697aa09fe196909813ee36103e34f721fe47a5fdc8aac0e4e4ac47b9b38282\) does not match the one in the database \(#{uploaded_file.checksum}\)/).to_stdout
+ expect { run_rake_task('gitlab:uploads:check') }.to output(/File checksum \(9e697aa09fe196909813ee36103e34f721fe47a5fdc8aac0e4e4ac47b9b38282\) does not match the one in the database \(#{upload.checksum}\)/).to_stdout
end
end
end
--
cgit v1.2.1
From 4c1e1ab1d7da1716fd6db2111a5a7e37dac799cd Mon Sep 17 00:00:00 2001
From: Clement Ho
Date: Mon, 8 Jan 2018 21:55:28 +0000
Subject: Refactor dashboard todos inside dispatcher
---
app/assets/javascripts/dispatcher.js | 6 +-
.../pages/dashboard/todos/index/index.js | 3 +
.../pages/dashboard/todos/index/todos.js | 156 +++++++++++++++++++++
app/assets/javascripts/todos.js | 156 ---------------------
spec/javascripts/todos_spec.js | 2 +-
5 files changed, 163 insertions(+), 160 deletions(-)
create mode 100644 app/assets/javascripts/pages/dashboard/todos/index/index.js
create mode 100644 app/assets/javascripts/pages/dashboard/todos/index/todos.js
delete mode 100644 app/assets/javascripts/todos.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 42f61d33f6e..9e8b2acfe1b 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -56,7 +56,6 @@ import GfmAutoComplete from './gfm_auto_complete';
import ShortcutsBlob from './shortcuts_blob';
import SigninTabsMemoizer from './signin_tabs_memoizer';
import Star from './star';
-import Todos from './todos';
import TreeView from './tree';
import UsagePing from './usage_ping';
import UsernameValidator from './username_validator';
@@ -111,6 +110,7 @@ import Activities from './activities';
}
const fail = () => Flash('Error loading dynamic module');
+ const callDefault = m => m.default();
path = page.split(':');
shortcut_handler = null;
@@ -212,7 +212,7 @@ import Activities from './activities';
projectSelect();
break;
case 'dashboard:todos:index':
- new Todos();
+ import('./pages/dashboard/todos/index').then(callDefault).catch(fail);
break;
case 'dashboard:projects:index':
case 'dashboard:projects:starred':
@@ -542,7 +542,7 @@ import Activities from './activities';
new CILintEditor();
break;
case 'users:show':
- import('./pages/users/show').then(m => m.default()).catch(fail);
+ import('./pages/users/show').then(callDefault).catch(fail);
break;
case 'admin:conversational_development_index:show':
new UserCallout();
diff --git a/app/assets/javascripts/pages/dashboard/todos/index/index.js b/app/assets/javascripts/pages/dashboard/todos/index/index.js
new file mode 100644
index 00000000000..77c23685943
--- /dev/null
+++ b/app/assets/javascripts/pages/dashboard/todos/index/index.js
@@ -0,0 +1,3 @@
+import Todos from './todos';
+
+export default () => new Todos();
diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
new file mode 100644
index 00000000000..e976a3d2f1d
--- /dev/null
+++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
@@ -0,0 +1,156 @@
+/* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */
+import { visitUrl } from '~/lib/utils/url_utility';
+import UsersSelect from '~/users_select';
+import { isMetaClick } from '~/lib/utils/common_utils';
+
+export default class Todos {
+ constructor() {
+ this.initFilters();
+ this.bindEvents();
+ this.todo_ids = [];
+
+ this.cleanupWrapper = this.cleanup.bind(this);
+ document.addEventListener('beforeunload', this.cleanupWrapper);
+ }
+
+ cleanup() {
+ this.unbindEvents();
+ document.removeEventListener('beforeunload', this.cleanupWrapper);
+ }
+
+ unbindEvents() {
+ $('.js-done-todo, .js-undo-todo, .js-add-todo').off('click', this.updateRowStateClickedWrapper);
+ $('.js-todos-mark-all', '.js-todos-undo-all').off('click', this.updateallStateClickedWrapper);
+ $('.todo').off('click', this.goToTodoUrl);
+ }
+
+ bindEvents() {
+ this.updateRowStateClickedWrapper = this.updateRowStateClicked.bind(this);
+ this.updateAllStateClickedWrapper = this.updateAllStateClicked.bind(this);
+
+ $('.js-done-todo, .js-undo-todo, .js-add-todo').on('click', this.updateRowStateClickedWrapper);
+ $('.js-todos-mark-all, .js-todos-undo-all').on('click', this.updateAllStateClickedWrapper);
+ $('.todo').on('click', this.goToTodoUrl);
+ }
+
+ initFilters() {
+ this.initFilterDropdown($('.js-project-search'), 'project_id', ['text']);
+ this.initFilterDropdown($('.js-type-search'), 'type');
+ this.initFilterDropdown($('.js-action-search'), 'action_id');
+
+ return new UsersSelect();
+ }
+
+ initFilterDropdown($dropdown, fieldName, searchFields) {
+ $dropdown.glDropdown({
+ fieldName,
+ selectable: true,
+ filterable: searchFields ? true : false,
+ search: { fields: searchFields },
+ data: $dropdown.data('data'),
+ clicked: () => $dropdown.closest('form.filter-form').submit(),
+ });
+ }
+
+ updateRowStateClicked(e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ const target = e.target;
+ target.setAttribute('disabled', true);
+ target.classList.add('disabled');
+ $.ajax({
+ type: 'POST',
+ url: target.dataset.href,
+ dataType: 'json',
+ data: {
+ '_method': target.dataset.method,
+ },
+ success: (data) => {
+ this.updateRowState(target);
+ return this.updateBadges(data);
+ },
+ });
+ }
+
+ updateRowState(target) {
+ const row = target.closest('li');
+ const restoreBtn = row.querySelector('.js-undo-todo');
+ const doneBtn = row.querySelector('.js-done-todo');
+
+ target.classList.add('hidden');
+ target.removeAttribute('disabled');
+ target.classList.remove('disabled');
+
+ if (target === doneBtn) {
+ row.classList.add('done-reversible');
+ restoreBtn.classList.remove('hidden');
+ } else if (target === restoreBtn) {
+ row.classList.remove('done-reversible');
+ doneBtn.classList.remove('hidden');
+ } else {
+ row.parentNode.removeChild(row);
+ }
+ }
+
+ updateAllStateClicked(e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ const target = e.currentTarget;
+ const requestData = { '_method': target.dataset.method, ids: this.todo_ids };
+ target.setAttribute('disabled', true);
+ target.classList.add('disabled');
+ $.ajax({
+ type: 'POST',
+ url: target.dataset.href,
+ dataType: 'json',
+ data: requestData,
+ success: (data) => {
+ this.updateAllState(target, data);
+ return this.updateBadges(data);
+ },
+ });
+ }
+
+ updateAllState(target, data) {
+ const markAllDoneBtn = document.querySelector('.js-todos-mark-all');
+ const undoAllBtn = document.querySelector('.js-todos-undo-all');
+ const todoListContainer = document.querySelector('.js-todos-list-container');
+ const nothingHereContainer = document.querySelector('.js-nothing-here-container');
+
+ target.removeAttribute('disabled');
+ target.classList.remove('disabled');
+
+ this.todo_ids = (target === markAllDoneBtn) ? data.updated_ids : [];
+ undoAllBtn.classList.toggle('hidden');
+ markAllDoneBtn.classList.toggle('hidden');
+ todoListContainer.classList.toggle('hidden');
+ nothingHereContainer.classList.toggle('hidden');
+ }
+
+ updateBadges(data) {
+ $(document).trigger('todo:toggle', data.count);
+ document.querySelector('.todos-pending .badge').innerHTML = data.count;
+ document.querySelector('.todos-done .badge').innerHTML = data.done_count;
+ }
+
+ goToTodoUrl(e) {
+ const todoLink = this.dataset.url;
+
+ if (!todoLink || e.target.tagName === 'A' || e.target.tagName === 'IMG') {
+ return;
+ }
+
+ e.stopPropagation();
+ e.preventDefault();
+
+ if (isMetaClick(e)) {
+ const windowTarget = '_blank';
+
+ window.open(todoLink, windowTarget);
+ } else {
+ visitUrl(todoLink);
+ }
+ }
+}
diff --git a/app/assets/javascripts/todos.js b/app/assets/javascripts/todos.js
deleted file mode 100644
index 748caecf153..00000000000
--- a/app/assets/javascripts/todos.js
+++ /dev/null
@@ -1,156 +0,0 @@
-/* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */
-import { visitUrl } from './lib/utils/url_utility';
-import UsersSelect from './users_select';
-import { isMetaClick } from './lib/utils/common_utils';
-
-export default class Todos {
- constructor() {
- this.initFilters();
- this.bindEvents();
- this.todo_ids = [];
-
- this.cleanupWrapper = this.cleanup.bind(this);
- document.addEventListener('beforeunload', this.cleanupWrapper);
- }
-
- cleanup() {
- this.unbindEvents();
- document.removeEventListener('beforeunload', this.cleanupWrapper);
- }
-
- unbindEvents() {
- $('.js-done-todo, .js-undo-todo, .js-add-todo').off('click', this.updateRowStateClickedWrapper);
- $('.js-todos-mark-all', '.js-todos-undo-all').off('click', this.updateallStateClickedWrapper);
- $('.todo').off('click', this.goToTodoUrl);
- }
-
- bindEvents() {
- this.updateRowStateClickedWrapper = this.updateRowStateClicked.bind(this);
- this.updateAllStateClickedWrapper = this.updateAllStateClicked.bind(this);
-
- $('.js-done-todo, .js-undo-todo, .js-add-todo').on('click', this.updateRowStateClickedWrapper);
- $('.js-todos-mark-all, .js-todos-undo-all').on('click', this.updateAllStateClickedWrapper);
- $('.todo').on('click', this.goToTodoUrl);
- }
-
- initFilters() {
- this.initFilterDropdown($('.js-project-search'), 'project_id', ['text']);
- this.initFilterDropdown($('.js-type-search'), 'type');
- this.initFilterDropdown($('.js-action-search'), 'action_id');
-
- return new UsersSelect();
- }
-
- initFilterDropdown($dropdown, fieldName, searchFields) {
- $dropdown.glDropdown({
- fieldName,
- selectable: true,
- filterable: searchFields ? true : false,
- search: { fields: searchFields },
- data: $dropdown.data('data'),
- clicked: () => $dropdown.closest('form.filter-form').submit(),
- });
- }
-
- updateRowStateClicked(e) {
- e.stopPropagation();
- e.preventDefault();
-
- const target = e.target;
- target.setAttribute('disabled', true);
- target.classList.add('disabled');
- $.ajax({
- type: 'POST',
- url: target.dataset.href,
- dataType: 'json',
- data: {
- '_method': target.dataset.method,
- },
- success: (data) => {
- this.updateRowState(target);
- return this.updateBadges(data);
- },
- });
- }
-
- updateRowState(target) {
- const row = target.closest('li');
- const restoreBtn = row.querySelector('.js-undo-todo');
- const doneBtn = row.querySelector('.js-done-todo');
-
- target.classList.add('hidden');
- target.removeAttribute('disabled');
- target.classList.remove('disabled');
-
- if (target === doneBtn) {
- row.classList.add('done-reversible');
- restoreBtn.classList.remove('hidden');
- } else if (target === restoreBtn) {
- row.classList.remove('done-reversible');
- doneBtn.classList.remove('hidden');
- } else {
- row.parentNode.removeChild(row);
- }
- }
-
- updateAllStateClicked(e) {
- e.stopPropagation();
- e.preventDefault();
-
- const target = e.currentTarget;
- const requestData = { '_method': target.dataset.method, ids: this.todo_ids };
- target.setAttribute('disabled', true);
- target.classList.add('disabled');
- $.ajax({
- type: 'POST',
- url: target.dataset.href,
- dataType: 'json',
- data: requestData,
- success: (data) => {
- this.updateAllState(target, data);
- return this.updateBadges(data);
- },
- });
- }
-
- updateAllState(target, data) {
- const markAllDoneBtn = document.querySelector('.js-todos-mark-all');
- const undoAllBtn = document.querySelector('.js-todos-undo-all');
- const todoListContainer = document.querySelector('.js-todos-list-container');
- const nothingHereContainer = document.querySelector('.js-nothing-here-container');
-
- target.removeAttribute('disabled');
- target.classList.remove('disabled');
-
- this.todo_ids = (target === markAllDoneBtn) ? data.updated_ids : [];
- undoAllBtn.classList.toggle('hidden');
- markAllDoneBtn.classList.toggle('hidden');
- todoListContainer.classList.toggle('hidden');
- nothingHereContainer.classList.toggle('hidden');
- }
-
- updateBadges(data) {
- $(document).trigger('todo:toggle', data.count);
- document.querySelector('.todos-pending .badge').innerHTML = data.count;
- document.querySelector('.todos-done .badge').innerHTML = data.done_count;
- }
-
- goToTodoUrl(e) {
- const todoLink = this.dataset.url;
-
- if (!todoLink || e.target.tagName === 'A' || e.target.tagName === 'IMG') {
- return;
- }
-
- e.stopPropagation();
- e.preventDefault();
-
- if (isMetaClick(e)) {
- const windowTarget = '_blank';
-
- window.open(todoLink, windowTarget);
- } else {
- visitUrl(todoLink);
- }
- }
-}
diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js
index 59e16f0786e..35871dddf89 100644
--- a/spec/javascripts/todos_spec.js
+++ b/spec/javascripts/todos_spec.js
@@ -1,5 +1,5 @@
import * as urlUtils from '~/lib/utils/url_utility';
-import Todos from '~/todos';
+import Todos from '~/pages/dashboard/todos/index/todos';
import '~/lib/utils/common_utils';
describe('Todos', () => {
--
cgit v1.2.1
From 0d85e1b4785e566ed5b02c9dda69f8a750aa9c57 Mon Sep 17 00:00:00 2001
From: Annabel Dunstone Gray
Date: Mon, 8 Jan 2018 15:04:33 -0700
Subject: Change max-height of all dropdowns to 312px
---
app/assets/stylesheets/framework/dropdowns.scss | 4 +++-
app/assets/stylesheets/framework/filters.scss | 2 +-
app/assets/stylesheets/framework/variables.scss | 3 ++-
app/assets/stylesheets/pages/pipelines.scss | 2 +-
app/assets/stylesheets/pages/projects.scss | 7 -------
5 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index bc907a390d8..d1b3754d4ef 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -28,7 +28,9 @@
.dropdown-menu,
.dropdown-menu-nav {
@include set-visible;
- min-height: 40px;
+ min-height: $dropdown-min-height;
+ max-height: $dropdown-max-height;
+ overflow: auto;
@media (max-width: $screen-xs-max) {
width: 100%;
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 2d7465401f1..621a4adc0cb 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -260,7 +260,7 @@
}
.filtered-search-input-dropdown-menu {
- max-height: 260px;
+ max-height: $dropdown-max-height;
max-width: 280px;
overflow: auto;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index f7853909f56..ef1520f1f63 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -334,7 +334,8 @@ $regular_font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-San
* Dropdowns
*/
$dropdown-width: 300px;
-$dropdown-max-height: 215px;
+$dropdown-min-height: 40px;
+$dropdown-max-height: 312px;
$dropdown-vertical-offset: 4px;
$dropdown-link-color: #555;
$dropdown-link-hover-bg: $row-hover;
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 05c1033c5f7..b375d19a848 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -48,7 +48,7 @@
}
.dropdown-menu {
- max-height: 250px;
+ max-height: $dropdown-max-height;
overflow-y: auto;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 6f4c678c4b8..61a76d0387a 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -322,13 +322,6 @@
}
}
-.project-repo-buttons {
- .project-action-button .dropdown-menu {
- max-height: 250px;
- overflow-y: auto;
- }
-}
-
.split-one {
display: inline-table;
margin-right: 12px;
--
cgit v1.2.1
From a9a858e0200cab8009fe17acee58dcb7aecb6c8e Mon Sep 17 00:00:00 2001
From: Jacob Schatz
Date: Mon, 8 Jan 2018 17:40:12 -0500
Subject: Fix `projects:a*` refactor for dispatcher
---
app/assets/javascripts/dispatcher.js | 6 ++++--
app/assets/javascripts/pages/projects/activity/index.js | 7 +++++++
2 files changed, 11 insertions(+), 2 deletions(-)
create mode 100644 app/assets/javascripts/pages/projects/activity/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 9e8b2acfe1b..edfc9088d9a 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -357,8 +357,10 @@ import Activities from './activities';
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break;
case 'projects:activity':
- new Activities();
- shortcut_handler = new ShortcutsNavigation();
+ import('./pages/projects/activity')
+ .then(callDefault)
+ .catch(fail);
+ shortcut_handler = true;
break;
case 'projects:commits:show':
CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
diff --git a/app/assets/javascripts/pages/projects/activity/index.js b/app/assets/javascripts/pages/projects/activity/index.js
new file mode 100644
index 00000000000..7af95127fd5
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/activity/index.js
@@ -0,0 +1,7 @@
+import Activities from '~/activities';
+import ShortcutsNavigation from '~/shortcuts_navigation';
+
+export default function () {
+ new Activities(); // eslint-disable-line no-new
+ new ShortcutsNavigation(); // eslint-disable-line no-new
+}
--
cgit v1.2.1
From 2bd4453ca2c4bec527a264194cf12d164cd31ed7 Mon Sep 17 00:00:00 2001
From: Jacob Schatz
Date: Mon, 8 Jan 2018 18:08:32 -0500
Subject: Fix eslint
---
app/assets/javascripts/dispatcher.js | 14 ++++++--------
app/assets/javascripts/pages/explore/groups/index.js | 6 +++---
app/assets/javascripts/pages/explore/projects/index.js | 4 ++--
3 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index f7421ea415d..11ec667fc07 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -38,12 +38,10 @@ import BindInOut from './behaviors/bind_in_out';
import SecretValues from './behaviors/secret_values';
import DeleteModal from './branches/branches_delete_modal';
import Group from './group';
-import GroupsList from './groups_list';
import ProjectsList from './projects_list';
import setupProjectEdit from './project_edit';
import MiniPipelineGraph from './mini_pipeline_graph_dropdown';
import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater';
-import Landing from './landing';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import UserCallout from './user_callout';
import ShortcutsWiki from './shortcuts_wiki';
@@ -218,7 +216,7 @@ import Activities from './activities';
case 'explore:projects:trending':
case 'explore:projects:starred':
import('./pages/explore/projects')
- .then(module => module.default())
+ .then(callDefault)
.catch(fail);
break;
case 'dashboard:projects:index':
@@ -228,7 +226,7 @@ import Activities from './activities';
break;
case 'explore:groups:index':
import('./pages/explore/groups')
- .then(module => module.default())
+ .then(callDefault)
.catch(fail);
break;
case 'projects:milestones:new':
@@ -498,8 +496,8 @@ import Activities from './activities';
break;
case 'projects:forks:new':
import(/* webpackChunkName: 'project_fork' */ './project_fork')
- .then(fork => fork.default())
- .catch(() => {});
+ .then(callDefault)
+ .catch(fail);
break;
case 'projects:artifacts:browse':
new ShortcutsNavigation();
@@ -635,8 +633,8 @@ import Activities from './activities';
shortcut_handler = new ShortcutsNavigation();
new ProjectNew();
import(/* webpackChunkName: 'project_permissions' */ './projects/permissions')
- .then(permissions => permissions.default())
- .catch(() => {});
+ .then(callDefault)
+ .catch(fail);
break;
case 'new':
new ProjectNew();
diff --git a/app/assets/javascripts/pages/explore/groups/index.js b/app/assets/javascripts/pages/explore/groups/index.js
index 6515202a31b..859b073f1cb 100644
--- a/app/assets/javascripts/pages/explore/groups/index.js
+++ b/app/assets/javascripts/pages/explore/groups/index.js
@@ -1,14 +1,14 @@
import GroupsList from '~/groups_list';
import Landing from '~/landing';
-export default function() {
- new GroupsList();
+export default function () {
+ new GroupsList(); // eslint-disable-line no-new
const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) return;
const exploreGroupsLanding = new Landing(
landingElement,
landingElement.querySelector('.dismiss-button'),
- 'explore_groups_landing_dismissed'
+ 'explore_groups_landing_dismissed',
);
exploreGroupsLanding.toggle();
}
diff --git a/app/assets/javascripts/pages/explore/projects/index.js b/app/assets/javascripts/pages/explore/projects/index.js
index 2259cb7a5cf..93acb54d4f1 100644
--- a/app/assets/javascripts/pages/explore/projects/index.js
+++ b/app/assets/javascripts/pages/explore/projects/index.js
@@ -1,5 +1,5 @@
import ProjectsList from '~/projects_list';
-export default function() {
- new ProjectsList();
+export default function () {
+ new ProjectsList(); // eslint-disable-line no-new
}
--
cgit v1.2.1
From ad1a9817dc7a94c0c5e1169eaf3da4b75d90326f Mon Sep 17 00:00:00 2001
From: Clement Ho
Date: Mon, 8 Jan 2018 17:49:31 -0600
Subject: Refactor dashboard issues
---
app/assets/javascripts/dispatcher.js | 2 ++
app/assets/javascripts/pages/dashboard/issues/index.js | 7 +++++++
2 files changed, 9 insertions(+)
create mode 100644 app/assets/javascripts/pages/dashboard/issues/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 9e8b2acfe1b..a353910d7cb 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -199,6 +199,8 @@ import Activities from './activities';
new Sidebar();
break;
case 'dashboard:issues':
+ import('./pages/dashboard/issues').then(callDefault).catch(fail);
+ break;
case 'dashboard:merge_requests':
projectSelect();
initLegacyFilters();
diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js
new file mode 100644
index 00000000000..06c304afb86
--- /dev/null
+++ b/app/assets/javascripts/pages/dashboard/issues/index.js
@@ -0,0 +1,7 @@
+import projectSelect from '~/project_select';
+import initLegacyFilters from '~/init_legacy_filters';
+
+export default () => {
+ projectSelect();
+ initLegacyFilters();
+}
--
cgit v1.2.1
From 0dd4041feec6f405719afa405868ddee4b5c1ae3 Mon Sep 17 00:00:00 2001
From: Clement Ho
Date: Mon, 8 Jan 2018 18:29:20 -0600
Subject: Fix eslint
---
app/assets/javascripts/pages/dashboard/issues/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js
index 06c304afb86..b7353669e65 100644
--- a/app/assets/javascripts/pages/dashboard/issues/index.js
+++ b/app/assets/javascripts/pages/dashboard/issues/index.js
@@ -4,4 +4,4 @@ import initLegacyFilters from '~/init_legacy_filters';
export default () => {
projectSelect();
initLegacyFilters();
-}
+};
--
cgit v1.2.1
From 365c0c6371896aecb5713ba40aa9e87a29b3b7d5 Mon Sep 17 00:00:00 2001
From: Clement Ho
Date: Tue, 9 Jan 2018 01:06:27 +0000
Subject: Improve table pagination spec
---
spec/javascripts/vue_shared/components/table_pagination_spec.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/javascripts/vue_shared/components/table_pagination_spec.js b/spec/javascripts/vue_shared/components/table_pagination_spec.js
index 1465ef5855f..b3b5dd1d10a 100644
--- a/spec/javascripts/vue_shared/components/table_pagination_spec.js
+++ b/spec/javascripts/vue_shared/components/table_pagination_spec.js
@@ -32,7 +32,7 @@ describe('Pagination component', () => {
change: spy,
});
- expect(component.$el.innerHTML).not.toBeDefined();
+ expect(component.$el.childNodes.length).toEqual(0);
});
describe('prev button', () => {
--
cgit v1.2.1
From 3ef346bce93c624ef069949286127a9403b49ad6 Mon Sep 17 00:00:00 2001
From: Jacob Schatz
Date: Mon, 8 Jan 2018 20:31:27 -0500
Subject: Finishes dispatcher `projects:a*` stuff.
---
app/assets/javascripts/dispatcher.js | 13 ++++++++-----
.../javascripts/pages/projects/artifacts/browse/index.js | 7 +++++++
.../javascripts/pages/projects/artifacts/file/index.js | 7 +++++++
3 files changed, 22 insertions(+), 5 deletions(-)
create mode 100644 app/assets/javascripts/pages/projects/artifacts/browse/index.js
create mode 100644 app/assets/javascripts/pages/projects/artifacts/file/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index edfc9088d9a..fe59bcbd477 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -12,7 +12,6 @@ import notificationsDropdown from './notifications_dropdown';
import groupAvatar from './group_avatar';
import GroupLabelSubscription from './group_label_subscription';
import LineHighlighter from './line_highlighter';
-import BuildArtifacts from './build_artifacts';
import CILintEditor from './ci_lint_editor';
import groupsSelect from './groups_select';
import Search from './search';
@@ -506,12 +505,16 @@ import Activities from './activities';
.catch(() => {});
break;
case 'projects:artifacts:browse':
- new ShortcutsNavigation();
- new BuildArtifacts();
+ import('./pages/projects/artifacts/browse')
+ .then(callDefault)
+ .catch(fail);
+ shortcut_handler = true;
break;
case 'projects:artifacts:file':
- new ShortcutsNavigation();
- new BlobViewer();
+ import('./pages/projects/artifacts/file')
+ .then(callDefault)
+ .catch(fail);
+ shortcut_handler = true;
break;
case 'help:index':
VersionCheckImage.bindErrorEvent($('img.js-version-status-badge'));
diff --git a/app/assets/javascripts/pages/projects/artifacts/browse/index.js b/app/assets/javascripts/pages/projects/artifacts/browse/index.js
new file mode 100644
index 00000000000..02456071086
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/artifacts/browse/index.js
@@ -0,0 +1,7 @@
+import BuildArtifacts from '~/build_artifacts';
+import ShortcutsNavigation from '~/shortcuts_navigation';
+
+export default function () {
+ new ShortcutsNavigation(); // eslint-disable-line no-new
+ new BuildArtifacts(); // eslint-disable-line no-new
+}
diff --git a/app/assets/javascripts/pages/projects/artifacts/file/index.js b/app/assets/javascripts/pages/projects/artifacts/file/index.js
new file mode 100644
index 00000000000..4cd67ac76e3
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/artifacts/file/index.js
@@ -0,0 +1,7 @@
+import BlobViewer from '~/blob/viewer/index';
+import ShortcutsNavigation from '~/shortcuts_navigation';
+
+export default function () {
+ new ShortcutsNavigation(); // eslint-disable-line no-new
+ new BlobViewer(); // eslint-disable-line no-new
+}
--
cgit v1.2.1
From eaf9088ba8abe8c847a09860b55a86c7ae0d5987 Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Sat, 6 Jan 2018 00:41:13 -0800
Subject: Save user ID and username in Grape API log (api_json.log)
This will enable admins to identify who actually made the API request.
Relates to #36960
---
changelogs/unreleased/sh-store-user-in-api-logs.yml | 5 +++++
lib/api/api.rb | 3 ++-
lib/api/helpers.rb | 7 +++++++
lib/gitlab/grape_logging/loggers/user_logger.rb | 18 ++++++++++++++++++
spec/requests/api/helpers_spec.rb | 6 ++++++
5 files changed, 38 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/sh-store-user-in-api-logs.yml
create mode 100644 lib/gitlab/grape_logging/loggers/user_logger.rb
diff --git a/changelogs/unreleased/sh-store-user-in-api-logs.yml b/changelogs/unreleased/sh-store-user-in-api-logs.yml
new file mode 100644
index 00000000000..d904dcaf6d3
--- /dev/null
+++ b/changelogs/unreleased/sh-store-user-in-api-logs.yml
@@ -0,0 +1,5 @@
+---
+title: Save user ID and username in Grape API log (api_json.log)
+merge_request:
+author:
+type: changed
diff --git a/lib/api/api.rb b/lib/api/api.rb
index e0d14281c96..ae161efb358 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -13,7 +13,8 @@ module API
formatter: Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new,
include: [
GrapeLogging::Loggers::FilterParameters.new,
- GrapeLogging::Loggers::ClientEnv.new
+ GrapeLogging::Loggers::ClientEnv.new,
+ Gitlab::GrapeLogging::Loggers::UserLogger.new
]
allow_access_with_scope :api
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index bf388163ec8..d6ce368efd5 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -5,6 +5,7 @@ module API
SUDO_HEADER = "HTTP_SUDO".freeze
SUDO_PARAM = :sudo
+ API_USER_ENV = 'gitlab.api.user'.freeze
def declared_params(options = {})
options = { include_parent_namespaces: false }.merge(options)
@@ -48,10 +49,16 @@ module API
validate_access_token!(scopes: scopes_registered_for_endpoint) unless sudo?
+ save_current_user_in_env(@current_user) if @current_user
+
@current_user
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
+ def save_current_user_in_env(user)
+ env[API_USER_ENV] = { user_id: user.id, username: user.username }
+ end
+
def sudo?
initial_current_user != current_user
end
diff --git a/lib/gitlab/grape_logging/loggers/user_logger.rb b/lib/gitlab/grape_logging/loggers/user_logger.rb
new file mode 100644
index 00000000000..fa172861967
--- /dev/null
+++ b/lib/gitlab/grape_logging/loggers/user_logger.rb
@@ -0,0 +1,18 @@
+# This grape_logging module (https://github.com/aserafin/grape_logging) makes it
+# possible to log the user who performed the Grape API action by retrieving
+# the user context from the request environment.
+module Gitlab
+ module GrapeLogging
+ module Loggers
+ class UserLogger < ::GrapeLogging::Loggers::Base
+ def parameters(request, _)
+ params = request.env[::API::Helpers::API_USER_ENV]
+
+ return {} unless params
+
+ params.slice(:user_id, :username)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 0462f494e15..837389451e8 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -68,6 +68,12 @@ describe API::Helpers do
end
it { is_expected.to eq(user) }
+
+ it 'sets the environment with data of the current user' do
+ subject
+
+ expect(env[API::Helpers::API_USER_ENV]).to eq({ user_id: subject.id, username: subject.username })
+ end
end
context "HEAD request" do
--
cgit v1.2.1
From 89fd16262d1fd3d986003a29a9171d3b84f2c522 Mon Sep 17 00:00:00 2001
From: Phil Hughes
Date: Mon, 8 Jan 2018 14:26:42 +0000
Subject: Added import for snippets:show in dispatcher
#41341
---
app/assets/javascripts/dispatcher.js | 5 +----
app/assets/javascripts/pages/snippets/show/index.js | 12 ++++++++++++
2 files changed, 13 insertions(+), 4 deletions(-)
create mode 100644 app/assets/javascripts/pages/snippets/show/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 9e8b2acfe1b..767705517a7 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -548,10 +548,7 @@ import Activities from './activities';
new UserCallout();
break;
case 'snippets:show':
- new LineHighlighter();
- new BlobViewer();
- initNotes();
- new ZenMode();
+ import('./pages/snippets/show').then(m => m.default()).catch(fail);
break;
case 'import:fogbugz:new_user_map':
new UsersSelect();
diff --git a/app/assets/javascripts/pages/snippets/show/index.js b/app/assets/javascripts/pages/snippets/show/index.js
new file mode 100644
index 00000000000..04c9562bfbb
--- /dev/null
+++ b/app/assets/javascripts/pages/snippets/show/index.js
@@ -0,0 +1,12 @@
+/* eslint-disable no-new */
+import LineHighlighter from '../../../line_highlighter';
+import BlobViewer from '../../../blob/viewer';
+import ZenMode from '../../../zen_mode';
+import initNotes from '../../../init_notes';
+
+export default () => {
+ new LineHighlighter();
+ new BlobViewer();
+ initNotes();
+ new ZenMode();
+};
--
cgit v1.2.1
From 506717d0cae67f58bf6e590b7122fd6e8b13a406 Mon Sep 17 00:00:00 2001
From: Phil Hughes
Date: Mon, 8 Jan 2018 14:29:00 +0000
Subject: Added ci:lints import to dispatcher
---
app/assets/javascripts/ci_lint_editor.js | 12 ------------
app/assets/javascripts/dispatcher.js | 3 +--
app/assets/javascripts/pages/ci/lints/ci_lint_editor.js | 12 ++++++++++++
app/assets/javascripts/pages/ci/lints/index.js | 3 +++
4 files changed, 16 insertions(+), 14 deletions(-)
delete mode 100644 app/assets/javascripts/ci_lint_editor.js
create mode 100644 app/assets/javascripts/pages/ci/lints/ci_lint_editor.js
create mode 100644 app/assets/javascripts/pages/ci/lints/index.js
diff --git a/app/assets/javascripts/ci_lint_editor.js b/app/assets/javascripts/ci_lint_editor.js
deleted file mode 100644
index b9469e5b7cb..00000000000
--- a/app/assets/javascripts/ci_lint_editor.js
+++ /dev/null
@@ -1,12 +0,0 @@
-export default class CILintEditor {
- constructor() {
- this.editor = window.ace.edit('ci-editor');
- this.textarea = document.querySelector('#content');
-
- this.editor.getSession().setMode('ace/mode/yaml');
- this.editor.on('input', () => {
- const content = this.editor.getSession().getValue();
- this.textarea.value = content;
- });
- }
-}
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 767705517a7..f9e37926509 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -13,7 +13,6 @@ import groupAvatar from './group_avatar';
import GroupLabelSubscription from './group_label_subscription';
import LineHighlighter from './line_highlighter';
import BuildArtifacts from './build_artifacts';
-import CILintEditor from './ci_lint_editor';
import groupsSelect from './groups_select';
import Search from './search';
import initAdmin from './admin';
@@ -539,7 +538,7 @@ import Activities from './activities';
break;
case 'ci:lints:create':
case 'ci:lints:show':
- new CILintEditor();
+ import('./pages/ci/lints').then(m => m.default()).catch(fail);
break;
case 'users:show':
import('./pages/users/show').then(callDefault).catch(fail);
diff --git a/app/assets/javascripts/pages/ci/lints/ci_lint_editor.js b/app/assets/javascripts/pages/ci/lints/ci_lint_editor.js
new file mode 100644
index 00000000000..b9469e5b7cb
--- /dev/null
+++ b/app/assets/javascripts/pages/ci/lints/ci_lint_editor.js
@@ -0,0 +1,12 @@
+export default class CILintEditor {
+ constructor() {
+ this.editor = window.ace.edit('ci-editor');
+ this.textarea = document.querySelector('#content');
+
+ this.editor.getSession().setMode('ace/mode/yaml');
+ this.editor.on('input', () => {
+ const content = this.editor.getSession().getValue();
+ this.textarea.value = content;
+ });
+ }
+}
diff --git a/app/assets/javascripts/pages/ci/lints/index.js b/app/assets/javascripts/pages/ci/lints/index.js
new file mode 100644
index 00000000000..5cc66546109
--- /dev/null
+++ b/app/assets/javascripts/pages/ci/lints/index.js
@@ -0,0 +1,3 @@
+import CILintEditor from './ci_lint_editor';
+
+export default () => new CILintEditor();
--
cgit v1.2.1
From 90d4d9b5f5c3a2d90a5c1c28dfe45b6887f299f5 Mon Sep 17 00:00:00 2001
From: Phil Hughes
Date: Mon, 8 Jan 2018 14:31:39 +0000
Subject: Added import:fogbugz:new_user_map import to dispatcher
---
app/assets/javascripts/dispatcher.js | 2 +-
app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index f9e37926509..816fbb5b98e 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -550,7 +550,7 @@ import Activities from './activities';
import('./pages/snippets/show').then(m => m.default()).catch(fail);
break;
case 'import:fogbugz:new_user_map':
- new UsersSelect();
+ import('./pages/import/fogbugz/new_user_map').then(m => m.default()).catch(fail);
break;
case 'profiles:personal_access_tokens:index':
case 'admin:impersonation_tokens:index':
diff --git a/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js b/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js
new file mode 100644
index 00000000000..5defea104d4
--- /dev/null
+++ b/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js
@@ -0,0 +1,3 @@
+import UsersSelect from '../../../../users_select';
+
+export default () => new UsersSelect();
--
cgit v1.2.1
From 2f86f64f3481947c534ab5840e3cecdd6b317671 Mon Sep 17 00:00:00 2001
From: Phil Hughes
Date: Mon, 8 Jan 2018 14:34:39 +0000
Subject: Added admin:conversational_development_index:show import to
dispatcher
---
app/assets/javascripts/dispatcher.js | 2 +-
.../pages/admin/conversational_development_index/show/index.js | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 app/assets/javascripts/pages/admin/conversational_development_index/show/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 816fbb5b98e..1f554be6046 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -544,7 +544,7 @@ import Activities from './activities';
import('./pages/users/show').then(callDefault).catch(fail);
break;
case 'admin:conversational_development_index:show':
- new UserCallout();
+ import('./pages/admin/conversational_development_index/show').then(m => m.default()).catch(fail);
break;
case 'snippets:show':
import('./pages/snippets/show').then(m => m.default()).catch(fail);
diff --git a/app/assets/javascripts/pages/admin/conversational_development_index/show/index.js b/app/assets/javascripts/pages/admin/conversational_development_index/show/index.js
new file mode 100644
index 00000000000..6e66ef69fe1
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/conversational_development_index/show/index.js
@@ -0,0 +1,3 @@
+import UserCallout from '../../../../user_callout';
+
+export default () => new UserCallout();
--
cgit v1.2.1
From d222bcc9320598fbfedba6106a59a8371ac51746 Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Tue, 9 Jan 2018 08:53:27 +0000
Subject: Resolve "Install dev dependencies as devDependencies instead of
dependencies"
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 1f83f62e7f7..5b9b90f0e77 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,6 @@
"dependencies": {
"autosize": "^4.0.0",
"axios": "^0.17.1",
- "axios-mock-adapter": "^1.10.0",
"babel-core": "^6.26.0",
"babel-eslint": "^8.0.2",
"babel-loader": "^7.1.2",
@@ -89,6 +88,7 @@
},
"devDependencies": {
"@gitlab-org/gitlab-svgs": "^1.5.0",
+ "axios-mock-adapter": "^1.10.0",
"babel-plugin-istanbul": "^4.1.5",
"eslint": "^3.10.1",
"eslint-config-airbnb-base": "^10.0.1",
--
cgit v1.2.1
From 4b945e2845cf40456ef71faafbce181f0e60dba7 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Tue, 9 Jan 2018 10:02:55 +0100
Subject: Make it possible to define a QA-specific page element
---
qa/qa/page/element.rb | 19 ++++++++++---------
qa/qa/page/view.rb | 2 +-
qa/spec/page/element_spec.rb | 21 ++++++++++++---------
3 files changed, 23 insertions(+), 19 deletions(-)
diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb
index 173fdbf6d36..af93a575cb6 100644
--- a/qa/qa/page/element.rb
+++ b/qa/qa/page/element.rb
@@ -3,21 +3,22 @@ module QA
class Element
attr_reader :name
- def initialize(name, pattern)
+ def initialize(name, pattern = nil)
@name = name
- @pattern = pattern
+ @pattern = pattern || "qa-#{@name.to_s.gsub('_', '-')}"
end
- def matches?(line)
- case @pattern
- when Regexp
- !!(line =~ @pattern)
- when String
- line.include?(@pattern)
+ def expression
+ if @pattern.is_a?(String)
+ @_regexp ||= Regexp.new(Regexp.escape(@pattern))
else
- raise ArgumentError, 'Pattern should be either String or Regexp!'
+ @pattern
end
end
+
+ def matches?(line)
+ !!(line =~ expression)
+ end
end
end
end
diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb
index fa0ed8be9d9..47658144783 100644
--- a/qa/qa/page/view.rb
+++ b/qa/qa/page/view.rb
@@ -46,7 +46,7 @@ module QA
@elements = []
end
- def element(name, pattern)
+ def element(name, pattern = nil)
@elements.push(Page::Element.new(name, pattern))
end
end
diff --git a/qa/spec/page/element_spec.rb b/qa/spec/page/element_spec.rb
index 238c4d1ac66..c665267b90e 100644
--- a/qa/spec/page/element_spec.rb
+++ b/qa/spec/page/element_spec.rb
@@ -2,11 +2,11 @@ describe QA::Page::Element do
context 'when pattern is an expression' do
subject { described_class.new(:something, /button 'Sign in'/) }
- it 'is correctly matches against a string' do
+ it 'matches when there is a match' do
expect(subject.matches?("button 'Sign in'")).to be true
end
- it 'does not match if string does not match against a pattern' do
+ it 'does not match if pattern is not present' do
expect(subject.matches?("button 'Sign out'")).to be false
end
end
@@ -14,21 +14,24 @@ describe QA::Page::Element do
context 'when pattern is a string' do
subject { described_class.new(:something, 'button') }
- it 'is correctly matches against a string' do
+ it 'matches when there is match' do
expect(subject.matches?('some button in the view')).to be true
end
- it 'does not match if string does not match against a pattern' do
+ it 'does not match if pattern is not present' do
expect(subject.matches?('text_field :name')).to be false
end
end
- context 'when pattern is not supported' do
- subject { described_class.new(:something, [/something/]) }
+ context 'when pattern is not provided' do
+ subject { described_class.new(:some_name) }
- it 'raises an error' do
- expect { subject.matches?('some line') }
- .to raise_error ArgumentError
+ it 'matches when QA specific selector is present' do
+ expect(subject.matches?('some qa-some-name selector')).to be true
+ end
+
+ it 'does not match if QA selector is not there' do
+ expect(subject.matches?('some_name selector')).to be false
end
end
end
--
cgit v1.2.1
From 7114faf1edb554c00d151ec9144f794d1dae0e9e Mon Sep 17 00:00:00 2001
From: Jacob Schatz
Date: Tue, 9 Jan 2018 09:08:11 +0000
Subject: Remove preview_markdown from the global obj
---
app/assets/javascripts/behaviors/index.js | 1 +
app/assets/javascripts/main.js | 1 -
app/assets/javascripts/preview_markdown.js | 364 ++++++++++++++---------------
3 files changed, 182 insertions(+), 184 deletions(-)
diff --git a/app/assets/javascripts/behaviors/index.js b/app/assets/javascripts/behaviors/index.js
index 34e905222b4..8d021de7998 100644
--- a/app/assets/javascripts/behaviors/index.js
+++ b/app/assets/javascripts/behaviors/index.js
@@ -7,6 +7,7 @@ import installGlEmojiElement from './gl_emoji';
import './quick_submit';
import './requires_input';
import './toggler_behavior';
+import '../preview_markdown';
installGlEmojiElement();
initCopyAsGFM();
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 59bfa482bb0..ce6f91439b4 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -46,7 +46,6 @@ import LazyLoader from './lazy_loader';
import './line_highlighter';
import initLogoAnimation from './logo';
import './milestone_select';
-import './preview_markdown';
import './projects_dropdown';
import './render_gfm';
import initBreadcrumbs from './breadcrumb';
diff --git a/app/assets/javascripts/preview_markdown.js b/app/assets/javascripts/preview_markdown.js
index ffaafb3ee9e..86c7b56198d 100644
--- a/app/assets/javascripts/preview_markdown.js
+++ b/app/assets/javascripts/preview_markdown.js
@@ -6,195 +6,193 @@
// (including the explanation of quick actions), and showing a warning when
// more than `x` users are referenced.
//
-(function () {
- var lastTextareaPreviewed;
- var lastTextareaHeight = null;
- var markdownPreview;
- var previewButtonSelector;
- var writeButtonSelector;
-
- window.MarkdownPreview = (function () {
- function MarkdownPreview() {}
-
- // Minimum number of users referenced before triggering a warning
- MarkdownPreview.prototype.referenceThreshold = 10;
- MarkdownPreview.prototype.emptyMessage = 'Nothing to preview.';
-
- MarkdownPreview.prototype.ajaxCache = {};
-
- MarkdownPreview.prototype.showPreview = function ($form) {
- var mdText;
- var preview = $form.find('.js-md-preview');
- var url = preview.data('url');
- if (preview.hasClass('md-preview-loading')) {
- return;
- }
- mdText = $form.find('textarea.markdown-area').val();
-
- if (mdText.trim().length === 0) {
- preview.text(this.emptyMessage);
- this.hideReferencedUsers($form);
- } else {
- preview.addClass('md-preview-loading').text('Loading...');
- this.fetchMarkdownPreview(mdText, url, (function (response) {
- var body;
- if (response.body.length > 0) {
- body = response.body;
- } else {
- body = this.emptyMessage;
- }
-
- preview.removeClass('md-preview-loading').html(body);
- preview.renderGFM();
- this.renderReferencedUsers(response.references.users, $form);
-
- if (response.references.commands) {
- this.renderReferencedCommands(response.references.commands, $form);
- }
- }).bind(this));
- }
- };
- MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) {
- if (!url) {
- return;
- }
- if (text === this.ajaxCache.text) {
- success(this.ajaxCache.response);
- return;
- }
- $.ajax({
- type: 'POST',
- url: url,
- data: {
- text: text
- },
- dataType: 'json',
- success: (function (response) {
- this.ajaxCache = {
- text: text,
- response: response
- };
- success(response);
- }).bind(this)
- });
- };
-
- MarkdownPreview.prototype.hideReferencedUsers = function ($form) {
- $form.find('.referenced-users').hide();
- };
-
- MarkdownPreview.prototype.renderReferencedUsers = function (users, $form) {
- var referencedUsers;
- referencedUsers = $form.find('.referenced-users');
- if (referencedUsers.length) {
- if (users.length >= this.referenceThreshold) {
- referencedUsers.show();
- referencedUsers.find('.js-referenced-users-count').text(users.length);
- } else {
- referencedUsers.hide();
- }
- }
- };
-
- MarkdownPreview.prototype.hideReferencedCommands = function ($form) {
- $form.find('.referenced-commands').hide();
- };
-
- MarkdownPreview.prototype.renderReferencedCommands = function (commands, $form) {
- var referencedCommands;
- referencedCommands = $form.find('.referenced-commands');
- if (commands.length > 0) {
- referencedCommands.html(commands);
- referencedCommands.show();
+var lastTextareaPreviewed;
+var lastTextareaHeight = null;
+var markdownPreview;
+var previewButtonSelector;
+var writeButtonSelector;
+
+function MarkdownPreview() {}
+
+// Minimum number of users referenced before triggering a warning
+MarkdownPreview.prototype.referenceThreshold = 10;
+MarkdownPreview.prototype.emptyMessage = 'Nothing to preview.';
+
+MarkdownPreview.prototype.ajaxCache = {};
+
+MarkdownPreview.prototype.showPreview = function ($form) {
+ var mdText;
+ var preview = $form.find('.js-md-preview');
+ var url = preview.data('url');
+ if (preview.hasClass('md-preview-loading')) {
+ return;
+ }
+ mdText = $form.find('textarea.markdown-area').val();
+
+ if (mdText.trim().length === 0) {
+ preview.text(this.emptyMessage);
+ this.hideReferencedUsers($form);
+ } else {
+ preview.addClass('md-preview-loading').text('Loading...');
+ this.fetchMarkdownPreview(mdText, url, (function (response) {
+ var body;
+ if (response.body.length > 0) {
+ body = response.body;
} else {
- referencedCommands.html('');
- referencedCommands.hide();
+ body = this.emptyMessage;
}
- };
-
- return MarkdownPreview;
- }());
-
- markdownPreview = new window.MarkdownPreview();
- previewButtonSelector = '.js-md-preview-button';
- writeButtonSelector = '.js-md-write-button';
- lastTextareaPreviewed = null;
- const markdownToolbar = $('.md-header-toolbar');
-
- $.fn.setupMarkdownPreview = function () {
- var $form = $(this);
- $form.find('textarea.markdown-area').on('input', function () {
- markdownPreview.hideReferencedUsers($form);
- });
- };
-
- $(document).on('markdown-preview:show', function (e, $form) {
- if (!$form) {
- return;
- }
-
- lastTextareaPreviewed = $form.find('textarea.markdown-area');
- lastTextareaHeight = lastTextareaPreviewed.height();
-
- // toggle tabs
- $form.find(writeButtonSelector).parent().removeClass('active');
- $form.find(previewButtonSelector).parent().addClass('active');
- // toggle content
- $form.find('.md-write-holder').hide();
- $form.find('.md-preview-holder').show();
- markdownToolbar.removeClass('active');
- markdownPreview.showPreview($form);
- });
-
- $(document).on('markdown-preview:hide', function (e, $form) {
- if (!$form) {
- return;
- }
- lastTextareaPreviewed = null;
-
- if (lastTextareaHeight) {
- $form.find('textarea.markdown-area').height(lastTextareaHeight);
- }
-
- // toggle tabs
- $form.find(writeButtonSelector).parent().addClass('active');
- $form.find(previewButtonSelector).parent().removeClass('active');
-
- // toggle content
- $form.find('.md-write-holder').show();
- $form.find('textarea.markdown-area').focus();
- $form.find('.md-preview-holder').hide();
- markdownToolbar.addClass('active');
+ preview.removeClass('md-preview-loading').html(body);
+ preview.renderGFM();
+ this.renderReferencedUsers(response.references.users, $form);
- markdownPreview.hideReferencedCommands($form);
+ if (response.references.commands) {
+ this.renderReferencedCommands(response.references.commands, $form);
+ }
+ }).bind(this));
+ }
+};
+
+MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) {
+ if (!url) {
+ return;
+ }
+ if (text === this.ajaxCache.text) {
+ success(this.ajaxCache.response);
+ return;
+ }
+ $.ajax({
+ type: 'POST',
+ url: url,
+ data: {
+ text: text
+ },
+ dataType: 'json',
+ success: (function (response) {
+ this.ajaxCache = {
+ text: text,
+ response: response
+ };
+ success(response);
+ }).bind(this)
});
-
- $(document).on('markdown-preview:toggle', function (e, keyboardEvent) {
- var $target;
- $target = $(keyboardEvent.target);
- if ($target.is('textarea.markdown-area')) {
- $(document).triggerHandler('markdown-preview:show', [$target.closest('form')]);
- keyboardEvent.preventDefault();
- } else if (lastTextareaPreviewed) {
- $target = lastTextareaPreviewed;
- $(document).triggerHandler('markdown-preview:hide', [$target.closest('form')]);
- keyboardEvent.preventDefault();
+};
+
+MarkdownPreview.prototype.hideReferencedUsers = function ($form) {
+ $form.find('.referenced-users').hide();
+};
+
+MarkdownPreview.prototype.renderReferencedUsers = function (users, $form) {
+ var referencedUsers;
+ referencedUsers = $form.find('.referenced-users');
+ if (referencedUsers.length) {
+ if (users.length >= this.referenceThreshold) {
+ referencedUsers.show();
+ referencedUsers.find('.js-referenced-users-count').text(users.length);
+ } else {
+ referencedUsers.hide();
}
+ }
+};
+
+MarkdownPreview.prototype.hideReferencedCommands = function ($form) {
+ $form.find('.referenced-commands').hide();
+};
+
+MarkdownPreview.prototype.renderReferencedCommands = function (commands, $form) {
+ var referencedCommands;
+ referencedCommands = $form.find('.referenced-commands');
+ if (commands.length > 0) {
+ referencedCommands.html(commands);
+ referencedCommands.show();
+ } else {
+ referencedCommands.html('');
+ referencedCommands.hide();
+ }
+};
+
+markdownPreview = new MarkdownPreview();
+
+previewButtonSelector = '.js-md-preview-button';
+writeButtonSelector = '.js-md-write-button';
+lastTextareaPreviewed = null;
+const markdownToolbar = $('.md-header-toolbar');
+
+$.fn.setupMarkdownPreview = function () {
+ var $form = $(this);
+ $form.find('textarea.markdown-area').on('input', function () {
+ markdownPreview.hideReferencedUsers($form);
});
+};
+
+$(document).on('markdown-preview:show', function (e, $form) {
+ if (!$form) {
+ return;
+ }
+
+ lastTextareaPreviewed = $form.find('textarea.markdown-area');
+ lastTextareaHeight = lastTextareaPreviewed.height();
+
+ // toggle tabs
+ $form.find(writeButtonSelector).parent().removeClass('active');
+ $form.find(previewButtonSelector).parent().addClass('active');
+
+ // toggle content
+ $form.find('.md-write-holder').hide();
+ $form.find('.md-preview-holder').show();
+ markdownToolbar.removeClass('active');
+ markdownPreview.showPreview($form);
+});
+
+$(document).on('markdown-preview:hide', function (e, $form) {
+ if (!$form) {
+ return;
+ }
+ lastTextareaPreviewed = null;
- $(document).on('click', previewButtonSelector, function (e) {
- var $form;
- e.preventDefault();
- $form = $(this).closest('form');
- $(document).triggerHandler('markdown-preview:show', [$form]);
- });
-
- $(document).on('click', writeButtonSelector, function (e) {
- var $form;
- e.preventDefault();
- $form = $(this).closest('form');
- $(document).triggerHandler('markdown-preview:hide', [$form]);
- });
-}());
+ if (lastTextareaHeight) {
+ $form.find('textarea.markdown-area').height(lastTextareaHeight);
+ }
+
+ // toggle tabs
+ $form.find(writeButtonSelector).parent().addClass('active');
+ $form.find(previewButtonSelector).parent().removeClass('active');
+
+ // toggle content
+ $form.find('.md-write-holder').show();
+ $form.find('textarea.markdown-area').focus();
+ $form.find('.md-preview-holder').hide();
+ markdownToolbar.addClass('active');
+
+ markdownPreview.hideReferencedCommands($form);
+});
+
+$(document).on('markdown-preview:toggle', function (e, keyboardEvent) {
+ var $target;
+ $target = $(keyboardEvent.target);
+ if ($target.is('textarea.markdown-area')) {
+ $(document).triggerHandler('markdown-preview:show', [$target.closest('form')]);
+ keyboardEvent.preventDefault();
+ } else if (lastTextareaPreviewed) {
+ $target = lastTextareaPreviewed;
+ $(document).triggerHandler('markdown-preview:hide', [$target.closest('form')]);
+ keyboardEvent.preventDefault();
+ }
+});
+
+$(document).on('click', previewButtonSelector, function (e) {
+ var $form;
+ e.preventDefault();
+ $form = $(this).closest('form');
+ $(document).triggerHandler('markdown-preview:show', [$form]);
+});
+
+$(document).on('click', writeButtonSelector, function (e) {
+ var $form;
+ e.preventDefault();
+ $form = $(this).closest('form');
+ $(document).triggerHandler('markdown-preview:hide', [$form]);
+});
+
+export default MarkdownPreview;
--
cgit v1.2.1
From 9452fd2b4818c63237c4e0172c4f7192be6b04e0 Mon Sep 17 00:00:00 2001
From: David Kuri
Date: Tue, 9 Jan 2018 09:24:08 +0000
Subject: Fixing re-ordering of an issue when dragging it to the bottom a long
issue list in the board
---
app/assets/javascripts/boards/components/board_list.js | 2 +-
.../unreleased/36906-reordering-issues-to-the-bottom.yml | 5 +++++
spec/javascripts/boards/board_list_spec.js | 12 ++++++++++++
3 files changed, 18 insertions(+), 1 deletion(-)
create mode 100644 changelogs/unreleased/36906-reordering-issues-to-the-bottom.yml
diff --git a/app/assets/javascripts/boards/components/board_list.js b/app/assets/javascripts/boards/components/board_list.js
index 84b76a6f1b1..d8cf532fe78 100644
--- a/app/assets/javascripts/boards/components/board_list.js
+++ b/app/assets/javascripts/boards/components/board_list.js
@@ -187,7 +187,7 @@ export default {
+ data-issue-id="-1">
{
});
});
+ it('sets data attribute with invalid id', (done) => {
+ component.showCount = true;
+
+ Vue.nextTick(() => {
+ expect(
+ component.$el.querySelector('.board-list-count').getAttribute('data-issue-id'),
+ ).toBe('-1');
+
+ done();
+ });
+ });
+
it('shows how many more issues to load', (done) => {
component.showCount = true;
component.list.issuesSize = 20;
--
cgit v1.2.1
From d5a92c53dd79ff661ca7f8e4b0deefec5e19704d Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Tue, 9 Jan 2018 11:28:14 +0100
Subject: Implement QA pages and views validator
---
qa/qa.rb | 1 +
qa/qa/page/validator.rb | 51 ++++++++++++++++++++++++++
qa/spec/page/validator_spec.rb | 83 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 135 insertions(+)
create mode 100644 qa/qa/page/validator.rb
create mode 100644 qa/spec/page/validator_spec.rb
diff --git a/qa/qa.rb b/qa/qa.rb
index 9ee4e6b9d0c..4803432aeee 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -74,6 +74,7 @@ module QA
autoload :Base, 'qa/page/base'
autoload :View, 'qa/page/view'
autoload :Element, 'qa/page/element'
+ autoload :Validator, 'qa/page/validator'
module Main
autoload :Login, 'qa/page/main/login'
diff --git a/qa/qa/page/validator.rb b/qa/qa/page/validator.rb
new file mode 100644
index 00000000000..cf4e57db0f0
--- /dev/null
+++ b/qa/qa/page/validator.rb
@@ -0,0 +1,51 @@
+module QA
+ module Page
+ class Validator
+ ValidationError = Class.new(StandardError)
+ Error = Struct.new(:page, :view, :message)
+
+ def initialize(constant)
+ @module = constant
+ end
+
+ def constants
+ @consts ||= @module.constants.map do |const|
+ @module.const_get(const)
+ end
+ end
+
+ def descendants
+ @descendants ||= constants.map do |const|
+ case const
+ when Class
+ const if const < Page::Base
+ when Module
+ Page::Validator.new(const).descendants
+ end
+ end
+
+ @descendants.flatten.compact
+ end
+
+ def errors
+ @errors ||= Array.new.tap do |errors|
+ descendants.each do |page|
+ page.views.each do |view|
+ view.errors.each do |error|
+ errors.push(Error.new(page, view, error))
+ end
+ end
+ end
+ end
+ end
+
+ def validate!
+ message = <<~EOS
+ We found validation errors!
+ EOS
+
+ raise ValidationError, message if errors.any?
+ end
+ end
+ end
+end
diff --git a/qa/spec/page/validator_spec.rb b/qa/spec/page/validator_spec.rb
new file mode 100644
index 00000000000..abee137f4a1
--- /dev/null
+++ b/qa/spec/page/validator_spec.rb
@@ -0,0 +1,83 @@
+describe QA::Page::Validator do
+ describe '#constants' do
+ subject do
+ described_class.new(QA::Page::Project)
+ end
+
+ it 'returns all costants that are module children' do
+ expect(subject.constants)
+ .to include QA::Page::Project::New, QA::Page::Project::Settings
+ end
+ end
+
+ describe '#descendants' do
+ subject do
+ described_class.new(QA::Page::Project)
+ end
+
+ it 'recursively returns all descendants that are page objects' do
+ expect(subject.descendants)
+ .to include QA::Page::Project::New, QA::Page::Project::Settings::Repository
+ end
+
+ it 'does not return modules that aggregate page objects' do
+ expect(subject.descendants)
+ .not_to include QA::Page::Project::Settings
+ end
+ end
+
+ context 'when checking validation errors' do
+ let(:view) { spy('view') }
+
+ before do
+ allow(QA::Page::Admin::Settings)
+ .to receive(:views).and_return([view])
+ end
+
+ subject do
+ described_class.new(QA::Page::Admin)
+ end
+
+ context 'when there are no validation errors' do
+ before do
+ allow(view).to receive(:errors).and_return([])
+ end
+
+ describe '#errors' do
+ it 'does not return errors' do
+ expect(subject.errors).to be_empty
+ end
+ end
+
+ describe '#validate!' do
+ it 'does not raise error' do
+ expect { subject.validate! }.not_to raise_error
+ end
+ end
+ end
+
+ context 'when there are validation errors' do
+ before do
+ allow(view).to receive(:errors)
+ .and_return(['some error', 'another error'])
+ end
+
+ describe '#errors' do
+ it 'returns errors' do
+ expect(subject.errors.count).to eq 2
+ end
+ end
+
+ describe '#validate!' do
+ it 'does raises an error with descriptive message' do
+ message = <<~EOS
+ We found validation errors!
+ EOS
+
+ expect { subject.validate! }
+ .to raise_error described_class::ValidationError, message
+ end
+ end
+ end
+ end
+end
--
cgit v1.2.1
From a5cfd5a69e61b915e8d5a15114441630ff8d37c7 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Tue, 9 Jan 2018 11:29:19 +0100
Subject: Fix rubocop offense in QA page element class
---
qa/qa/page/element.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb
index af93a575cb6..23e1b10fe33 100644
--- a/qa/qa/page/element.rb
+++ b/qa/qa/page/element.rb
@@ -5,7 +5,7 @@ module QA
def initialize(name, pattern = nil)
@name = name
- @pattern = pattern || "qa-#{@name.to_s.gsub('_', '-')}"
+ @pattern = pattern || "qa-#{@name.to_s.tr('_', '-')}"
end
def expression
--
cgit v1.2.1
From e28e1f4226a0643638679907aadd42d1843fc48f Mon Sep 17 00:00:00 2001
From: Filipa Lacerda
Date: Tue, 9 Jan 2018 10:48:02 +0000
Subject: [ci skip] Fix pagination specs
---
app/assets/javascripts/vue_shared/components/table_pagination.vue | 7 +++----
spec/javascripts/vue_shared/components/table_pagination_spec.js | 1 -
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/app/assets/javascripts/vue_shared/components/table_pagination.vue b/app/assets/javascripts/vue_shared/components/table_pagination.vue
index 5aa2aee8882..c44c606a8b2 100644
--- a/app/assets/javascripts/vue_shared/components/table_pagination.vue
+++ b/app/assets/javascripts/vue_shared/components/table_pagination.vue
@@ -93,10 +93,9 @@
},
},
methods: {
- changePage(e) {
- if (e.target.parentElement.classList.contains('disabled')) return;
+ changePage(text, isDisabled) {
+ if (isDisabled) return;
- const text = e.target.innerText;
const { totalPages, nextPage, previousPage } = this.pageInfo;
switch (text) {
@@ -142,7 +141,7 @@
disabled: item.disabled
}"
>
-
+
{{ item.title }}
--
cgit v1.2.1
From a783158bbf52b3d115f9d102499719cc365de81e Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Wed, 10 Jan 2018 12:55:52 +0530
Subject: Update tests for modal changes
---
.../groups/components/item_actions_spec.js | 40 ++++------------------
1 file changed, 7 insertions(+), 33 deletions(-)
diff --git a/spec/javascripts/groups/components/item_actions_spec.js b/spec/javascripts/groups/components/item_actions_spec.js
index 6d6fb410859..acccbe639c4 100644
--- a/spec/javascripts/groups/components/item_actions_spec.js
+++ b/spec/javascripts/groups/components/item_actions_spec.js
@@ -26,32 +26,12 @@ describe('ItemActionsComponent', () => {
vm.$destroy();
});
- describe('computed', () => {
- describe('leaveConfirmationMessage', () => {
- it('should return appropriate string for leave group confirmation', () => {
- expect(vm.leaveConfirmationMessage).toBe('Are you sure you want to leave the "platform / hardware" group?');
- });
- });
- });
-
describe('methods', () => {
describe('onLeaveGroup', () => {
- it('should change `modalStatus` prop to `true` which shows confirmation dialog', () => {
- expect(vm.modalStatus).toBeFalsy();
- vm.onLeaveGroup();
- expect(vm.modalStatus).toBeTruthy();
- });
- });
-
- describe('leaveGroup', () => {
- it('should change `modalStatus` prop to `false` and emit `leaveGroup` event with required params when called with `leaveConfirmed` as `true`', () => {
+ it('emits `showLeaveGroupModal` event with `group` and `parentGroup` props', () => {
spyOn(eventHub, '$emit');
- vm.modalStatus = true;
-
- vm.leaveGroup();
-
- expect(vm.modalStatus).toBeFalsy();
- expect(eventHub.$emit).toHaveBeenCalledWith('leaveGroup', vm.group, vm.parentGroup);
+ vm.onLeaveGroup();
+ expect(eventHub.$emit).toHaveBeenCalledWith('showLeaveGroupModal', vm.group, vm.parentGroup);
});
});
});
@@ -72,7 +52,8 @@ describe('ItemActionsComponent', () => {
expect(editBtn.getAttribute('href')).toBe(group.editPath);
expect(editBtn.getAttribute('aria-label')).toBe('Edit group');
expect(editBtn.dataset.originalTitle).toBe('Edit group');
- expect(editBtn.querySelector('i.fa.fa-cogs')).toBeDefined();
+ expect(editBtn.querySelectorAll('svg use').length).not.toBe(0);
+ expect(editBtn.querySelector('svg use').getAttribute('xlink:href')).toContain('#settings');
newVm.$destroy();
});
@@ -88,17 +69,10 @@ describe('ItemActionsComponent', () => {
expect(leaveBtn.getAttribute('href')).toBe(group.leavePath);
expect(leaveBtn.getAttribute('aria-label')).toBe('Leave this group');
expect(leaveBtn.dataset.originalTitle).toBe('Leave this group');
- expect(leaveBtn.querySelector('i.fa.fa-sign-out')).toBeDefined();
+ expect(leaveBtn.querySelectorAll('svg use').length).not.toBe(0);
+ expect(leaveBtn.querySelector('svg use').getAttribute('xlink:href')).toContain('#leave');
newVm.$destroy();
});
-
- it('should show modal dialog when `modalStatus` is set to `true`', () => {
- vm.modalStatus = true;
- const modalDialogEl = vm.$el.querySelector('.modal');
- expect(modalDialogEl).toBeDefined();
- expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?');
- expect(modalDialogEl.querySelector('.btn.btn-warning').innerText.trim()).toBe('Leave');
- });
});
});
--
cgit v1.2.1
From 3545ceb02c08b71422b51209a2cca21155236cfc Mon Sep 17 00:00:00 2001
From: Sascha Szott
Date: Thu, 11 Jan 2018 08:04:50 +0000
Subject: apply documentation changes from EE to CE
---
doc/api/snippets.md | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/doc/api/snippets.md b/doc/api/snippets.md
index fdafbfb5b9e..e57143e4215 100644
--- a/doc/api/snippets.md
+++ b/doc/api/snippets.md
@@ -84,7 +84,11 @@ Parameters:
``` bash
-curl --request POST --data '{"title": "This is a snippet", "content": "Hello world", "description": "Hello World snippet", "file_name": "test.txt", "visibility": "internal" }' --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/snippets
+curl --request POST \
+ --data '{"title": "This is a snippet", "content": "Hello world", "description": "Hello World snippet", "file_name": "test.txt", "visibility": "internal" }' \
+ --header 'Content-Type: application/json' \
+ --header "PRIVATE-TOKEN: valid_api_token" \
+ https://gitlab.example.com/api/v4/snippets
```
Example response:
@@ -131,7 +135,11 @@ Parameters:
``` bash
-curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data '{"title": "foo", "content": "bar"}' https://gitlab.example.com/api/v4/snippets/1
+curl --request PUT \
+ --data '{"title": "foo", "content": "bar"}' \
+ --header 'Content-Type: application/json' \
+ --header "PRIVATE-TOKEN: valid_api_token" \
+ https://gitlab.example.com/api/v4/snippets/1
```
Example response:
--
cgit v1.2.1
From 407d56384460806ed2e2c88657ce35750527aae5 Mon Sep 17 00:00:00 2001
From: Jose Ivan Vargas
Date: Thu, 11 Jan 2018 08:23:44 +0000
Subject: Fix up Web IDE user preference copy and buttons
---
app/assets/images/multi-editor-on.png | Bin 5464 -> 3971 bytes
app/helpers/blob_helper.rb | 2 +-
app/views/layouts/header/_default.html.haml | 2 --
app/views/profiles/preferences/show.html.haml | 4 ++--
...ix-up-web-ide-user-preference-copy-and-buttons.yml | 5 +++++
spec/features/projects/tree/create_directory_spec.rb | 2 +-
spec/features/projects/tree/create_file_spec.rb | 2 +-
spec/features/projects/tree/upload_file_spec.rb | 2 +-
8 files changed, 11 insertions(+), 8 deletions(-)
create mode 100644 changelogs/unreleased/41789-fix-up-web-ide-user-preference-copy-and-buttons.yml
diff --git a/app/assets/images/multi-editor-on.png b/app/assets/images/multi-editor-on.png
index 2bcd29abf13..d51b68da985 100644
Binary files a/app/assets/images/multi-editor-on.png and b/app/assets/images/multi-editor-on.png differ
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index f9dcb32f7c4..5e3b2e5581c 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -46,7 +46,7 @@ module BlobHelper
end
def ide_edit_text
- "#{_('Multi Edit')} #{_('Beta')}".html_safe
+ "#{_('Web IDE')}"
end
def ide_blob_link(project = @project, ref = @ref, path = @path, options = {})
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 39eb71c2bac..99e7f3b568d 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -56,8 +56,6 @@
= 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 65328791ce5..aeae7455a1c 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -5,8 +5,8 @@
= 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
+ Web IDE (Beta)
+ %p Enable the new web IDE on this device to make it possible to open and edit multiple files with a single commit
.col-lg-8.multi-file-editor-options
= label_tag do
.preview.append-bottom-10= image_tag "multi-editor-off.png"
diff --git a/changelogs/unreleased/41789-fix-up-web-ide-user-preference-copy-and-buttons.yml b/changelogs/unreleased/41789-fix-up-web-ide-user-preference-copy-and-buttons.yml
new file mode 100644
index 00000000000..fe87cd5cadb
--- /dev/null
+++ b/changelogs/unreleased/41789-fix-up-web-ide-user-preference-copy-and-buttons.yml
@@ -0,0 +1,5 @@
+---
+title: Fix web ide user preferences copy and buttons
+merge_request: 41789
+author:
+type: other
diff --git a/spec/features/projects/tree/create_directory_spec.rb b/spec/features/projects/tree/create_directory_spec.rb
index 3f6d16c8acf..0c67196f53e 100644
--- a/spec/features/projects/tree/create_directory_spec.rb
+++ b/spec/features/projects/tree/create_directory_spec.rb
@@ -14,7 +14,7 @@ feature 'Multi-file editor new directory', :js do
wait_for_requests
- click_link('Multi Edit')
+ click_link('Web IDE')
wait_for_requests
end
diff --git a/spec/features/projects/tree/create_file_spec.rb b/spec/features/projects/tree/create_file_spec.rb
index ba71eef07f4..85f7318c05d 100644
--- a/spec/features/projects/tree/create_file_spec.rb
+++ b/spec/features/projects/tree/create_file_spec.rb
@@ -14,7 +14,7 @@ feature 'Multi-file editor new file', :js do
wait_for_requests
- click_link('Multi Edit')
+ click_link('Web IDE')
wait_for_requests
end
diff --git a/spec/features/projects/tree/upload_file_spec.rb b/spec/features/projects/tree/upload_file_spec.rb
index 9fbb1dbd0e8..f81e8677e92 100644
--- a/spec/features/projects/tree/upload_file_spec.rb
+++ b/spec/features/projects/tree/upload_file_spec.rb
@@ -16,7 +16,7 @@ feature 'Multi-file editor upload file', :js do
wait_for_requests
- click_link('Multi Edit')
+ click_link('Web IDE')
wait_for_requests
end
--
cgit v1.2.1
From a607f343c5c28511e92e058a9556b89f897ae8c2 Mon Sep 17 00:00:00 2001
From: Phil Hughes
Date: Tue, 9 Jan 2018 12:10:53 +0000
Subject: Admin dispatcher JS imports
---
app/assets/javascripts/abuse_reports.js | 36 -------------
app/assets/javascripts/admin.js | 59 ----------------------
app/assets/javascripts/broadcast_message.js | 28 ----------
app/assets/javascripts/dispatcher.js | 44 ++++++++--------
.../pages/admin/abuse_reports/abuse_reports.js | 36 +++++++++++++
.../javascripts/pages/admin/abuse_reports/index.js | 3 ++
app/assets/javascripts/pages/admin/admin.js | 59 ++++++++++++++++++++++
.../admin/broadcast_messages/broadcast_message.js | 28 ++++++++++
.../pages/admin/broadcast_messages/index.js | 3 ++
.../javascripts/pages/admin/cohorts/index.js | 3 ++
.../javascripts/pages/admin/cohorts/usage_ping.js | 12 +++++
.../javascripts/pages/admin/groups/edit/index.js | 3 ++
.../javascripts/pages/admin/groups/new/index.js | 9 ++++
.../javascripts/pages/admin/groups/show/index.js | 3 ++
.../pages/admin/impersonation_tokens/index.js | 3 ++
app/assets/javascripts/pages/admin/index.js | 3 ++
.../javascripts/pages/admin/labels/edit/index.js | 3 ++
.../javascripts/pages/admin/labels/new/index.js | 3 ++
.../javascripts/pages/admin/projects/index.js | 9 ++++
app/assets/javascripts/usage_ping.js | 12 -----
20 files changed, 204 insertions(+), 155 deletions(-)
delete mode 100644 app/assets/javascripts/abuse_reports.js
delete mode 100644 app/assets/javascripts/admin.js
delete mode 100644 app/assets/javascripts/broadcast_message.js
create mode 100644 app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
create mode 100644 app/assets/javascripts/pages/admin/abuse_reports/index.js
create mode 100644 app/assets/javascripts/pages/admin/admin.js
create mode 100644 app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
create mode 100644 app/assets/javascripts/pages/admin/broadcast_messages/index.js
create mode 100644 app/assets/javascripts/pages/admin/cohorts/index.js
create mode 100644 app/assets/javascripts/pages/admin/cohorts/usage_ping.js
create mode 100644 app/assets/javascripts/pages/admin/groups/edit/index.js
create mode 100644 app/assets/javascripts/pages/admin/groups/new/index.js
create mode 100644 app/assets/javascripts/pages/admin/groups/show/index.js
create mode 100644 app/assets/javascripts/pages/admin/impersonation_tokens/index.js
create mode 100644 app/assets/javascripts/pages/admin/index.js
create mode 100644 app/assets/javascripts/pages/admin/labels/edit/index.js
create mode 100644 app/assets/javascripts/pages/admin/labels/new/index.js
create mode 100644 app/assets/javascripts/pages/admin/projects/index.js
delete mode 100644 app/assets/javascripts/usage_ping.js
diff --git a/app/assets/javascripts/abuse_reports.js b/app/assets/javascripts/abuse_reports.js
deleted file mode 100644
index d2d3a257c0d..00000000000
--- a/app/assets/javascripts/abuse_reports.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { truncate } from './lib/utils/text_utility';
-
-const MAX_MESSAGE_LENGTH = 500;
-const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
-
-export default class AbuseReports {
- constructor() {
- $(MESSAGE_CELL_SELECTOR).each(this.truncateLongMessage);
- $(document)
- .off('click', MESSAGE_CELL_SELECTOR)
- .on('click', MESSAGE_CELL_SELECTOR, this.toggleMessageTruncation);
- }
-
- truncateLongMessage() {
- const $messageCellElement = $(this);
- const reportMessage = $messageCellElement.text();
- if (reportMessage.length > MAX_MESSAGE_LENGTH) {
- $messageCellElement.data('original-message', reportMessage);
- $messageCellElement.data('message-truncated', 'true');
- $messageCellElement.text(truncate(reportMessage, MAX_MESSAGE_LENGTH));
- }
- }
-
- toggleMessageTruncation() {
- const $messageCellElement = $(this);
- const originalMessage = $messageCellElement.data('original-message');
- if (!originalMessage) return;
- if ($messageCellElement.data('message-truncated') === 'true') {
- $messageCellElement.data('message-truncated', 'false');
- $messageCellElement.text(originalMessage);
- } else {
- $messageCellElement.data('message-truncated', 'true');
- $messageCellElement.text(`${originalMessage.substr(0, (MAX_MESSAGE_LENGTH - 3))}...`);
- }
- }
-}
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js
deleted file mode 100644
index c1f7fa2aced..00000000000
--- a/app/assets/javascripts/admin.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import { refreshCurrentPage } from './lib/utils/url_utility';
-
-function showBlacklistType() {
- if ($('input[name="blacklist_type"]:checked').val() === 'file') {
- $('.blacklist-file').show();
- $('.blacklist-raw').hide();
- } else {
- $('.blacklist-file').hide();
- $('.blacklist-raw').show();
- }
-}
-
-export default function adminInit() {
- const modal = $('.change-owner-holder');
-
- $('input#user_force_random_password').on('change', function randomPasswordClick() {
- const $elems = $('#user_password, #user_password_confirmation');
- if ($(this).attr('checked')) {
- $elems.val('').attr('disabled', true);
- } else {
- $elems.removeAttr('disabled');
- }
- });
-
- $('body').on('click', '.js-toggle-colors-link', (e) => {
- e.preventDefault();
- $('.js-toggle-colors-container').toggle();
- });
-
- $('.log-tabs a').on('click', function logTabsClick(e) {
- e.preventDefault();
- $(this).tab('show');
- });
-
- $('.log-bottom').on('click', (e) => {
- e.preventDefault();
- const $visibleLog = $('.file-content:visible');
- $visibleLog.animate({
- scrollTop: $visibleLog.find('ol').height(),
- }, 'fast');
- });
-
- $('.change-owner-link').on('click', function changeOwnerLinkClick(e) {
- e.preventDefault();
- $(this).hide();
- modal.show();
- });
-
- $('.change-owner-cancel-link').on('click', (e) => {
- e.preventDefault();
- modal.hide();
- $('.change-owner-link').show();
- });
-
- $('li.project_member, li.group_member').on('ajax:success', refreshCurrentPage);
-
- $("input[name='blacklist_type']").on('click', showBlacklistType);
- showBlacklistType();
-}
diff --git a/app/assets/javascripts/broadcast_message.js b/app/assets/javascripts/broadcast_message.js
deleted file mode 100644
index ff88083a4b4..00000000000
--- a/app/assets/javascripts/broadcast_message.js
+++ /dev/null
@@ -1,28 +0,0 @@
-export default function initBroadcastMessagesForm() {
- $('input#broadcast_message_color').on('input', function onMessageColorInput() {
- const previewColor = $(this).val();
- $('div.broadcast-message-preview').css('background-color', previewColor);
- });
-
- $('input#broadcast_message_font').on('input', function onMessageFontInput() {
- const previewColor = $(this).val();
- $('div.broadcast-message-preview').css('color', previewColor);
- });
-
- const previewPath = $('textarea#broadcast_message_message').data('preview-path');
-
- $('textarea#broadcast_message_message').on('input', _.debounce(function onMessageInput() {
- const message = $(this).val();
- if (message === '') {
- $('.js-broadcast-message-preview').text('Your message here');
- } else {
- $.ajax({
- url: previewPath,
- type: 'POST',
- data: {
- broadcast_message: { message },
- },
- });
- }
- }, 250));
-}
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 9d9605045fb..d0073a1a403 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -13,8 +13,6 @@ import groupAvatar from './group_avatar';
import GroupLabelSubscription from './group_label_subscription';
import LineHighlighter from './line_highlighter';
import groupsSelect from './groups_select';
-import initAdmin from './admin';
-import NamespaceSelect from './namespace_select';
import NewCommitForm from './new_commit_form';
import Project from './project';
import projectAvatar from './project_avatar';
@@ -51,14 +49,12 @@ import GfmAutoComplete from './gfm_auto_complete';
import ShortcutsBlob from './shortcuts_blob';
import Star from './star';
import TreeView from './tree';
-import UsagePing from './usage_ping';
import VersionCheckImage from './version_check_image';
import Wikis from './wikis';
import ZenMode from './zen_mode';
import initSettingsPanels from './settings_panels';
import initExperimentalFlags from './experimental_flags';
import PerformanceBar from './performance_bar';
-import initBroadcastMessagesForm from './broadcast_message';
import initNotes from './init_notes';
import initLegacyFilters from './init_legacy_filters';
import initIssuableSidebar from './init_issuable_sidebar';
@@ -66,7 +62,6 @@ import initProjectVisibilitySelector from './project_visibility';
import GpgBadges from './gpg_badges';
import initChangesDropdown from './init_changes_dropdown';
import NewGroupChild from './groups/new_group_child';
-import AbuseReports from './abuse_reports';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
import AjaxLoadingSpinner from './ajax_loading_spinner';
import GlFieldErrors from './gl_field_errors';
@@ -229,9 +224,6 @@ import Activities from './activities';
.then(callDefault)
.catch(fail);
break;
- case 'admin:projects:index':
- new ProjectsList();
- break;
case 'explore:groups:index':
import('./pages/explore/groups')
.then(callDefault)
@@ -441,15 +433,19 @@ import Activities from './activities';
new UsersSelect();
break;
case 'groups:new':
- case 'admin:groups:new':
case 'groups:create':
- case 'admin:groups:create':
BindInOut.initAll();
new Group();
groupAvatar();
break;
- case 'groups:edit':
+ case 'admin:groups:create':
+ case 'admin:groups:new':
+ import('./pages/admin/groups/new').then(m => m.default()).catch(fail);
+ break;
case 'admin:groups:edit':
+ import('./pages/admin/groups/edit').then(m => m.default()).catch(fail);
+ break;
+ case 'groups:edit':
groupAvatar();
break;
case 'projects:tree:show':
@@ -565,8 +561,10 @@ import Activities from './activities';
case 'import:fogbugz:new_user_map':
import('./pages/import/fogbugz/new_user_map').then(m => m.default()).catch(fail);
break;
- case 'profiles:personal_access_tokens:index':
case 'admin:impersonation_tokens:index':
+ import('./pages/admin/impersonation_tokens').then(m => m.default()).catch(fail);
+ break;
+ case 'profiles:personal_access_tokens:index':
new DueDateSelectors();
break;
case 'projects:clusters:show':
@@ -601,29 +599,35 @@ import Activities from './activities';
// needed in rspec
gl.u2fAuthenticate = u2fAuthenticate;
case 'admin':
- initAdmin();
+ import('./pages/admin').then(m => m.default()).catch(fail);
switch (path[1]) {
case 'broadcast_messages':
- initBroadcastMessagesForm();
+ import('./pages/admin/broadcast_messages').then(m => m.default()).catch(fail);
break;
case 'cohorts':
- new UsagePing();
+ import('./pages/admin/cohorts').then(m => m.default()).catch(fail);
break;
case 'groups':
- new UsersSelect();
+ switch (path[2]) {
+ case 'show':
+ import('./pages/admin/groups/show').then(m => m.default()).catch(fail);
+ break;
+ }
break;
case 'projects':
- document.querySelectorAll('.js-namespace-select')
- .forEach(dropdown => new NamespaceSelect({ dropdown }));
+ import('./pages/admin/projects').then(m => m.default()).catch(fail);
break;
case 'labels':
switch (path[2]) {
case 'new':
+ import('./pages/admin/labels/new').then(m => m.default()).catch(fail);
+ break;
case 'edit':
- new Labels();
+ import('./pages/admin/labels/edit').then(m => m.default()).catch(fail);
+ break;
}
case 'abuse_reports':
- new AbuseReports();
+ import('./pages/admin/abuse_reports').then(m => m.default()).catch(fail);
break;
}
break;
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
new file mode 100644
index 00000000000..d87e6304a24
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
@@ -0,0 +1,36 @@
+import { truncate } from '../../../lib/utils/text_utility';
+
+const MAX_MESSAGE_LENGTH = 500;
+const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
+
+export default class AbuseReports {
+ constructor() {
+ $(MESSAGE_CELL_SELECTOR).each(this.truncateLongMessage);
+ $(document)
+ .off('click', MESSAGE_CELL_SELECTOR)
+ .on('click', MESSAGE_CELL_SELECTOR, this.toggleMessageTruncation);
+ }
+
+ truncateLongMessage() {
+ const $messageCellElement = $(this);
+ const reportMessage = $messageCellElement.text();
+ if (reportMessage.length > MAX_MESSAGE_LENGTH) {
+ $messageCellElement.data('original-message', reportMessage);
+ $messageCellElement.data('message-truncated', 'true');
+ $messageCellElement.text(truncate(reportMessage, MAX_MESSAGE_LENGTH));
+ }
+ }
+
+ toggleMessageTruncation() {
+ const $messageCellElement = $(this);
+ const originalMessage = $messageCellElement.data('original-message');
+ if (!originalMessage) return;
+ if ($messageCellElement.data('message-truncated') === 'true') {
+ $messageCellElement.data('message-truncated', 'false');
+ $messageCellElement.text(originalMessage);
+ } else {
+ $messageCellElement.data('message-truncated', 'true');
+ $messageCellElement.text(`${originalMessage.substr(0, (MAX_MESSAGE_LENGTH - 3))}...`);
+ }
+ }
+}
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/index.js b/app/assets/javascripts/pages/admin/abuse_reports/index.js
new file mode 100644
index 00000000000..c0b6e8d4095
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/abuse_reports/index.js
@@ -0,0 +1,3 @@
+import AbuseReports from './abuse_reports';
+
+export default () => new AbuseReports();
diff --git a/app/assets/javascripts/pages/admin/admin.js b/app/assets/javascripts/pages/admin/admin.js
new file mode 100644
index 00000000000..135c15c346b
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/admin.js
@@ -0,0 +1,59 @@
+import { refreshCurrentPage } from '../../lib/utils/url_utility';
+
+function showBlacklistType() {
+ if ($('input[name="blacklist_type"]:checked').val() === 'file') {
+ $('.blacklist-file').show();
+ $('.blacklist-raw').hide();
+ } else {
+ $('.blacklist-file').hide();
+ $('.blacklist-raw').show();
+ }
+}
+
+export default function adminInit() {
+ const modal = $('.change-owner-holder');
+
+ $('input#user_force_random_password').on('change', function randomPasswordClick() {
+ const $elems = $('#user_password, #user_password_confirmation');
+ if ($(this).attr('checked')) {
+ $elems.val('').attr('disabled', true);
+ } else {
+ $elems.removeAttr('disabled');
+ }
+ });
+
+ $('body').on('click', '.js-toggle-colors-link', (e) => {
+ e.preventDefault();
+ $('.js-toggle-colors-container').toggle();
+ });
+
+ $('.log-tabs a').on('click', function logTabsClick(e) {
+ e.preventDefault();
+ $(this).tab('show');
+ });
+
+ $('.log-bottom').on('click', (e) => {
+ e.preventDefault();
+ const $visibleLog = $('.file-content:visible');
+ $visibleLog.animate({
+ scrollTop: $visibleLog.find('ol').height(),
+ }, 'fast');
+ });
+
+ $('.change-owner-link').on('click', function changeOwnerLinkClick(e) {
+ e.preventDefault();
+ $(this).hide();
+ modal.show();
+ });
+
+ $('.change-owner-cancel-link').on('click', (e) => {
+ e.preventDefault();
+ modal.hide();
+ $('.change-owner-link').show();
+ });
+
+ $('li.project_member, li.group_member').on('ajax:success', refreshCurrentPage);
+
+ $("input[name='blacklist_type']").on('click', showBlacklistType);
+ showBlacklistType();
+}
diff --git a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
new file mode 100644
index 00000000000..ff88083a4b4
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
@@ -0,0 +1,28 @@
+export default function initBroadcastMessagesForm() {
+ $('input#broadcast_message_color').on('input', function onMessageColorInput() {
+ const previewColor = $(this).val();
+ $('div.broadcast-message-preview').css('background-color', previewColor);
+ });
+
+ $('input#broadcast_message_font').on('input', function onMessageFontInput() {
+ const previewColor = $(this).val();
+ $('div.broadcast-message-preview').css('color', previewColor);
+ });
+
+ const previewPath = $('textarea#broadcast_message_message').data('preview-path');
+
+ $('textarea#broadcast_message_message').on('input', _.debounce(function onMessageInput() {
+ const message = $(this).val();
+ if (message === '') {
+ $('.js-broadcast-message-preview').text('Your message here');
+ } else {
+ $.ajax({
+ url: previewPath,
+ type: 'POST',
+ data: {
+ broadcast_message: { message },
+ },
+ });
+ }
+ }, 250));
+}
diff --git a/app/assets/javascripts/pages/admin/broadcast_messages/index.js b/app/assets/javascripts/pages/admin/broadcast_messages/index.js
new file mode 100644
index 00000000000..b548c48282a
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/broadcast_messages/index.js
@@ -0,0 +1,3 @@
+import initBroadcastMessagesForm from './broadcast_message';
+
+export default () => initBroadcastMessagesForm();
diff --git a/app/assets/javascripts/pages/admin/cohorts/index.js b/app/assets/javascripts/pages/admin/cohorts/index.js
new file mode 100644
index 00000000000..42ef9d38ef7
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/cohorts/index.js
@@ -0,0 +1,3 @@
+import initUsagePing from './usage_ping';
+
+export default () => initUsagePing();
diff --git a/app/assets/javascripts/pages/admin/cohorts/usage_ping.js b/app/assets/javascripts/pages/admin/cohorts/usage_ping.js
new file mode 100644
index 00000000000..2389056bd02
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/cohorts/usage_ping.js
@@ -0,0 +1,12 @@
+export default function UsagePing() {
+ const usageDataUrl = $('.usage-data').data('endpoint');
+
+ $.ajax({
+ type: 'GET',
+ url: usageDataUrl,
+ dataType: 'html',
+ success(html) {
+ $('.usage-data').html(html);
+ },
+ });
+}
diff --git a/app/assets/javascripts/pages/admin/groups/edit/index.js b/app/assets/javascripts/pages/admin/groups/edit/index.js
new file mode 100644
index 00000000000..ff9ef8d2449
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/groups/edit/index.js
@@ -0,0 +1,3 @@
+import groupAvatar from '../../../../group_avatar';
+
+export default () => groupAvatar();
diff --git a/app/assets/javascripts/pages/admin/groups/new/index.js b/app/assets/javascripts/pages/admin/groups/new/index.js
new file mode 100644
index 00000000000..fb5c46e4729
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/groups/new/index.js
@@ -0,0 +1,9 @@
+import BindInOut from '../../../../behaviors/bind_in_out';
+import Group from '../../../../group';
+import groupAvatar from '../../../../group_avatar';
+
+export default () => {
+ BindInOut.initAll();
+ new Group(); // eslint-disable-line no-new
+ groupAvatar();
+};
diff --git a/app/assets/javascripts/pages/admin/groups/show/index.js b/app/assets/javascripts/pages/admin/groups/show/index.js
new file mode 100644
index 00000000000..5defea104d4
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/groups/show/index.js
@@ -0,0 +1,3 @@
+import UsersSelect from '../../../../users_select';
+
+export default () => new UsersSelect();
diff --git a/app/assets/javascripts/pages/admin/impersonation_tokens/index.js b/app/assets/javascripts/pages/admin/impersonation_tokens/index.js
new file mode 100644
index 00000000000..030328a1363
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/impersonation_tokens/index.js
@@ -0,0 +1,3 @@
+import DueDateSelectors from '../../../due_date_select';
+
+export default () => new DueDateSelectors();
diff --git a/app/assets/javascripts/pages/admin/index.js b/app/assets/javascripts/pages/admin/index.js
new file mode 100644
index 00000000000..8b843037d85
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/index.js
@@ -0,0 +1,3 @@
+import initAdmin from './admin';
+
+export default () => initAdmin();
diff --git a/app/assets/javascripts/pages/admin/labels/edit/index.js b/app/assets/javascripts/pages/admin/labels/edit/index.js
new file mode 100644
index 00000000000..d7ec6e47f67
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/labels/edit/index.js
@@ -0,0 +1,3 @@
+import Labels from '../../../../labels';
+
+export default () => new Labels();
diff --git a/app/assets/javascripts/pages/admin/labels/new/index.js b/app/assets/javascripts/pages/admin/labels/new/index.js
new file mode 100644
index 00000000000..d7ec6e47f67
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/labels/new/index.js
@@ -0,0 +1,3 @@
+import Labels from '../../../../labels';
+
+export default () => new Labels();
diff --git a/app/assets/javascripts/pages/admin/projects/index.js b/app/assets/javascripts/pages/admin/projects/index.js
new file mode 100644
index 00000000000..71e0ddcd7b6
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/projects/index.js
@@ -0,0 +1,9 @@
+import ProjectsList from '../../../projects_list';
+import NamespaceSelect from '../../../namespace_select';
+
+export default () => {
+ new ProjectsList(); // eslint-disable-line no-new
+
+ document.querySelectorAll('.js-namespace-select')
+ .forEach(dropdown => new NamespaceSelect({ dropdown }));
+};
diff --git a/app/assets/javascripts/usage_ping.js b/app/assets/javascripts/usage_ping.js
deleted file mode 100644
index 2389056bd02..00000000000
--- a/app/assets/javascripts/usage_ping.js
+++ /dev/null
@@ -1,12 +0,0 @@
-export default function UsagePing() {
- const usageDataUrl = $('.usage-data').data('endpoint');
-
- $.ajax({
- type: 'GET',
- url: usageDataUrl,
- dataType: 'html',
- success(html) {
- $('.usage-data').html(html);
- },
- });
-}
--
cgit v1.2.1
From 3b9a1f36ee4af34fdcb82a29537d8ef20cb67270 Mon Sep 17 00:00:00 2001
From: Phil Hughes
Date: Tue, 9 Jan 2018 12:58:05 +0000
Subject: fixed abuse_reports spec
---
spec/javascripts/abuse_reports_spec.js | 41 ----------------------
.../admin/abuse_reports/abuse_reports_spec.js | 41 ++++++++++++++++++++++
2 files changed, 41 insertions(+), 41 deletions(-)
delete mode 100644 spec/javascripts/abuse_reports_spec.js
create mode 100644 spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js
diff --git a/spec/javascripts/abuse_reports_spec.js b/spec/javascripts/abuse_reports_spec.js
deleted file mode 100644
index 7f6b5873011..00000000000
--- a/spec/javascripts/abuse_reports_spec.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import '~/lib/utils/text_utility';
-import AbuseReports from '~/abuse_reports';
-
-describe('Abuse Reports', () => {
- const FIXTURE = 'abuse_reports/abuse_reports_list.html.raw';
- const MAX_MESSAGE_LENGTH = 500;
-
- let $messages;
-
- const assertMaxLength = $message => expect($message.text().length).toEqual(MAX_MESSAGE_LENGTH);
- const findMessage = searchText => $messages.filter(
- (index, element) => element.innerText.indexOf(searchText) > -1,
- ).first();
-
- preloadFixtures(FIXTURE);
-
- beforeEach(function () {
- loadFixtures(FIXTURE);
- this.abuseReports = new AbuseReports();
- $messages = $('.abuse-reports .message');
- });
-
- it('should truncate long messages', () => {
- const $longMessage = findMessage('LONG MESSAGE');
- expect($longMessage.data('original-message')).toEqual(jasmine.anything());
- assertMaxLength($longMessage);
- });
-
- it('should not truncate short messages', () => {
- const $shortMessage = findMessage('SHORT MESSAGE');
- expect($shortMessage.data('original-message')).not.toEqual(jasmine.anything());
- });
-
- it('should allow clicking a truncated message to expand and collapse the full message', () => {
- const $longMessage = findMessage('LONG MESSAGE');
- $longMessage.click();
- expect($longMessage.data('original-message').length).toEqual($longMessage.text().length);
- $longMessage.click();
- assertMaxLength($longMessage);
- });
-});
diff --git a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js
new file mode 100644
index 00000000000..d2386077aa6
--- /dev/null
+++ b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js
@@ -0,0 +1,41 @@
+import '~/lib/utils/text_utility';
+import AbuseReports from '~/pages/admin/abuse_reports/abuse_reports';
+
+describe('Abuse Reports', () => {
+ const FIXTURE = 'abuse_reports/abuse_reports_list.html.raw';
+ const MAX_MESSAGE_LENGTH = 500;
+
+ let $messages;
+
+ const assertMaxLength = $message => expect($message.text().length).toEqual(MAX_MESSAGE_LENGTH);
+ const findMessage = searchText => $messages.filter(
+ (index, element) => element.innerText.indexOf(searchText) > -1,
+ ).first();
+
+ preloadFixtures(FIXTURE);
+
+ beforeEach(function () {
+ loadFixtures(FIXTURE);
+ this.abuseReports = new AbuseReports();
+ $messages = $('.abuse-reports .message');
+ });
+
+ it('should truncate long messages', () => {
+ const $longMessage = findMessage('LONG MESSAGE');
+ expect($longMessage.data('original-message')).toEqual(jasmine.anything());
+ assertMaxLength($longMessage);
+ });
+
+ it('should not truncate short messages', () => {
+ const $shortMessage = findMessage('SHORT MESSAGE');
+ expect($shortMessage.data('original-message')).not.toEqual(jasmine.anything());
+ });
+
+ it('should allow clicking a truncated message to expand and collapse the full message', () => {
+ const $longMessage = findMessage('LONG MESSAGE');
+ $longMessage.click();
+ expect($longMessage.data('original-message').length).toEqual($longMessage.text().length);
+ $longMessage.click();
+ assertMaxLength($longMessage);
+ });
+});
--
cgit v1.2.1
From 025009929c3f9fb30be2860e75c8c736761a48d0 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 10:26:48 +0100
Subject: Add link to QA page objects docs from main README
---
qa/README.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/qa/README.md b/qa/README.md
index 7f2dd39ff63..8fa04e80825 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -27,13 +27,17 @@ following call would login to a local [GDK] instance and run all specs in
bin/qa Test::Instance http://localhost:3000
```
+### Writing tests
+
+1. [Using page objects](qa/page/README.md)
+
### Running specific tests
You can also supply specific tests to run as another parameter. For example, to
-test the EE license specs, you can run:
+run the repository-related specs, you can execute:
```
-EE_LICENSE="" bin/qa Test::Instance http://localhost qa/specs/features/ee
+bin/qa Test::Instance http://localhost qa/specs/features/repository/
```
Since the arguments would be passed to `rspec`, you could use all `rspec`
--
cgit v1.2.1
From 355982744eb4f0fa905b8fe3257f90978823c720 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?=
Date: Thu, 11 Jan 2018 10:46:26 +0100
Subject: Fix breadcumb of clusters show page
---
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 c7c84b5a42c..2049105dff6 100644
--- a/app/views/projects/clusters/show.html.haml
+++ b/app/views/projects/clusters/show.html.haml
@@ -1,6 +1,6 @@
- @content_class = "limit-container-width" unless fluid_layout
- add_to_breadcrumbs "Clusters", project_clusters_path(@project)
-- breadcrumb_title @cluster.id
+- breadcrumb_title @cluster.name
- page_title _("Cluster")
- expanded = Rails.env.test?
--
cgit v1.2.1
From 1011ca49495eb1f48d43694bfbb2a96951fd45ba Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 10:47:49 +0100
Subject: Add a DSL evaluator to QA base factory class
---
qa/qa/factory/base.rb | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/qa/qa/factory/base.rb b/qa/qa/factory/base.rb
index 00851a7bece..3e5227ea426 100644
--- a/qa/qa/factory/base.rb
+++ b/qa/qa/factory/base.rb
@@ -1,6 +1,12 @@
+require 'forwardable'
+
module QA
module Factory
class Base
+ extend SingleForwardable
+
+ def_delegators :evaluator, :dependency, :dependencies
+
def fabricate!(*_args)
raise NotImplementedError
end
@@ -17,16 +23,25 @@ module QA
end
end
- def self.dependencies
- @dependencies ||= {}
+ def self.evaluator
+ @evaluator ||= Factory::Base::DSL.new(self)
end
- def self.dependency(factory, as:, &block)
- as.tap do |name|
- class_eval { attr_accessor name }
+ class DSL
+ attr_reader :dependencies
+
+ def initialize(base)
+ @base = base
+ @dependencies = {}
+ end
+
+ def dependency(factory, as:, &block)
+ as.tap do |name|
+ @base.class_eval { attr_accessor name }
- Dependency::Signature.new(factory, block).tap do |signature|
- dependencies.store(name, signature)
+ Dependency::Signature.new(factory, block).tap do |signature|
+ dependencies.store(name, signature)
+ end
end
end
end
--
cgit v1.2.1
From d32a151714c01bc09484d423dd2136a89760b5ef Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 10:58:56 +0100
Subject: Make it possible to define QA factory product attributes
---
qa/qa/factory/base.rb | 12 ++++++++++--
qa/qa/factory/product.rb | 2 ++
qa/spec/factory/base_spec.rb | 46 +++++++++++++++++++++++++++++---------------
3 files changed, 42 insertions(+), 18 deletions(-)
diff --git a/qa/qa/factory/base.rb b/qa/qa/factory/base.rb
index 3e5227ea426..c7202d4ae65 100644
--- a/qa/qa/factory/base.rb
+++ b/qa/qa/factory/base.rb
@@ -6,6 +6,7 @@ module QA
extend SingleForwardable
def_delegators :evaluator, :dependency, :dependencies
+ def_delegators :evaluator, :product, :attributes
def fabricate!(*_args)
raise NotImplementedError
@@ -28,11 +29,12 @@ module QA
end
class DSL
- attr_reader :dependencies
+ attr_reader :dependencies, :attributes
def initialize(base)
@base = base
@dependencies = {}
+ @attributes = {}
end
def dependency(factory, as:, &block)
@@ -40,10 +42,16 @@ module QA
@base.class_eval { attr_accessor name }
Dependency::Signature.new(factory, block).tap do |signature|
- dependencies.store(name, signature)
+ @dependencies.store(name, signature)
end
end
end
+
+ def product(attribute, &block)
+ Product::Attribute.new(attribute, block).tap do |signature|
+ @attributes.store(attribute, signature)
+ end
+ end
end
end
end
diff --git a/qa/qa/factory/product.rb b/qa/qa/factory/product.rb
index df35bbbb443..2558350f8a3 100644
--- a/qa/qa/factory/product.rb
+++ b/qa/qa/factory/product.rb
@@ -5,6 +5,8 @@ module QA
class Product
include Capybara::DSL
+ Attribute = Struct.new(:name, :block)
+
def initialize(factory)
@factory = factory
@location = current_url
diff --git a/qa/spec/factory/base_spec.rb b/qa/spec/factory/base_spec.rb
index a3ba0176819..d7cb9a770b5 100644
--- a/qa/spec/factory/base_spec.rb
+++ b/qa/spec/factory/base_spec.rb
@@ -59,30 +59,44 @@ describe QA::Factory::Base do
it 'defines dependency accessors' do
expect(subject.new).to respond_to :mydep, :mydep=
end
- end
- describe 'building dependencies' do
- let(:dependency) { double('dependency') }
- let(:instance) { spy('instance') }
+ describe 'dependencies fabrication' do
+ let(:dependency) { double('dependency') }
+ let(:instance) { spy('instance') }
- subject do
- Class.new(described_class) do
- dependency Some::MyDependency, as: :mydep
+ subject do
+ Class.new(described_class) do
+ dependency Some::MyDependency, as: :mydep
+ end
end
- end
- before do
- stub_const('Some::MyDependency', dependency)
+ before do
+ stub_const('Some::MyDependency', dependency)
+
+ allow(subject).to receive(:new).and_return(instance)
+ allow(instance).to receive(:mydep).and_return(nil)
+ allow(QA::Factory::Product).to receive(:new)
+ end
- allow(subject).to receive(:new).and_return(instance)
- allow(instance).to receive(:mydep).and_return(nil)
- allow(QA::Factory::Product).to receive(:new)
+ it 'builds all dependencies first' do
+ expect(dependency).to receive(:fabricate!).once
+
+ subject.fabricate!
+ end
end
+ end
- it 'builds all dependencies first' do
- expect(dependency).to receive(:fabricate!).once
+ describe '.product' do
+ subject do
+ Class.new(described_class) do
+ product :token do |factory, page|
+ page.do_something!
+ end
+ end
+ end
- subject.fabricate!
+ it 'appends new product attribute' do
+ expect(subject.attributes).to be_one
end
end
end
--
cgit v1.2.1
From cf8429867021f20e671c02115b9c6806acd2d739 Mon Sep 17 00:00:00 2001
From: Fabio Busatto
Date: Thu, 11 Jan 2018 09:59:00 +0000
Subject: Update links for GCP instructions
---
app/views/projects/clusters/gcp/_header.html.haml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/views/projects/clusters/gcp/_header.html.haml b/app/views/projects/clusters/gcp/_header.html.haml
index e2d7326a312..bddb902115d 100644
--- a/app/views/projects/clusters/gcp/_header.html.haml
+++ b/app/views/projects/clusters/gcp/_header.html.haml
@@ -4,11 +4,11 @@
= s_('ClusterIntegration|Please make sure that your Google account meets the following requirements:')
%ul
%li
- - link_to_kubernetes_engine = link_to(s_('ClusterIntegration|access to Google Kubernetes Engine'), 'https://console.cloud.google.com', target: '_blank', rel: 'noopener noreferrer')
+ - link_to_kubernetes_engine = link_to(s_('ClusterIntegration|access to Google Kubernetes Engine'), 'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Your account must have %{link_to_kubernetes_engine}').html_safe % { link_to_kubernetes_engine: link_to_kubernetes_engine }
%li
- - link_to_requirements = link_to(s_('ClusterIntegration|meets the requirements'), 'https://cloud.google.com/kubernetes-engine/docs/quickstart', target: '_blank', rel: 'noopener noreferrer')
+ - link_to_requirements = link_to(s_('ClusterIntegration|meets the requirements'), 'https://cloud.google.com/kubernetes-engine/docs/quickstart?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters').html_safe % { link_to_requirements: link_to_requirements }
%li
- - link_to_container_project = link_to(s_('ClusterIntegration|Google Kubernetes Engine project'), 'https://console.cloud.google.com/home/dashboard', target: '_blank', rel: 'noopener noreferrer')
+ - link_to_container_project = link_to(s_('ClusterIntegration|Google Kubernetes Engine project'), 'https://console.cloud.google.com/home/dashboard?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below').html_safe % { link_to_container_project: link_to_container_project }
--
cgit v1.2.1
From 56469fc7ec4d608db43fc0f961133236e1b38599 Mon Sep 17 00:00:00 2001
From: Phil Hughes
Date: Thu, 11 Jan 2018 10:28:54 +0000
Subject: Uses `callDefault`
---
app/assets/javascripts/dispatcher.js | 44 +++++++++++++++++++++++++++---------
1 file changed, 33 insertions(+), 11 deletions(-)
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index d0073a1a403..3b3d08d6724 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -440,10 +440,14 @@ import Activities from './activities';
break;
case 'admin:groups:create':
case 'admin:groups:new':
- import('./pages/admin/groups/new').then(m => m.default()).catch(fail);
+ import('./pages/admin/groups/new')
+ .then(callDefault)
+ .catch(fail);
break;
case 'admin:groups:edit':
- import('./pages/admin/groups/edit').then(m => m.default()).catch(fail);
+ import('./pages/admin/groups/edit')
+ .then(callDefault)
+ .catch(fail);
break;
case 'groups:edit':
groupAvatar();
@@ -562,7 +566,9 @@ import Activities from './activities';
import('./pages/import/fogbugz/new_user_map').then(m => m.default()).catch(fail);
break;
case 'admin:impersonation_tokens:index':
- import('./pages/admin/impersonation_tokens').then(m => m.default()).catch(fail);
+ import('./pages/admin/impersonation_tokens')
+ .then(callDefault)
+ .catch(fail);
break;
case 'profiles:personal_access_tokens:index':
new DueDateSelectors();
@@ -599,35 +605,51 @@ import Activities from './activities';
// needed in rspec
gl.u2fAuthenticate = u2fAuthenticate;
case 'admin':
- import('./pages/admin').then(m => m.default()).catch(fail);
+ import('./pages/admin')
+ .then(callDefault)
+ .catch(fail);
switch (path[1]) {
case 'broadcast_messages':
- import('./pages/admin/broadcast_messages').then(m => m.default()).catch(fail);
+ import('./pages/admin/broadcast_messages')
+ .then(callDefault)
+ .catch(fail);
break;
case 'cohorts':
- import('./pages/admin/cohorts').then(m => m.default()).catch(fail);
+ import('./pages/admin/cohorts')
+ .then(callDefault)
+ .catch(fail);
break;
case 'groups':
switch (path[2]) {
case 'show':
- import('./pages/admin/groups/show').then(m => m.default()).catch(fail);
+ import('./pages/admin/groups/show')
+ .then(callDefault)
+ .catch(fail);
break;
}
break;
case 'projects':
- import('./pages/admin/projects').then(m => m.default()).catch(fail);
+ import('./pages/admin/projects')
+ .then(callDefault)
+ .catch(fail);
break;
case 'labels':
switch (path[2]) {
case 'new':
- import('./pages/admin/labels/new').then(m => m.default()).catch(fail);
+ import('./pages/admin/labels/new')
+ .then(callDefault)
+ .catch(fail);
break;
case 'edit':
- import('./pages/admin/labels/edit').then(m => m.default()).catch(fail);
+ import('./pages/admin/labels/edit')
+ .then(callDefault)
+ .catch(fail);
break;
}
case 'abuse_reports':
- import('./pages/admin/abuse_reports').then(m => m.default()).catch(fail);
+ import('./pages/admin/abuse_reports')
+ .then(callDefault)
+ .catch(fail);
break;
}
break;
--
cgit v1.2.1
From a3ab8aa3bbcf83c80e8f6195994bd531507e7348 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 12:00:22 +0100
Subject: Populate QA factory product with data from a page
---
qa/qa/factory/base.rb | 4 +++-
qa/qa/factory/product.rb | 15 ++++++++-------
qa/spec/factory/base_spec.rb | 28 ++++++++++++++++++++++++----
qa/spec/factory/product_spec.rb | 21 ++-------------------
4 files changed, 37 insertions(+), 31 deletions(-)
diff --git a/qa/qa/factory/base.rb b/qa/qa/factory/base.rb
index c7202d4ae65..bd66b74a164 100644
--- a/qa/qa/factory/base.rb
+++ b/qa/qa/factory/base.rb
@@ -13,7 +13,7 @@ module QA
end
def self.fabricate!(*args)
- Factory::Product.populate!(new) do |factory|
+ new.tap do |factory|
yield factory if block_given?
dependencies.each do |name, signature|
@@ -21,6 +21,8 @@ module QA
end
factory.fabricate!(*args)
+
+ return Factory::Product.populate!(self)
end
end
diff --git a/qa/qa/factory/product.rb b/qa/qa/factory/product.rb
index 2558350f8a3..d004e642f9b 100644
--- a/qa/qa/factory/product.rb
+++ b/qa/qa/factory/product.rb
@@ -7,8 +7,7 @@ module QA
Attribute = Struct.new(:name, :block)
- def initialize(factory)
- @factory = factory
+ def initialize
@location = current_url
end
@@ -17,11 +16,13 @@ module QA
end
def self.populate!(factory)
- raise ArgumentError unless block_given?
-
- yield factory
-
- new(factory)
+ new.tap do |product|
+ factory.attributes.each_value do |attribute|
+ product.instance_exec(&attribute.block).tap do |value|
+ product.define_singleton_method(attribute.name) { value }
+ end
+ end
+ end
end
end
end
diff --git a/qa/spec/factory/base_spec.rb b/qa/spec/factory/base_spec.rb
index d7cb9a770b5..90dd58e20fd 100644
--- a/qa/spec/factory/base_spec.rb
+++ b/qa/spec/factory/base_spec.rb
@@ -1,8 +1,9 @@
describe QA::Factory::Base do
+ let(:factory) { spy('factory') }
+ let(:product) { spy('product') }
+
describe '.fabricate!' do
subject { Class.new(described_class) }
- let(:factory) { spy('factory') }
- let(:product) { spy('product') }
before do
allow(QA::Factory::Product).to receive(:new).and_return(product)
@@ -89,14 +90,33 @@ describe QA::Factory::Base do
describe '.product' do
subject do
Class.new(described_class) do
- product :token do |factory, page|
- page.do_something!
+ product :token do
+ page.do_something_on_page!
+ 'resulting value'
end
end
end
it 'appends new product attribute' do
expect(subject.attributes).to be_one
+ expect(subject.attributes).to have_key(:token)
+ end
+
+ describe 'populating fabrication product with data' do
+ let(:page) { spy('page') }
+
+ before do
+ allow(subject).to receive(:new).and_return(factory)
+ allow(QA::Factory::Product).to receive(:new).and_return(product)
+ allow(product).to receive(:page).and_return(page)
+ end
+
+ it 'populates product after fabrication' do
+ subject.fabricate!
+
+ expect(page).to have_received(:do_something_on_page!)
+ expect(product.token).to eq 'resulting value'
+ end
end
end
end
diff --git a/qa/spec/factory/product_spec.rb b/qa/spec/factory/product_spec.rb
index 3d9e86a641b..fdfb1ec90cc 100644
--- a/qa/spec/factory/product_spec.rb
+++ b/qa/spec/factory/product_spec.rb
@@ -3,19 +3,8 @@ describe QA::Factory::Product do
let(:product) { spy('product') }
describe '.populate!' do
- it 'instantiates and yields factory' do
- expect(described_class).to receive(:new).with(factory)
-
- described_class.populate!(factory) do |instance|
- instance.something = 'string'
- end
-
- expect(factory).to have_received(:something=).with('string')
- end
-
it 'returns a fabrication product' do
- expect(described_class).to receive(:new)
- .with(factory).and_return(product)
+ expect(described_class).to receive(:new).and_return(product)
result = described_class.populate!(factory) do |instance|
instance.something = 'string'
@@ -23,11 +12,6 @@ describe QA::Factory::Product do
expect(result).to be product
end
-
- it 'raises unless block given' do
- expect { described_class.populate!(factory) }
- .to raise_error ArgumentError
- end
end
describe '.visit!' do
@@ -37,8 +21,7 @@ describe QA::Factory::Product do
allow_any_instance_of(described_class)
.to receive(:visit).and_return('visited some url')
- expect(described_class.new(factory).visit!)
- .to eq 'visited some url'
+ expect(subject.visit!).to eq 'visited some url'
end
end
end
--
cgit v1.2.1
From a2ae0f85127619e0e380c9cd5198508a801ab3bd Mon Sep 17 00:00:00 2001
From: Kushal Pandya
Date: Wed, 10 Jan 2018 12:56:03 +0530
Subject: Add modal dialog for leave group action
---
app/assets/javascripts/groups/components/app.vue | 48 ++++++++++++++++++------
1 file changed, 37 insertions(+), 11 deletions(-)
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue
index 400306759b2..e035ba462db 100644
--- a/app/assets/javascripts/groups/components/app.vue
+++ b/app/assets/javascripts/groups/components/app.vue
@@ -1,16 +1,20 @@
@@ -29,6 +39,8 @@
:title="title"
:data-clipboard-text="text"
v-tooltip
+ :data-container="tooltipContainer"
+ :data-placement="tooltipPlacement"
>
{
vm.$destroy();
});
- it('renders a button for clipboard with a tooltip', () => {
+ it('renders a button for clipboard', () => {
expect(vm.$el.tagName).toEqual('BUTTON');
expect(vm.$el.getAttribute('data-clipboard-text')).toEqual('copy me');
+ expect(vm.$el.querySelector('i').className).toEqual('fa fa-clipboard');
+ });
+
+ it('should have a tooltip with default values', () => {
expect(vm.$el.getAttribute('data-original-title')).toEqual('Copy this value into Clipboard!');
+ expect(vm.$el.getAttribute('data-placement')).toEqual('top');
+ expect(vm.$el.getAttribute('data-container')).toEqual(null);
});
});
--
cgit v1.2.1
From 7d0a1285a10fcb4735c20e21d83367159402a06d Mon Sep 17 00:00:00 2001
From: Constance Okoghenun
Date: Thu, 11 Jan 2018 12:21:19 +0100
Subject: Removed experimental feature flag unsed depenecy for
profiles/preferences
---
app/assets/javascripts/dispatcher.js | 9 +++------
app/assets/javascripts/pages/profiles/preferences/index.js | 3 ---
2 files changed, 3 insertions(+), 9 deletions(-)
delete mode 100644 app/assets/javascripts/pages/profiles/preferences/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 40c4a563db9..206f5bfaa6e 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -156,11 +156,6 @@ import Activities from './activities';
const filteredSearchEnabled = gl.FilteredSearchManager && document.querySelector('.filtered-search');
switch (page) {
- case 'profiles:preferences:show':
- import('./pages/profiles/preferences')
- .then(callDefault)
- .catch(fail);
- break;
case 'sessions:new':
new UsernameValidator();
new SigninTabsMemoizer();
@@ -512,7 +507,9 @@ import Activities from './activities';
new BlobViewer();
break;
case 'help:index':
- import('./pages/help').then(module => module.default()).catch(fail);
+ import('./pages/help')
+ .then(callDefault)
+ .catch(fail);
break;
case 'search:show':
new Search();
diff --git a/app/assets/javascripts/pages/profiles/preferences/index.js b/app/assets/javascripts/pages/profiles/preferences/index.js
deleted file mode 100644
index bc399bb7138..00000000000
--- a/app/assets/javascripts/pages/profiles/preferences/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import initExperimentalFlags from '../../../experimental_flags';
-
-export default () => initExperimentalFlags();
--
cgit v1.2.1
From d48df55177533922ad17913995203fb57c00289a Mon Sep 17 00:00:00 2001
From: Mark Fletcher
Date: Thu, 11 Jan 2018 11:23:42 +0000
Subject: Fix external links in Snippets API documentation
---
doc/api/snippets.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/doc/api/snippets.md b/doc/api/snippets.md
index fdafbfb5b9e..b6a2833bb42 100644
--- a/doc/api/snippets.md
+++ b/doc/api/snippets.md
@@ -2,7 +2,7 @@
> [Introduced][ce-6373] in GitLab 8.15.
-### Snippet visibility level
+## Snippet visibility level
Snippets in GitLab can be either private, internal, or public.
You can set it with the `visibility` field in the snippet.
@@ -265,4 +265,5 @@ Example response:
}
```
-[ce-[ce-29508]: https://gitlab.com/gitlab-org/gitlab-ce/issues/29508]: https://gitlab.com/gitlab-org/gitlab-ce/issues/29508
+[ce-6373]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6373
+[ce-29508]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12655
--
cgit v1.2.1
From af1680ab2d46d82cb7b4c32f0eca6ad682428bb0 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 12:26:09 +0100
Subject: Populate QA project factory product with project name
---
qa/qa/factory/resource/project.rb | 4 ++++
qa/qa/specs/features/project/create_spec.rb | 4 +++-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/qa/qa/factory/resource/project.rb b/qa/qa/factory/resource/project.rb
index 07c2e3086d1..7df2dc6618c 100644
--- a/qa/qa/factory/resource/project.rb
+++ b/qa/qa/factory/resource/project.rb
@@ -13,6 +13,10 @@ module QA
@description = 'My awesome project'
end
+ product :name do
+ Page::Project::Show.act { project_name }
+ end
+
def fabricate!
group.visit!
diff --git a/qa/qa/specs/features/project/create_spec.rb b/qa/qa/specs/features/project/create_spec.rb
index 61c19378ae0..b1c07249892 100644
--- a/qa/qa/specs/features/project/create_spec.rb
+++ b/qa/qa/specs/features/project/create_spec.rb
@@ -4,11 +4,13 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
- Factory::Resource::Project.fabricate! do |project|
+ created_project = Factory::Resource::Project.fabricate! do |project|
project.name = 'awesome-project'
project.description = 'create awesome project test'
end
+ expect(created_project.name).to match /^awesome-project-\h{16}$/
+
expect(page).to have_content(
/Project \S?awesome-project\S+ was successfully created/
)
--
cgit v1.2.1
From 0cc25f0f1b5e672e76fa93be8bf5ec553f10699a Mon Sep 17 00:00:00 2001
From: Andrew Newdigate
Date: Thu, 11 Jan 2018 12:05:55 +0000
Subject: Update end_to_end_tests.md
---
doc/development/testing_guide/end_to_end_tests.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/development/testing_guide/end_to_end_tests.md b/doc/development/testing_guide/end_to_end_tests.md
index abe5b06e0f0..5b4f6511f04 100644
--- a/doc/development/testing_guide/end_to_end_tests.md
+++ b/doc/development/testing_guide/end_to_end_tests.md
@@ -25,7 +25,7 @@ It is possible to run end-to-end tests (eventually being run within a
the `package-qa` manual action, that should be present in a merge request
widget.
-Mmanual action that starts end-to-end tests is also available in merge requests
+Manual 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 e21939fa44f46a863e55350d5993af041ed5e505 Mon Sep 17 00:00:00 2001
From: Sean McGivern
Date: Thu, 11 Jan 2018 12:28:28 +0000
Subject: Remove call to ProjectTeam#<< in MR API spec
---
spec/requests/api/merge_requests_spec.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 6c0ebf4fc82..4eae3e50602 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -585,7 +585,7 @@ describe API::MergeRequests do
project = create(:project, public_builds: false)
merge_request = create(:merge_request, :simple, source_project: project)
guest = create(:user)
- project.team << [guest, :guest]
+ project.add_guest(guest)
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/pipelines", guest)
--
cgit v1.2.1
From 9d766d2ecfa368d6d4dcfc298794e5706d4814b0 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 13:54:33 +0100
Subject: Define QA project pages views / selectors
---
app/views/projects/_new_project_fields.html.haml | 2 +-
qa/qa/page/project/new.rb | 18 ++++++++++--------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml
index a78a8e5d628..bd99eb93cc8 100644
--- a/app/views/projects/_new_project_fields.html.haml
+++ b/app/views/projects/_new_project_fields.html.haml
@@ -9,7 +9,7 @@
- if current_user.can_select_namespace?
.input-group-addon
= root_url
- = f.select :namespace_id, namespaces_options(namespace_id_from(params) || :current_user, display_path: true, extra_group: namespace_id_from(params)), {}, { class: 'select2 js-select-namespace', tabindex: 1}
+ = f.select :namespace_id, namespaces_options(namespace_id_from(params) || :current_user, display_path: true, extra_group: namespace_id_from(params)), {}, { class: 'select2 js-select-namespace qa-project-namespace-select', tabindex: 1}
- else
.input-group-addon.static-namespace
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index a87313b2cb9..1f23de29642 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -2,16 +2,18 @@ module QA
module Page
module Project
class New < Page::Base
- ##
- # TODO, define all selectors required by this page object
- #
- # See gitlab-org/gitlab-qa#154
- #
- view 'app/views/projects/new.html.haml'
+ view 'projects/_new_project_fields.html.haml' do
+ element :project_namespace_select
+ element :project_namespace_field, 'select :namespace_id'
+ element :project_path, 'text_field :path'
+ element :project_description, 'text_area :description'
+ element :project_create_button, "submit 'Create project'"
+ end
def choose_test_namespace
- find('#s2id_project_namespace_id').click
- find('.select2-result-label', text: Runtime::Namespace.name).click
+ click_element :project_namespace_select
+
+ first('li', text: Runtime::Namespace.name).click
end
def choose_name(name)
--
cgit v1.2.1
From d2f83a10ea52a4fcbf380ddf01685bbc6ad7ee7a Mon Sep 17 00:00:00 2001
From: Nick Thomas
Date: Wed, 10 Jan 2018 18:10:42 +0000
Subject: Ensure that emails contain absolute, rather than relative, links to
user uploads
---
...2-respect-only-path-in-relative-link-filter.yml | 5 +++
lib/banzai/filter/relative_link_filter.rb | 15 +++++--
.../lib/banzai/filter/relative_link_filter_spec.rb | 48 ++++++++++++++++------
3 files changed, 51 insertions(+), 17 deletions(-)
create mode 100644 changelogs/unreleased/41882-respect-only-path-in-relative-link-filter.yml
diff --git a/changelogs/unreleased/41882-respect-only-path-in-relative-link-filter.yml b/changelogs/unreleased/41882-respect-only-path-in-relative-link-filter.yml
new file mode 100644
index 00000000000..d4b7ec6a3b5
--- /dev/null
+++ b/changelogs/unreleased/41882-respect-only-path-in-relative-link-filter.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure that emails contain absolute, rather than relative, links to user uploads
+merge_request: 16364
+author:
+type: fixed
diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb
index 5c197afd782..f6169b2c85d 100644
--- a/lib/banzai/filter/relative_link_filter.rb
+++ b/lib/banzai/filter/relative_link_filter.rb
@@ -50,15 +50,22 @@ module Banzai
end
def process_link_to_upload_attr(html_attr)
- uri_parts = [html_attr.value]
+ path_parts = [html_attr.value]
if group
- uri_parts.unshift(relative_url_root, 'groups', group.full_path, '-')
+ path_parts.unshift(relative_url_root, 'groups', group.full_path, '-')
elsif project
- uri_parts.unshift(relative_url_root, project.full_path)
+ path_parts.unshift(relative_url_root, project.full_path)
end
- html_attr.value = File.join(*uri_parts)
+ path = File.join(*path_parts)
+
+ html_attr.value =
+ if context[:only_path]
+ path
+ else
+ URI.join(Gitlab.config.gitlab.base_url, path).to_s
+ end
end
def process_link_to_repository_attr(html_attr)
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index f38f0776303..7e17457ce70 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -8,7 +8,8 @@ describe Banzai::Filter::RelativeLinkFilter do
group: group,
project_wiki: project_wiki,
ref: ref,
- requested_path: requested_path
+ requested_path: requested_path,
+ only_path: only_path
})
described_class.call(doc, contexts)
@@ -37,6 +38,7 @@ describe Banzai::Filter::RelativeLinkFilter do
let(:commit) { project.commit(ref) }
let(:project_wiki) { nil }
let(:requested_path) { '/' }
+ let(:only_path) { true }
shared_examples :preserve_unchanged do
it 'does not modify any relative URL in anchor' do
@@ -240,26 +242,35 @@ describe Banzai::Filter::RelativeLinkFilter do
let(:commit) { nil }
let(:ref) { nil }
let(:requested_path) { nil }
+ let(:upload_path) { '/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg' }
+ let(:relative_path) { "/#{project.full_path}#{upload_path}" }
context 'to a project upload' do
+ context 'with an absolute URL' do
+ let(:absolute_path) { Gitlab.config.gitlab.url + relative_path }
+ let(:only_path) { false }
+
+ it 'rewrites the link correctly' do
+ doc = filter(link(upload_path))
+
+ expect(doc.at_css('a')['href']).to eq(absolute_path)
+ end
+ end
+
it 'rebuilds relative URL for a link' do
- doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('a')['href'])
- .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ doc = filter(link(upload_path))
+ expect(doc.at_css('a')['href']).to eq(relative_path)
- doc = filter(nested(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')))
- expect(doc.at_css('a')['href'])
- .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ doc = filter(nested(link(upload_path)))
+ expect(doc.at_css('a')['href']).to eq(relative_path)
end
it 'rebuilds relative URL for an image' do
- doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('img')['src'])
- .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ doc = filter(image(upload_path))
+ expect(doc.at_css('img')['src']).to eq(relative_path)
- doc = filter(nested(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')))
- expect(doc.at_css('img')['src'])
- .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ doc = filter(nested(image(upload_path)))
+ expect(doc.at_css('img')['src']).to eq(relative_path)
end
it 'does not modify absolute URL' do
@@ -288,6 +299,17 @@ describe Banzai::Filter::RelativeLinkFilter do
let(:project) { nil }
let(:relative_path) { "/groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" }
+ context 'with an absolute URL' do
+ let(:absolute_path) { Gitlab.config.gitlab.url + relative_path }
+ let(:only_path) { false }
+
+ it 'rewrites the link correctly' do
+ doc = filter(upload_link)
+
+ expect(doc.at_css('a')['href']).to eq(absolute_path)
+ end
+ end
+
it 'rewrites the link correctly' do
doc = filter(upload_link)
--
cgit v1.2.1
From 3e6e09c458ea67f156e43d2829bdce3138c5cf03 Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 14:14:16 +0100
Subject: Use full QA sandbox group path when creating a project
---
qa/qa/page/project/new.rb | 2 +-
qa/qa/runtime/namespace.rb | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index 1f23de29642..19428ede79e 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -13,7 +13,7 @@ module QA
def choose_test_namespace
click_element :project_namespace_select
- first('li', text: Runtime::Namespace.name).click
+ first('li', text: Runtime::Namespace.path).click
end
def choose_name(name)
diff --git a/qa/qa/runtime/namespace.rb b/qa/qa/runtime/namespace.rb
index b00e925986b..a72c2d21898 100644
--- a/qa/qa/runtime/namespace.rb
+++ b/qa/qa/runtime/namespace.rb
@@ -11,6 +11,10 @@ module QA
'qa-test-' + time.strftime('%d-%m-%Y-%H-%M-%S')
end
+ def path
+ "#{sandbox_name}/#{name}"
+ end
+
def sandbox_name
'gitlab-qa-sandbox'
end
--
cgit v1.2.1
From 760d611ba128f24b30d9ca23decab7e64052004f Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 13:20:06 +0100
Subject: Copy-edit docs about GitLab QA page objects
---
qa/qa/page/README.md | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/qa/qa/page/README.md b/qa/qa/page/README.md
index 896654c9a9c..f72fbfeafca 100644
--- a/qa/qa/page/README.md
+++ b/qa/qa/page/README.md
@@ -19,18 +19,18 @@ We need page objects, because we need to reduce duplication and avoid problems
whenever someone changes some selectors in GitLab's source code.
Imagine that we have a hundred specs in GitLab QA, and we need to sign into
-GitLab each time, before we make assertions. Without page object one would need
-to rely on volatile helpers or invoke Capybara methods directly. Imagine
+GitLab each time, before we make assertions. Without a page object one would
+need to rely on volatile helpers or invoke Capybara methods directly. Imagine
invoking `fill_in :user_login` in every `*_spec.rb` file / test example.
When someone later changes `t.text_field :login` in the view associated with
-this page to `t.text_field :username` it will generate different field ID,
-what would effectively break all 100 tests.
+this page to `t.text_field :username` it will generate a different field
+identifier, what would effectively break all tests.
-Because we are now using `Page::Main::Login.act { sign_in_using_credentials }`
-everywhere, where we want to sign into GitLab, page object is the single source
-of truth, and we will need to update `fill_in :user_login`
-to `fill_in :user_username` only in a one place as well.
+Because we are using `Page::Main::Login.act { sign_in_using_credentials }`
+everywhere, when we want to sign into GitLab, the page object is the single
+source of truth, and we will need to update `fill_in :user_login`
+to `fill_in :user_username` only in a one place.
## What problems did we have in the past?
@@ -38,9 +38,9 @@ We do not run QA tests for every commit, because of performance reasons, and
the time it would take to build packages and test everything.
That is why when someone changes `t.text_field :login` to
-`t.text_field :username` in new session view we won't know about this change
-until our GitLab QA nightly pipeline runs, or someone triggers `package-qa`
-action in their merge request.
+`t.text_field :username` in the _new session_ view we won't know about this
+change until our GitLab QA nightly pipeline fails, or until someone triggers
+`package-qa` action in their merge request.
Obviously such a change would break all tests. We call this problem a _fragile
tests problem_.
@@ -53,11 +53,11 @@ problem by introducing coupling between GitLab CE / EE views and GitLab QA.
Currently, when you add a new `Page::Base` derived class, you will also need to
define all selectors that your page objects depends on.
-Whenever your push your code to CE / EE repository, `qa:selectors` sanity test
+Whenever you push your code to CE / EE repository, `qa:selectors` sanity test
job is going to be run as a part of a CI pipeline.
This test is going to validate all page objects that we have implemented in
-`qa/page` directory. When if fails, you will be notified about missing
+`qa/page` directory. When it fails, you will be notified about missing
or invalid views / selectors definition.
## How to properly implement a page object?
--
cgit v1.2.1
From 0619c537ac1ae57233f493f95b3e6c8a119fdb8d Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 14:17:51 +0100
Subject: Fix path to QA new project page object view
---
qa/qa/page/project/new.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index 19428ede79e..9b1438f76d5 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -2,7 +2,7 @@ module QA
module Page
module Project
class New < Page::Base
- view 'projects/_new_project_fields.html.haml' do
+ view 'app/views/projects/_new_project_fields.html.haml' do
element :project_namespace_select
element :project_namespace_field, 'select :namespace_id'
element :project_path, 'text_field :path'
--
cgit v1.2.1
From bf05a7e77ddecace7e231abbde18cbd1e42d528a Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon
Date: Thu, 11 Jan 2018 14:27:11 +0100
Subject: Add selectors coupling for QA project show page object
---
app/views/projects/_home_panel.html.haml | 2 +-
app/views/shared/_clone_panel.html.haml | 2 +-
qa/qa/page/project/show.rb | 22 ++++++++++++++--------
3 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 1d644dda177..b565f14747a 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -4,7 +4,7 @@
.limit-container-width{ class: container_class }
.avatar-container.s70.project-avatar
= project_icon(@project, alt: @project.name, class: 'avatar s70 avatar-tile')
- %h1.project-title
+ %h1.project-title.qa-project-name
= @project.name
%span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@project) }
= visibility_level_icon(@project.visibility_level, fw: false)
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 1cba4fc6c41..687cd4d1532 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -7,7 +7,7 @@
%span
= enabled_project_button(project, enabled_protocol)
- else
- %a#clone-dropdown.btn.clone-dropdown-btn{ href: '#', data: { toggle: 'dropdown' } }
+ %a#clone-dropdown.btn.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } }
%span
= default_clone_protocol.upcase
= icon('caret-down')
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index 90967e6cc15..c8af5ba6280 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -2,15 +2,21 @@ module QA
module Page
module Project
class Show < Page::Base
- ##
- # TODO, define all selectors required by this page object
- #
- # See gitlab-org/gitlab-qa#154
- #
- view 'app/views/projects/show.html.haml'
+ view 'app/views/shared/_clone_panel.html.haml' do
+ element :clone_dropdown
+ element :clone_options_dropdown, '.clone-options-dropdown'
+ end
+
+ view 'app/views/shared/_clone_panel.html.haml' do
+ element :project_repository_location, 'text_field_tag :project_clone'
+ end
+
+ view 'app/views/projects/_home_panel.html.haml' do
+ element :project_name
+ end
def choose_repository_clone_http
- find('#clone-dropdown').click
+ click_element :clone_dropdown
page.within('.clone-options-dropdown') do
click_link('HTTP')
@@ -22,7 +28,7 @@ module QA
end
def project_name
- find('.project-title').text
+ find('.qa-project-name').text
end
def wait_for_push
--
cgit v1.2.1
From 831019412f32089935755215db609b78794f997a Mon Sep 17 00:00:00 2001
From: Ahmad Sherif
Date: Thu, 28 Dec 2017 19:07:21 +0100
Subject: Migrate merged_branch_names to Gitaly
Closes gitaly#851
---
lib/gitlab/git/repository.rb | 33 ++++++++++++-----
lib/gitlab/gitaly_client/ref_service.rb | 31 ++++++++++++----
spec/lib/gitlab/git/repository_spec.rb | 66 +++++++++++++++++++--------------
3 files changed, 85 insertions(+), 45 deletions(-)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 283134e043e..05fa44b48c7 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -571,7 +571,21 @@ module Gitlab
end
def merged_branch_names(branch_names = [])
- Set.new(git_merged_branch_names(branch_names))
+ return [] unless root_ref
+
+ root_sha = find_branch(root_ref)&.target
+
+ return [] unless root_sha
+
+ branches = gitaly_migrate(:merged_branch_names) do |is_enabled|
+ if is_enabled
+ gitaly_merged_branch_names(branch_names, root_sha)
+ else
+ git_merged_branch_names(branch_names, root_sha)
+ end
+ end
+
+ Set.new(branches)
end
# Return an array of Diff objects that represent the diff
@@ -1475,14 +1489,7 @@ module Gitlab
sort_branches(branches, sort_by)
end
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/695
- def git_merged_branch_names(branch_names = [])
- return [] unless root_ref
-
- root_sha = find_branch(root_ref)&.target
-
- return [] unless root_sha
-
+ def git_merged_branch_names(branch_names, root_sha)
git_arguments =
%W[branch --merged #{root_sha}
--format=%(refname:short)\ %(objectname)] + branch_names
@@ -1496,6 +1503,14 @@ module Gitlab
end
end
+ def gitaly_merged_branch_names(branch_names, root_sha)
+ qualified_branch_names = branch_names.map { |b| "refs/heads/#{b}" }
+
+ gitaly_ref_client.merged_branches(qualified_branch_names)
+ .reject { |b| b.target == root_sha }
+ .map(&:name)
+ end
+
def process_count_commits_options(options)
if options[:from] || options[:to]
ref =
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index 5bce1009878..f8e2a27f3fe 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -14,12 +14,18 @@ module Gitlab
request = Gitaly::FindAllBranchesRequest.new(repository: @gitaly_repo)
response = GitalyClient.call(@storage, :ref_service, :find_all_branches, request)
- response.flat_map do |message|
- message.branches.map do |branch|
- target_commit = Gitlab::Git::Commit.decorate(@repository, branch.target)
- Gitlab::Git::Branch.new(@repository, branch.name, branch.target.id, target_commit)
- end
- end
+ consume_find_all_branches_response(response)
+ end
+
+ def merged_branches(branch_names = [])
+ request = Gitaly::FindAllBranchesRequest.new(
+ repository: @gitaly_repo,
+ merged_only: true,
+ merged_branches: branch_names.map { |s| encode_binary(s) }
+ )
+ response = GitalyClient.call(@storage, :ref_service, :find_all_branches, request)
+
+ consume_find_all_branches_response(response)
end
def default_branch_name
@@ -62,7 +68,7 @@ module Gitlab
request = Gitaly::FindLocalBranchesRequest.new(repository: @gitaly_repo)
request.sort_by = sort_by_param(sort_by) if sort_by
response = GitalyClient.call(@storage, :ref_service, :find_local_branches, request)
- consume_branches_response(response)
+ consume_find_local_branches_response(response)
end
def tags
@@ -151,7 +157,7 @@ module Gitlab
enum_value
end
- def consume_branches_response(response)
+ def consume_find_local_branches_response(response)
response.flat_map do |message|
message.branches.map do |gitaly_branch|
Gitlab::Git::Branch.new(
@@ -164,6 +170,15 @@ module Gitlab
end
end
+ def consume_find_all_branches_response(response)
+ response.flat_map do |message|
+ message.branches.map do |branch|
+ target_commit = Gitlab::Git::Commit.decorate(@repository, branch.target)
+ Gitlab::Git::Branch.new(@repository, branch.name, branch.target.id, target_commit)
+ end
+ end
+ end
+
def consume_tags_response(response)
response.flat_map do |message|
message.tags.map { |gitaly_tag| Util.gitlab_tag_from_gitaly_tag(@repository, gitaly_tag) }
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index f346a345f00..f4e781c599e 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1283,48 +1283,58 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe '#merged_branch_names' do
- context 'when branch names are passed' do
- it 'only returns the names we are asking' do
- names = repository.merged_branch_names(%w[merge-test])
+ shared_examples 'finding merged branch names' do
+ context 'when branch names are passed' do
+ it 'only returns the names we are asking' do
+ names = repository.merged_branch_names(%w[merge-test])
- expect(names).to contain_exactly('merge-test')
- end
+ expect(names).to contain_exactly('merge-test')
+ end
- it 'does not return unmerged branch names' do
- names = repository.merged_branch_names(%w[feature])
+ it 'does not return unmerged branch names' do
+ names = repository.merged_branch_names(%w[feature])
- expect(names).to be_empty
+ expect(names).to be_empty
+ end
end
- end
- context 'when no root ref is available' do
- it 'returns empty list' do
- project = create(:project, :empty_repo)
+ context 'when no root ref is available' do
+ it 'returns empty list' do
+ project = create(:project, :empty_repo)
- names = project.repository.merged_branch_names(%w[feature])
+ names = project.repository.merged_branch_names(%w[feature])
- expect(names).to be_empty
+ expect(names).to be_empty
+ end
end
- end
- context 'when no branch names are specified' do
- before do
- repository.create_branch('identical', 'master')
- end
+ context 'when no branch names are specified' do
+ before do
+ repository.create_branch('identical', 'master')
+ end
- after do
- ensure_seeds
- end
+ after do
+ ensure_seeds
+ end
- it 'returns all merged branch names except for identical one' do
- names = repository.merged_branch_names
+ it 'returns all merged branch names except for identical one' do
+ names = repository.merged_branch_names
- expect(names).to include('merge-test')
- expect(names).to include('fix-mode')
- expect(names).not_to include('feature')
- expect(names).not_to include('identical')
+ expect(names).to include('merge-test')
+ expect(names).to include('fix-mode')
+ expect(names).not_to include('feature')
+ expect(names).not_to include('identical')
+ end
end
end
+
+ context 'when Gitaly merged_branch_names feature is enabled' do
+ it_behaves_like 'finding merged branch names'
+ end
+
+ context 'when Gitaly merged_branch_names feature is disabled', :disable_gitaly do
+ it_behaves_like 'finding merged branch names'
+ end
end
describe "#ls_files" do
--
cgit v1.2.1
From 16855c8b9fc07dfd6d0c1c3fbbeecee47cde25ff Mon Sep 17 00:00:00 2001
From: Oswaldo Ferreira
Date: Thu, 11 Jan 2018 12:27:52 -0200
Subject: Update CHANGELOG.md for 10.2.6
[ci skip]
---
CHANGELOG.md | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9fac24c2447..e88ab5b6565 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -193,6 +193,21 @@ entry.
- Clean up schema of the "merge_requests" table.
+## 10.2.6 (2018-01-11)
+
+### Security (9 changes, 1 of them is from the community)
+
+- Fix writable shared deploy keys.
+- Filter out sensitive fields from the project services API. (Robert Schilling)
+- Fix RCE via project import mechanism.
+- Fixed IPython notebook output not being sanitized.
+- Prevent OAuth login POST requests when a provider has been disabled.
+- Prevent a SQL injection in the MilestonesFinder.
+- Check user authorization for source and target projects when creating a merge request.
+- Fix path traversal in gitlab-ci.yml cache:key.
+- Fix XSS vulnerability in pipeline job trace.
+
+
## 10.2.5 (2017-12-15)
### Fixed (8 changes)
--
cgit v1.2.1
From 48e638f6917b292b406d71f29b4daaf7058f68e1 Mon Sep 17 00:00:00 2001
From: Constance Okoghenun
Date: Thu, 11 Jan 2018 16:11:06 +0000
Subject: Refactored project:n* imports in dispatcher.js
---
app/assets/javascripts/dispatcher.js | 29 +++++++---------------
.../pages/projects/pipelines/builds/index.js | 16 ++++++++++++
.../pages/projects/pipelines/new/index.js | 5 ++++
.../pages/projects/project_members/index.js | 12 +++++++++
4 files changed, 42 insertions(+), 20 deletions(-)
create mode 100644 app/assets/javascripts/pages/projects/pipelines/builds/index.js
create mode 100644 app/assets/javascripts/pages/projects/pipelines/new/index.js
create mode 100644 app/assets/javascripts/pages/projects/project_members/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index e35f53081ec..2c1809c929c 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -12,7 +12,6 @@ import notificationsDropdown from './notifications_dropdown';
import groupAvatar from './group_avatar';
import GroupLabelSubscription from './group_label_subscription';
import LineHighlighter from './line_highlighter';
-import groupsSelect from './groups_select';
import NewCommitForm from './new_commit_form';
import Project from './project';
import projectAvatar from './project_avatar';
@@ -40,7 +39,6 @@ import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import UserCallout from './user_callout';
import ShortcutsWiki from './shortcuts_wiki';
-import Pipelines from './pipelines';
import BlobViewer from './blob/viewer/index';
import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
import UsersSelect from './users_select';
@@ -390,23 +388,16 @@ import Activities from './activities';
break;
case 'projects:pipelines:new':
case 'projects:pipelines:create':
- new NewBranchForm($('.js-new-pipeline-form'));
+ import('./pages/projects/pipelines/new')
+ .then(callDefault)
+ .catch(fail);
break;
case 'projects:pipelines:builds':
case 'projects:pipelines:failures':
case 'projects:pipelines:show':
- const { controllerAction } = document.querySelector('.js-pipeline-container').dataset;
- const pipelineStatusUrl = `${document.querySelector('.js-pipeline-tab-link a').getAttribute('href')}/status.json`;
-
- new Pipelines({
- initTabs: true,
- pipelineStatusUrl,
- tabsOptions: {
- action: controllerAction,
- defaultAction: 'pipelines',
- parentEl: '.pipelines-tabs',
- },
- });
+ import('./pages/projects/pipelines/builds')
+ .then(callDefault)
+ .catch(fail);
break;
case 'groups:activity':
new Activities();
@@ -428,11 +419,9 @@ import Activities from './activities';
new UsersSelect();
break;
case 'projects:project_members:index':
- memberExpirationDate('.js-access-expiration-date-groups');
- groupsSelect();
- memberExpirationDate();
- new Members();
- new UsersSelect();
+ import('./pages/projects/project_members/')
+ .then(callDefault)
+ .catch(fail);
break;
case 'groups:new':
case 'groups:create':
diff --git a/app/assets/javascripts/pages/projects/pipelines/builds/index.js b/app/assets/javascripts/pages/projects/pipelines/builds/index.js
new file mode 100644
index 00000000000..060a78b427e
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/pipelines/builds/index.js
@@ -0,0 +1,16 @@
+import Pipelines from '../../../../pipelines';
+
+export default () => {
+ const { controllerAction } = document.querySelector('.js-pipeline-container').dataset;
+ const pipelineStatusUrl = `${document.querySelector('.js-pipeline-tab-link a').getAttribute('href')}/status.json`;
+
+ new Pipelines({ // eslint-disable-line no-new
+ initTabs: true,
+ pipelineStatusUrl,
+ tabsOptions: {
+ action: controllerAction,
+ defaultAction: 'pipelines',
+ parentEl: '.pipelines-tabs',
+ },
+ });
+};
diff --git a/app/assets/javascripts/pages/projects/pipelines/new/index.js b/app/assets/javascripts/pages/projects/pipelines/new/index.js
new file mode 100644
index 00000000000..c54cc62bf05
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/pipelines/new/index.js
@@ -0,0 +1,5 @@
+import NewBranchForm from '../../../../new_branch_form';
+
+export default () => {
+ new NewBranchForm($('.js-new-pipeline-form')); // eslint-disable-line no-new
+};
diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js
new file mode 100644
index 00000000000..f4643e7dba0
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/project_members/index.js
@@ -0,0 +1,12 @@
+import memberExpirationDate from '../../../member_expiration_date';
+import UsersSelect from '../../../users_select';
+import groupsSelect from '../../../groups_select';
+import Members from '../../../members';
+
+export default () => {
+ memberExpirationDate('.js-access-expiration-date-groups');
+ groupsSelect();
+ memberExpirationDate();
+ new Members(); // eslint-disable-line no-new
+ new UsersSelect(); // eslint-disable-line no-new
+};
--
cgit v1.2.1
From 403fbe227dbcf42f9c21a758ce57ee7f09bfc8b1 Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Thu, 11 Jan 2018 16:19:59 +0000
Subject: Filter out build traces from logged parameters
---
config/application.rb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/config/application.rb b/config/application.rb
index 1110199b888..cd5e3d45bab 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -61,6 +61,7 @@ module Gitlab
# - Any parameter containing `secret`
# - Two-factor tokens (:otp_attempt)
# - Repo/Project Import URLs (:import_url)
+ # - Build traces (:trace)
# - Build variables (:variables)
# - GitLab Pages SSL cert/key info (:certificate, :encrypted_key)
# - Webhook URLs (:hook)
@@ -75,6 +76,7 @@ module Gitlab
key
otp_attempt
sentry_dsn
+ trace
variables
)
--
cgit v1.2.1
From 47b04690289303b3209a3b72df08fd0a6bd3233f Mon Sep 17 00:00:00 2001
From: Oswaldo Ferreira
Date: Thu, 11 Jan 2018 14:23:43 -0200
Subject: Update CHANGELOG.md for 10.1.6
[ci skip]
---
CHANGELOG.md | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e88ab5b6565..c29c289310d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -474,6 +474,20 @@ entry.
- Add Gitaly metrics to the performance bar.
+## 10.1.6 (2018-01-11)
+
+### Security (8 changes, 1 of them is from the community)
+
+- Fix writable shared deploy keys.
+- Filter out sensitive fields from the project services API. (Robert Schilling)
+- Fix RCE via project import mechanism.
+- Prevent OAuth login POST requests when a provider has been disabled.
+- Prevent a SQL injection in the MilestonesFinder.
+- Check user authorization for source and target projects when creating a merge request.
+- Fix path traversal in gitlab-ci.yml cache:key.
+- Fix XSS vulnerability in pipeline job trace.
+
+
## 10.1.5 (2017-12-07)
### Security (5 changes)
--
cgit v1.2.1
From 729f05f0e3c4835c91e20ccd1ddb630eb7ef4379 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=F0=9F=99=88=20=20jacopo=20beschi=20=F0=9F=99=89?=
Date: Thu, 11 Jan 2018 16:34:01 +0000
Subject: Adds Rubocop rule for line break around conditionals
---
app/controllers/admin/runners_controller.rb | 1 +
app/controllers/concerns/group_tree.rb | 1 +
app/controllers/concerns/routable_actions.rb | 1 +
app/controllers/metrics_controller.rb | 1 +
app/controllers/omniauth_callbacks_controller.rb | 3 +
app/controllers/projects/blob_controller.rb | 1 +
app/controllers/projects/deploy_keys_controller.rb | 1 +
app/controllers/projects/hooks_controller.rb | 1 +
.../merge_requests/creations_controller.rb | 1 +
app/controllers/projects_controller.rb | 1 +
app/controllers/sessions_controller.rb | 1 +
app/finders/group_descendants_finder.rb | 3 +
app/finders/group_projects_finder.rb | 1 +
app/helpers/markup_helper.rb | 1 +
app/helpers/nav_helper.rb | 1 +
app/helpers/snippets_helper.rb | 1 +
app/helpers/submodule_helper.rb | 1 +
app/helpers/todos_helper.rb | 1 +
app/models/application_setting.rb | 1 +
app/models/concerns/issuable.rb | 1 +
app/models/concerns/loaded_in_group_list.rb | 1 +
app/models/label.rb | 1 +
app/models/merge_request.rb | 1 +
app/models/network/graph.rb | 1 +
app/models/notification_recipient.rb | 1 +
app/models/project.rb | 1 +
app/models/project_services/hipchat_service.rb | 1 +
app/models/repository.rb | 1 +
app/models/service.rb | 1 +
app/services/create_deployment_service.rb | 1 +
app/workers/pages_worker.rb | 1 +
...18040-line-breaks-around-conditional-blocks.yml | 5 +
config/application.rb | 1 +
config/initializers/1_settings.rb | 2 +
config/initializers/devise.rb | 1 +
config/initializers/peek.rb | 2 +
db/migrate/20170928124105_create_fork_networks.rb | 1 +
.../20170928133643_create_fork_network_members.rb | 1 +
...220191323_add_index_on_namespaces_lower_name.rb | 2 +
...18200835_rename_users_with_renamed_namespace.rb | 1 +
features/steps/project/commits/commits.rb | 2 +
lib/api/helpers.rb | 1 +
lib/api/internal.rb | 1 +
lib/api/issues.rb | 1 +
lib/api/pipelines.rb | 1 +
lib/api/project_snippets.rb | 1 +
lib/api/projects.rb | 1 +
lib/api/repositories.rb | 1 +
lib/api/v3/members.rb | 1 +
lib/api/v3/merge_requests.rb | 1 +
lib/api/v3/project_snippets.rb | 1 +
lib/api/v3/projects.rb | 2 +
lib/api/v3/repositories.rb | 1 +
lib/api/v3/snippets.rb | 1 +
lib/backup/database.rb | 1 +
lib/backup/repository.rb | 1 +
lib/gitlab/ci/ansi2html.rb | 5 +
lib/gitlab/database/migration_helpers.rb | 1 +
.../v1/rename_projects.rb | 1 +
lib/gitlab/diff/highlight.rb | 1 +
lib/gitlab/ee_compat_check.rb | 2 +
.../email/handler/create_merge_request_handler.rb | 1 +
lib/gitlab/fogbugz_import/importer.rb | 3 +
lib/gitlab/git/repository.rb | 1 +
lib/gitlab/git/storage/forked_storage_check.rb | 1 +
lib/gitlab/gitaly_client/operation_service.rb | 1 +
lib/gitlab/google_code_import/importer.rb | 3 +
lib/gitlab/import_export/project_tree_restorer.rb | 1 +
lib/gitlab/import_export/relation_factory.rb | 1 +
lib/gitlab/kubernetes/helm/pod.rb | 1 +
lib/gitlab/ldap/config.rb | 1 +
lib/gitlab/metrics/influx_db.rb | 1 +
lib/gitlab/middleware/multipart.rb | 2 +
lib/gitlab/multi_collection_paginator.rb | 1 +
lib/gitlab/quick_actions/extractor.rb | 1 +
lib/gitlab/redis/wrapper.rb | 2 +
lib/gitlab/search_results.rb | 1 +
lib/gitlab/storage_check/cli.rb | 2 +
lib/gitlab/testing/request_blocker_middleware.rb | 2 +
lib/gitlab/timeless.rb | 1 +
lib/gitlab/upgrader.rb | 2 +
lib/gitlab/workhorse.rb | 1 +
lib/system_check/simple_executor.rb | 1 +
lib/tasks/gitlab/backup.rake | 2 +
lib/tasks/gitlab/check.rake | 3 +
lib/tasks/gitlab/cleanup.rake | 1 +
lib/tasks/gitlab/dev.rake | 1 +
lib/tasks/gitlab/gitaly.rake | 2 +
lib/tasks/gitlab/list_repos.rake | 1 +
lib/tasks/gitlab/update_templates.rake | 1 +
lib/tasks/gitlab/workhorse.rake | 2 +
lib/tasks/migrate/migrate_iids.rake | 3 +
rubocop/cop/line_break_around_conditional_block.rb | 119 ++++++
rubocop/rubocop.rb | 1 +
spec/factories/protected_branches.rb | 1 +
.../features/issues/bulk_assignment_labels_spec.rb | 1 +
spec/requests/api/commit_statuses_spec.rb | 1 +
spec/requests/api/runner_spec.rb | 1 +
.../line_break_around_conditional_block_spec.rb | 411 +++++++++++++++++++++
spec/services/projects/transfer_service_spec.rb | 1 +
spec/services/system_note_service_spec.rb | 1 +
.../features/discussion_comments_shared_example.rb | 2 +
spec/support/filtered_search_helpers.rb | 2 +
spec/support/generate-seed-repo-rb | 1 +
.../matchers/access_matchers_for_controller.rb | 1 +
spec/support/select2_helper.rb | 1 +
spec/support/stub_env.rb | 1 +
spec/support/test_env.rb | 1 +
spec/support/wait_for_requests.rb | 1 +
109 files changed, 673 insertions(+)
create mode 100644 changelogs/unreleased/18040-line-breaks-around-conditional-blocks.yml
create mode 100644 rubocop/cop/line_break_around_conditional_block.rb
create mode 100644 spec/rubocop/cop/line_break_around_conditional_block_spec.rb
diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb
index 38b808cdc31..4b01904f2a1 100644
--- a/app/controllers/admin/runners_controller.rb
+++ b/app/controllers/admin/runners_controller.rb
@@ -65,6 +65,7 @@ class Admin::RunnersController < Admin::ApplicationController
else
Project.all
end
+
@projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any?
@projects = @projects.page(params[:page]).per(30)
end
diff --git a/app/controllers/concerns/group_tree.rb b/app/controllers/concerns/group_tree.rb
index b10147835f3..b569029283f 100644
--- a/app/controllers/concerns/group_tree.rb
+++ b/app/controllers/concerns/group_tree.rb
@@ -8,6 +8,7 @@ module GroupTree
# Only show root groups if no parent-id is given
groups.where(parent_id: params[:parent_id])
end
+
@groups = @groups.with_selects_for_list(archived: params[:archived])
.sort(@sort = params[:sort])
.page(params[:page])
diff --git a/app/controllers/concerns/routable_actions.rb b/app/controllers/concerns/routable_actions.rb
index 4199da9cdf5..f745deb083c 100644
--- a/app/controllers/concerns/routable_actions.rb
+++ b/app/controllers/concerns/routable_actions.rb
@@ -32,6 +32,7 @@ module RoutableActions
if canonical_path.casecmp(requested_full_path) != 0
flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_full_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path."
end
+
redirect_to build_canonical_path(routable)
end
end
diff --git a/app/controllers/metrics_controller.rb b/app/controllers/metrics_controller.rb
index d81ad135198..33b682d2859 100644
--- a/app/controllers/metrics_controller.rb
+++ b/app/controllers/metrics_controller.rb
@@ -12,6 +12,7 @@ class MetricsController < ActionController::Base
)
"# Metrics are disabled, see: #{help_page}\n"
end
+
render text: response, content_type: 'text/plain; version=0.0.4'
end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index e3c18cba1dd..689d2e3db22 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -83,6 +83,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
if ticket
handle_service_ticket oauth['provider'], ticket
end
+
handle_omniauth
end
@@ -90,6 +91,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
if params['sid']
handle_service_ticket oauth['provider'], params['sid']
end
+
handle_omniauth
end
@@ -124,6 +126,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Only allow properly saved users to login.
if @user.persisted? && @user.valid?
log_audit_event(@user, with: oauth['provider'])
+
if @user.two_factor_enabled?
params[:remember_me] = '1' if remember_me?
prompt_for_two_factor(@user)
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index d838b8dc29e..35e67730a27 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -150,6 +150,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present?
params[:file_name] = params[:file].original_filename
end
+
File.join(@path, params[:file_name])
elsif params[:file_path].present?
params[:file_path]
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index cf8829ba95b..e06dda1baa4 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -27,6 +27,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
unless @key.valid? && @project.deploy_keys << @key
flash[:alert] = @key.errors.full_messages.join(', ').html_safe
end
+
redirect_to_repository_settings(@project)
end
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 85d35900c71..6f51e7b9b40 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -21,6 +21,7 @@ class Projects::HooksController < Projects::ApplicationController
@hooks = @project.hooks.select(&:persisted?)
flash[:alert] = @hook.errors.full_messages.join.html_safe
end
+
redirect_to project_settings_integrations_path(@project)
end
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index dc524b790a0..3d2926d5d75 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -48,6 +48,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
else
[]
end
+
@diff_notes_disabled = true
@environment = @merge_request.environments_for(current_user).last
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 6f229b08c0c..e6e2b219e6a 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -203,6 +203,7 @@ class ProjectsController < Projects::ApplicationController
else
flash[:alert] = _("Project export could not be deleted.")
end
+
redirect_to(edit_project_path(@project))
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index d79108c88fb..c73306a6b66 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -28,6 +28,7 @@ class SessionsController < Devise::SessionsController
resource.update_attributes(reset_password_token: nil,
reset_password_sent_at: nil)
end
+
# hide the signed-in notification
flash[:notice] = nil
log_audit_event(current_user, resource, with: authentication_method)
diff --git a/app/finders/group_descendants_finder.rb b/app/finders/group_descendants_finder.rb
index 1a5f6063437..58570a580f1 100644
--- a/app/finders/group_descendants_finder.rb
+++ b/app/finders/group_descendants_finder.rb
@@ -63,6 +63,7 @@ class GroupDescendantsFinder
groups_table = Group.arel_table
visible_to_user = groups_table[:visibility_level]
.in(Gitlab::VisibilityLevel.levels_for_user(current_user))
+
if current_user
authorized_groups = GroupsFinder.new(current_user,
all_available: false)
@@ -115,6 +116,7 @@ class GroupDescendantsFinder
else
direct_child_groups
end
+
groups.with_selects_for_list(archived: params[:archived]).order_by(sort)
end
@@ -140,6 +142,7 @@ class GroupDescendantsFinder
else
direct_child_projects
end
+
projects.with_route.order_by(sort)
end
diff --git a/app/finders/group_projects_finder.rb b/app/finders/group_projects_finder.rb
index 6e8733bb49c..f2d3b90b8e2 100644
--- a/app/finders/group_projects_finder.rb
+++ b/app/finders/group_projects_finder.rb
@@ -34,6 +34,7 @@ class GroupProjectsFinder < ProjectsFinder
else
collection_without_user
end
+
union(projects)
end
diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb
index f78d41a0448..2fe1927a189 100644
--- a/app/helpers/markup_helper.rb
+++ b/app/helpers/markup_helper.rb
@@ -203,6 +203,7 @@ module MarkupHelper
node.content = node.content.truncate(num_remaining)
truncated = true
end
+
content_length += node.content.length
end
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 8ada746b244..680ea96a556 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -12,6 +12,7 @@ module NavHelper
current_path?('projects/merge_requests/conflicts#show') ||
current_path?('issues#show') ||
current_path?('milestones#show')
+
if cookies[:collapsed_gutter] == 'true'
%w[page-gutter right-sidebar-collapsed]
else
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index b447d4952e7..00e7e4230b9 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -89,6 +89,7 @@ module SnippetsHelper
snippet_chunk = [lined_content[line_number]]
snippet_start_line = line_number
end
+
last_line = line_number
end
# Add final chunk to chunk array
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
index 40d69e30188..1db9ae3839c 100644
--- a/app/helpers/submodule_helper.rb
+++ b/app/helpers/submodule_helper.rb
@@ -58,6 +58,7 @@ module SubmoduleHelper
url_no_dotgit = url.chomp('.git')
return true if url_no_dotgit == [Gitlab.config.gitlab.url, '/', namespace, '/',
project].join('')
+
url_with_dotgit = url_no_dotgit + '.git'
url_with_dotgit == Gitlab::Shell.new.url_to_repo([namespace, '/', project].join(''))
end
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 2a7aa299e83..e7c953e749e 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -30,6 +30,7 @@ module TodosHelper
else
todo.target_reference
end
+
link_to text, todo_target_path(todo), class: 'has-tooltip', title: todo.target.title
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 8ab338d873d..80bda7f22ff 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -418,6 +418,7 @@ class ApplicationSetting < ActiveRecord::Base
super(group_full_path)
Gitlab::PerformanceBar.expire_allowed_user_ids_cache
end
+
return
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 4251561a0a0..7049f340c9d 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -314,6 +314,7 @@ module Issuable
includes = []
includes << :author unless notes.authors_loaded?
includes << :award_emoji unless notes.award_emojis_loaded?
+
if includes.any?
notes.includes(includes)
else
diff --git a/app/models/concerns/loaded_in_group_list.rb b/app/models/concerns/loaded_in_group_list.rb
index dcb3b2b5ff3..935e9d10133 100644
--- a/app/models/concerns/loaded_in_group_list.rb
+++ b/app/models/concerns/loaded_in_group_list.rb
@@ -25,6 +25,7 @@ module LoadedInGroupList
base_count = projects.project(Arel.star.count.as('preloaded_project_count'))
.where(projects[:namespace_id].eq(namespaces[:id]))
+
if archived == 'only'
base_count.where(projects[:archived].eq(true))
elsif Gitlab::Utils.to_boolean(archived)
diff --git a/app/models/label.rb b/app/models/label.rb
index b5bfa6ea2dd..7538f2d8718 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -132,6 +132,7 @@ class Label < ActiveRecord::Base
else
priorities.find_by(project: project)
end
+
priority.try(:priority)
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 8fdeddf1ed1..2669d2a6ff3 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -793,6 +793,7 @@ class MergeRequest < ActiveRecord::Base
if !include_description && closes_issues_references.present?
message << "Closes #{closes_issues_references.to_sentence}"
end
+
message << "#{description}" if include_description && description.present?
message << "See merge request #{to_reference(full: true)}"
diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb
index aec7b01e23a..c351d2012c6 100644
--- a/app/models/network/graph.rb
+++ b/app/models/network/graph.rb
@@ -224,6 +224,7 @@ module Network
space_base = parents.first.space
end
end
+
space_base
end
diff --git a/app/models/notification_recipient.rb b/app/models/notification_recipient.rb
index 183e098d819..ab5a96209c7 100644
--- a/app/models/notification_recipient.rb
+++ b/app/models/notification_recipient.rb
@@ -9,6 +9,7 @@ class NotificationRecipient
group: nil,
skip_read_ability: false
)
+
unless NotificationSetting.levels.key?(type) || type == :subscription
raise ArgumentError, "invalid type: #{type.inspect}"
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 7dc5e980c1b..029f2da2e4e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -633,6 +633,7 @@ class Project < ActiveRecord::Base
project_import_data.data ||= {}
project_import_data.data = project_import_data.data.merge(data)
end
+
if credentials
project_import_data.credentials ||= {}
project_import_data.credentials = project_import_data.credentials.merge(credentials)
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 768f0a7472e..bfe7ac29c18 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -110,6 +110,7 @@ class HipchatService < Service
message = ""
message << "#{push[:user_name]} "
+
if Gitlab::Git.blank_ref?(before)
message << "pushed new #{ref_type} #{ref}"\
diff --git a/app/models/repository.rb b/app/models/repository.rb
index a84d6a1426b..d27212b2058 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1014,6 +1014,7 @@ class Repository
else
cache.fetch(key, &block)
end
+
instance_variable_set(ivar, value)
rescue Rugged::ReferenceError, Gitlab::Git::Repository::NoRepository
# Even if the above `#exists?` check passes these errors might still
diff --git a/app/models/service.rb b/app/models/service.rb
index 24ba3039707..7f260f7a96b 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -250,6 +250,7 @@ class Service < ActiveRecord::Base
teamcity
microsoft_teams
]
+
if Rails.env.development?
service_names += %w[mock_ci mock_deployment mock_monitoring]
end
diff --git a/app/services/create_deployment_service.rb b/app/services/create_deployment_service.rb
index 63b85c3de7d..88dfb7a4a90 100644
--- a/app/services/create_deployment_service.rb
+++ b/app/services/create_deployment_service.rb
@@ -16,6 +16,7 @@ class CreateDeploymentService
ActiveRecord::Base.transaction do
environment.external_url = expanded_environment_url if
expanded_environment_url
+
environment.fire_state_event(action)
return unless environment.save
diff --git a/app/workers/pages_worker.rb b/app/workers/pages_worker.rb
index 3ec81d040b4..d3b95009364 100644
--- a/app/workers/pages_worker.rb
+++ b/app/workers/pages_worker.rb
@@ -13,6 +13,7 @@ class PagesWorker
if result[:status] == :success
result = Projects::UpdatePagesConfigurationService.new(build.project).execute
end
+
result
end
diff --git a/changelogs/unreleased/18040-line-breaks-around-conditional-blocks.yml b/changelogs/unreleased/18040-line-breaks-around-conditional-blocks.yml
new file mode 100644
index 00000000000..447c65a3764
--- /dev/null
+++ b/changelogs/unreleased/18040-line-breaks-around-conditional-blocks.yml
@@ -0,0 +1,5 @@
+---
+title: Adds Rubocop rule for line break around conditionals
+merge_request: 15739
+author: Jacopo Beschi @jacopo-beschi
+type: added
diff --git a/config/application.rb b/config/application.rb
index cd5e3d45bab..ea9a07cbde9 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -151,6 +151,7 @@ module Gitlab
caching_config_hash[:pool_size] = Sidekiq.options[:concurrency] + 5
caching_config_hash[:pool_timeout] = 1
end
+
config.cache_store = :redis_store, caching_config_hash
config.active_record.raise_in_transactional_callbacks = true
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index f10f0cdf42c..abc992e49dc 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -68,6 +68,7 @@ class Settings < Settingslogic
end
values.delete_if { |value| value.nil? }
end
+
values
end
@@ -78,6 +79,7 @@ class Settings < Settingslogic
if current.is_a? String
value = modul.const_get(current.upcase) rescue default
end
+
value
end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 051ef93b205..fa25f3778fa 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -241,6 +241,7 @@ Devise.setup do |config|
true
end
end
+
if provider['name'] == 'authentiq'
provider['args'][:remote_sign_out_handler] = lambda do |request|
authentiq_session = request.params['sid']
diff --git a/config/initializers/peek.rb b/config/initializers/peek.rb
index 581397b26f8..e74b95f1646 100644
--- a/config/initializers/peek.rb
+++ b/config/initializers/peek.rb
@@ -2,6 +2,7 @@ Rails.application.config.peek.adapter = :redis, { client: ::Redis.new(Gitlab::Re
Peek.into Peek::Views::Host
Peek.into Peek::Views::PerformanceBar
+
if Gitlab::Database.mysql?
require 'peek-mysql2'
PEEK_DB_CLIENT = ::Mysql2::Client
@@ -11,6 +12,7 @@ else
PEEK_DB_CLIENT = ::PG::Connection
PEEK_DB_VIEW = Peek::Views::PG
end
+
Peek.into PEEK_DB_VIEW
Peek.into Peek::Views::Redis
Peek.into Peek::Views::Sidekiq
diff --git a/db/migrate/20170928124105_create_fork_networks.rb b/db/migrate/20170928124105_create_fork_networks.rb
index ca906b953a3..89e5b871967 100644
--- a/db/migrate/20170928124105_create_fork_networks.rb
+++ b/db/migrate/20170928124105_create_fork_networks.rb
@@ -23,6 +23,7 @@ class CreateForkNetworks < ActiveRecord::Migration
if foreign_keys_for(:fork_networks, :root_project_id).any?
remove_foreign_key :fork_networks, column: :root_project_id
end
+
drop_table :fork_networks
end
end
diff --git a/db/migrate/20170928133643_create_fork_network_members.rb b/db/migrate/20170928133643_create_fork_network_members.rb
index 836f023efdc..8c7d9ba859a 100644
--- a/db/migrate/20170928133643_create_fork_network_members.rb
+++ b/db/migrate/20170928133643_create_fork_network_members.rb
@@ -21,6 +21,7 @@ class CreateForkNetworkMembers < ActiveRecord::Migration
if foreign_keys_for(:fork_network_members, :forked_from_project_id).any?
remove_foreign_key :fork_network_members, column: :forked_from_project_id
end
+
drop_table :fork_network_members
end
end
diff --git a/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb b/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb
index 7cf1d0cec68..d1a039ed551 100644
--- a/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb
+++ b/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb
@@ -9,6 +9,7 @@ class AddIndexOnNamespacesLowerName < ActiveRecord::Migration
return unless Gitlab::Database.postgresql?
disable_statement_timeout
+
if Gitlab::Database.version.to_f >= 9.5
# Allow us to hot-patch the index manually ahead of the migration
execute "CREATE INDEX CONCURRENTLY IF NOT EXISTS #{INDEX_NAME} ON namespaces (lower(name));"
@@ -21,6 +22,7 @@ class AddIndexOnNamespacesLowerName < ActiveRecord::Migration
return unless Gitlab::Database.postgresql?
disable_statement_timeout
+
if Gitlab::Database.version.to_f >= 9.2
execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME};"
else
diff --git a/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb b/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb
index da0fcda87a6..17ad7de065d 100644
--- a/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb
+++ b/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb
@@ -31,6 +31,7 @@ class RenameUsersWithRenamedNamespace < ActiveRecord::Migration
predicate = namespaces[:owner_id].eq(users[:id])
.and(namespaces[:type].eq(nil))
.and(users[:username].matches(path))
+
update_sql = if Gitlab::Database.postgresql?
"UPDATE users SET username = namespaces.path "\
"FROM namespaces WHERE #{predicate.to_sql}"
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index c623a516c47..bd3011b1cd8 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -180,11 +180,13 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
dropdown.find(".compare-dropdown-toggle").click
dropdown.find('.dropdown-menu', visible: true)
dropdown.fill_in("Filter by Git revision", with: selection)
+
if is_commit
dropdown.find('input[type="search"]').send_keys(:return)
else
find_link(selection, visible: true).click
end
+
dropdown.find('.dropdown-menu', visible: false)
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index d6ce368efd5..6134ad2bfc7 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -26,6 +26,7 @@ module API
check_unmodified_since!(last_updated)
status 204
+
if block_given?
yield resource
else
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 8bf53939751..063f0d6599c 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -103,6 +103,7 @@ module API
elsif params[:user_id]
user = User.find_by(id: params[:user_id])
end
+
present user, with: Entities::UserSafe
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 7aa10631d53..c99fe3ab5b3 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -175,6 +175,7 @@ module API
issue = ::Issues::CreateService.new(user_project,
current_user,
issue_params.merge(request: request, api: true)).execute
+
if issue.spam?
render_api_error!({ error: 'Spam detected' }, 400)
end
diff --git a/lib/api/pipelines.rb b/lib/api/pipelines.rb
index 74b3376a1f3..675c963bae2 100644
--- a/lib/api/pipelines.rb
+++ b/lib/api/pipelines.rb
@@ -48,6 +48,7 @@ module API
current_user,
declared_params(include_missing: false))
.execute(:api, ignore_skip_ci: true, save_on_errors: false)
+
if new_pipeline.persisted?
present new_pipeline, with: Entities::Pipeline
else
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 2ccda1c1aa1..5bed58c2d63 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -13,6 +13,7 @@ module API
if errors[:project_access].any?
error!(errors[:project_access], 422)
end
+
not_found!
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index fa222bf2b1c..653126e79ea 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -154,6 +154,7 @@ module API
if project.errors[:limit_reached].present?
error!(project.errors[:limit_reached], 403)
end
+
render_validation_error!(project)
end
end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 4f36bbd760f..9638c53a1df 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -15,6 +15,7 @@ module API
if errors[:project_access].any?
error!(errors[:project_access], 422)
end
+
not_found!
end
diff --git a/lib/api/v3/members.rb b/lib/api/v3/members.rb
index 684860b553e..de226e4e573 100644
--- a/lib/api/v3/members.rb
+++ b/lib/api/v3/members.rb
@@ -67,6 +67,7 @@ module API
unless member
member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at])
end
+
if member.persisted? && member.valid?
present member.user, with: ::API::Entities::Member, member: member
else
diff --git a/lib/api/v3/merge_requests.rb b/lib/api/v3/merge_requests.rb
index 1d6d823f32b..0a24fea52a3 100644
--- a/lib/api/v3/merge_requests.rb
+++ b/lib/api/v3/merge_requests.rb
@@ -126,6 +126,7 @@ module API
if status == :deprecated
detail DEPRECATION_MESSAGE
end
+
success ::API::V3::Entities::MergeRequest
end
get path do
diff --git a/lib/api/v3/project_snippets.rb b/lib/api/v3/project_snippets.rb
index c41fee32610..6ba425ba8c7 100644
--- a/lib/api/v3/project_snippets.rb
+++ b/lib/api/v3/project_snippets.rb
@@ -14,6 +14,7 @@ module API
if errors[:project_access].any?
error!(errors[:project_access], 422)
end
+
not_found!
end
diff --git a/lib/api/v3/projects.rb b/lib/api/v3/projects.rb
index 7c260b8d910..446f804124b 100644
--- a/lib/api/v3/projects.rb
+++ b/lib/api/v3/projects.rb
@@ -41,6 +41,7 @@ module API
# private or internal, use the more conservative option, private.
attrs[:visibility_level] = (publik == true) ? Gitlab::VisibilityLevel::PUBLIC : Gitlab::VisibilityLevel::PRIVATE
end
+
attrs
end
@@ -201,6 +202,7 @@ module API
if project.errors[:limit_reached].present?
error!(project.errors[:limit_reached], 403)
end
+
render_validation_error!(project)
end
end
diff --git a/lib/api/v3/repositories.rb b/lib/api/v3/repositories.rb
index f9a47101e27..5b54734bb45 100644
--- a/lib/api/v3/repositories.rb
+++ b/lib/api/v3/repositories.rb
@@ -14,6 +14,7 @@ module API
if errors[:project_access].any?
error!(errors[:project_access], 422)
end
+
not_found!
end
end
diff --git a/lib/api/v3/snippets.rb b/lib/api/v3/snippets.rb
index 126ec72248e..85613c8ed84 100644
--- a/lib/api/v3/snippets.rb
+++ b/lib/api/v3/snippets.rb
@@ -97,6 +97,7 @@ module API
attrs = declared_params(include_missing: false)
UpdateSnippetService.new(nil, current_user, snippet, attrs).execute
+
if snippet.persisted?
present snippet, with: ::API::Entities::PersonalSnippet
else
diff --git a/lib/backup/database.rb b/lib/backup/database.rb
index d97e5d98229..5e6828de597 100644
--- a/lib/backup/database.rb
+++ b/lib/backup/database.rb
@@ -31,6 +31,7 @@ module Backup
pgsql_args << "-n"
pgsql_args << Gitlab.config.backup.pg_schema
end
+
spawn('pg_dump', *pgsql_args, config['database'], out: compress_wr)
end
compress_wr.close
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index 2a04c03919d..6715159a1aa 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -47,6 +47,7 @@ module Backup
if File.exist?(path_to_wiki_repo)
progress.print " * #{display_repo_path(wiki)} ... "
+
if empty_repo?(wiki)
progress.puts " [SKIPPED]".color(:cyan)
else
diff --git a/lib/gitlab/ci/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb
index e25916528f4..35eadf6fa93 100644
--- a/lib/gitlab/ci/ansi2html.rb
+++ b/lib/gitlab/ci/ansi2html.rb
@@ -148,6 +148,7 @@ module Gitlab
stream.seek(@offset)
append = @offset > 0
end
+
start_offset = @offset
open_new_tag
@@ -155,6 +156,7 @@ module Gitlab
stream.each_line do |line|
s = StringScanner.new(line)
until s.eos?
+
if s.scan(Gitlab::Regex.build_trace_section_regex)
handle_section(s)
elsif s.scan(/\e([@-_])(.*?)([@-~])/)
@@ -168,6 +170,7 @@ module Gitlab
else
@out << s.scan(/./m)
end
+
@offset += s.matched_size
end
end
@@ -236,8 +239,10 @@ module Gitlab
if @style_mask & STYLE_SWITCHES[:bold] != 0
fg_color.sub!(/fg-([a-z]{2,}+)/, 'fg-l-\1')
end
+
css_classes << fg_color
end
+
css_classes << @bg_color unless @bg_color.nil?
STYLE_SWITCHES.each do |css_class, flag|
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 7b35c24d153..592a1956ceb 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -512,6 +512,7 @@ module Gitlab
batch_size: 10_000,
interval: 10.minutes
)
+
unless relation.model < EachBatch
raise TypeError, 'The relation must include the EachBatch module'
end
diff --git a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb
index d32616862f0..979225dd216 100644
--- a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb
+++ b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb
@@ -26,6 +26,7 @@ module Gitlab
move_repository(project, old_full_path, new_full_path)
move_repository(project, "#{old_full_path}.wiki", "#{new_full_path}.wiki")
end
+
move_uploads(old_full_path, new_full_path) unless project.hashed_storage?(:attachments)
move_pages(old_full_path, new_full_path)
end
diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb
index b669ee5b799..0f897e6316c 100644
--- a/lib/gitlab/diff/highlight.rb
+++ b/lib/gitlab/diff/highlight.rb
@@ -14,6 +14,7 @@ module Gitlab
else
@diff_lines = diff_lines
end
+
@raw_lines = @diff_lines.map(&:text)
end
diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb
index 37face8e7d0..d3b49b1ec75 100644
--- a/lib/gitlab/ee_compat_check.rb
+++ b/lib/gitlab/ee_compat_check.rb
@@ -156,12 +156,14 @@ module Gitlab
%W[git apply --3way #{patch_path}]
) do |output, status|
puts output
+
unless status.zero?
@failed_files = output.lines.reduce([]) do |memo, line|
if line.start_with?('error: patch failed:')
file = line.sub(/\Aerror: patch failed: /, '')
memo << file unless file =~ IGNORED_FILES_REGEX
end
+
memo
end
diff --git a/lib/gitlab/email/handler/create_merge_request_handler.rb b/lib/gitlab/email/handler/create_merge_request_handler.rb
index e2f7c1d0257..3436306e122 100644
--- a/lib/gitlab/email/handler/create_merge_request_handler.rb
+++ b/lib/gitlab/email/handler/create_merge_request_handler.rb
@@ -10,6 +10,7 @@ module Gitlab
def initialize(mail, mail_key)
super(mail, mail_key)
+
if m = /\A([^\+]*)\+merge-request\+(.*)/.match(mail_key.to_s)
@project_path, @incoming_email_token = m.captures
end
diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb
index 5e426b13ade..8953bc8c148 100644
--- a/lib/gitlab/fogbugz_import/importer.rb
+++ b/lib/gitlab/fogbugz_import/importer.rb
@@ -112,6 +112,7 @@ module Gitlab
[bug['sCategory'], bug['sPriority']].each do |label|
unless label.blank?
labels << label
+
unless @known_labels.include?(label)
create_label(label)
@known_labels << label
@@ -265,6 +266,7 @@ module Gitlab
if content.blank?
content = '*(No description has been entered for this issue)*'
end
+
body << content
body.join("\n\n")
@@ -278,6 +280,7 @@ module Gitlab
if content.blank?
content = "*(No comment has been entered for this change)*"
end
+
body << content
if updates.any?
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index f371adfa109..6ada9a145db 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -668,6 +668,7 @@ module Gitlab
end
end
end
+
@refs_hash
end
diff --git a/lib/gitlab/git/storage/forked_storage_check.rb b/lib/gitlab/git/storage/forked_storage_check.rb
index 1307f400700..0a4e557b59b 100644
--- a/lib/gitlab/git/storage/forked_storage_check.rb
+++ b/lib/gitlab/git/storage/forked_storage_check.rb
@@ -27,6 +27,7 @@ module Gitlab
status = nil
while status.nil?
+
if deadline > Time.now.utc
sleep(wait_time)
_pid, status = Process.wait2(filesystem_check_pid, Process::WNOHANG)
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index ae1753ff0ae..37ba1af8d6f 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -52,6 +52,7 @@ module Gitlab
)
response = GitalyClient.call(@repository.storage, :operation_service,
:user_create_branch, request)
+
if response.pre_receive_error.present?
raise Gitlab::Git::HooksService::PreReceiveError.new(response.pre_receive_error)
end
diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb
index ab38c0c3e34..46b49128140 100644
--- a/lib/gitlab/google_code_import/importer.rb
+++ b/lib/gitlab/google_code_import/importer.rb
@@ -302,6 +302,7 @@ module Gitlab
else
"#{project.namespace.full_path}/#{name}##{id}"
end
+
text = "~~#{text}~~" if deleted
text
end
@@ -329,6 +330,7 @@ module Gitlab
if content.blank?
content = "*(No comment has been entered for this change)*"
end
+
body << content
if updates.any?
@@ -352,6 +354,7 @@ module Gitlab
if content.blank?
content = "*(No description has been entered for this issue)*"
end
+
body << content
if attachments.any?
diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb
index c518943be59..4b5f9f3a926 100644
--- a/lib/gitlab/import_export/project_tree_restorer.rb
+++ b/lib/gitlab/import_export/project_tree_restorer.rb
@@ -148,6 +148,7 @@ module Gitlab
else
relation_hash = relation_item[sub_relation.to_s]
end
+
[relation_hash, sub_relation]
end
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index 05dbaf6322c..cb711a83433 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -267,6 +267,7 @@ module Gitlab
else
%w[title group_id]
end
+
finder_hash = parsed_relation_hash.slice(*finder_attributes)
if label?
diff --git a/lib/gitlab/kubernetes/helm/pod.rb b/lib/gitlab/kubernetes/helm/pod.rb
index 233f6bf6227..97ad3c97e95 100644
--- a/lib/gitlab/kubernetes/helm/pod.rb
+++ b/lib/gitlab/kubernetes/helm/pod.rb
@@ -14,6 +14,7 @@ module Gitlab
generate_config_map
spec['volumes'] = volumes_specification
end
+
::Kubeclient::Resource.new(metadata: metadata, spec: spec)
end
diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb
index 0d9a554fc18..cde60addcf7 100644
--- a/lib/gitlab/ldap/config.rb
+++ b/lib/gitlab/ldap/config.rb
@@ -42,6 +42,7 @@ module Gitlab
else
self.class.invalid_provider(provider)
end
+
@options = config_for(@provider) # Use @provider, not provider
end
diff --git a/lib/gitlab/metrics/influx_db.rb b/lib/gitlab/metrics/influx_db.rb
index 877cebf6786..ef44a13df51 100644
--- a/lib/gitlab/metrics/influx_db.rb
+++ b/lib/gitlab/metrics/influx_db.rb
@@ -169,6 +169,7 @@ module Gitlab
end
end
end
+
@pool
end
end
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb
index fee741b47be..cc1e92480be 100644
--- a/lib/gitlab/middleware/multipart.rb
+++ b/lib/gitlab/middleware/multipart.rb
@@ -47,6 +47,7 @@ module Gitlab
else
value = decorate_params_value(value, @request.params[key], tmp_path)
end
+
@request.update_param(key, value)
end
@@ -60,6 +61,7 @@ module Gitlab
unless path_hash.is_a?(Hash) && path_hash.count == 1
raise "invalid path: #{path_hash.inspect}"
end
+
path_key, path_value = path_hash.first
unless value_hash.is_a?(Hash) && value_hash[path_key]
diff --git a/lib/gitlab/multi_collection_paginator.rb b/lib/gitlab/multi_collection_paginator.rb
index c22d0a84860..43921a8c1c0 100644
--- a/lib/gitlab/multi_collection_paginator.rb
+++ b/lib/gitlab/multi_collection_paginator.rb
@@ -37,6 +37,7 @@ module Gitlab
else
per_page - first_collection_last_page_size
end
+
hash[page] = second_collection.page(second_collection_page)
.per(per_page - paginated_first_collection(page).size)
.padding(offset)
diff --git a/lib/gitlab/quick_actions/extractor.rb b/lib/gitlab/quick_actions/extractor.rb
index 3ebfa3bd4b8..c0878a34fb1 100644
--- a/lib/gitlab/quick_actions/extractor.rb
+++ b/lib/gitlab/quick_actions/extractor.rb
@@ -126,6 +126,7 @@ module Gitlab
command << match_data[1] unless match_data[1].empty?
commands << command
end
+
content = substitution.perform_substitution(self, content)
end
diff --git a/lib/gitlab/redis/wrapper.rb b/lib/gitlab/redis/wrapper.rb
index 8ad06480575..4178b436acf 100644
--- a/lib/gitlab/redis/wrapper.rb
+++ b/lib/gitlab/redis/wrapper.rb
@@ -24,6 +24,7 @@ module Gitlab
# the pool will be used in a multi-threaded context
size += Sidekiq.options[:concurrency]
end
+
size
end
@@ -104,6 +105,7 @@ module Gitlab
db_numbers = queries["db"] if queries.key?("db")
config[:db] = db_numbers[0].to_i if db_numbers.any?
end
+
config
else
redis_hash = ::Redis::Store::Factory.extract_host_options_from_uri(redis_url)
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index ca48c6df602..70b639501fd 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -115,6 +115,7 @@ module Gitlab
else
merge_requests.full_search(query)
end
+
merge_requests.order('updated_at DESC')
end
diff --git a/lib/gitlab/storage_check/cli.rb b/lib/gitlab/storage_check/cli.rb
index 04bf1bf1d26..9b64c8e033a 100644
--- a/lib/gitlab/storage_check/cli.rb
+++ b/lib/gitlab/storage_check/cli.rb
@@ -59,9 +59,11 @@ module Gitlab
if response.skipped_shards.any?
warnings << "Skipped shards: #{response.skipped_shards.join(', ')}"
end
+
if response.failing_shards.any?
warnings << "Failing shards: #{response.failing_shards.join(', ')}"
end
+
logger.warn(warnings.join(' - ')) if warnings.any?
end
end
diff --git a/lib/gitlab/testing/request_blocker_middleware.rb b/lib/gitlab/testing/request_blocker_middleware.rb
index 4a8e3c2eee0..53333b9b06b 100644
--- a/lib/gitlab/testing/request_blocker_middleware.rb
+++ b/lib/gitlab/testing/request_blocker_middleware.rb
@@ -37,12 +37,14 @@ module Gitlab
def call(env)
increment_active_requests
+
if block_requests?
block_request(env)
else
sleep 0.2 if slow_requests?
@app.call(env)
end
+
ensure
decrement_active_requests
end
diff --git a/lib/gitlab/timeless.rb b/lib/gitlab/timeless.rb
index b290c716f97..76a1808c8ac 100644
--- a/lib/gitlab/timeless.rb
+++ b/lib/gitlab/timeless.rb
@@ -9,6 +9,7 @@ module Gitlab
else
block.call
end
+
ensure
model.record_timestamps = original_record_timestamps
end
diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb
index 961df0468a4..3b64cb32afa 100644
--- a/lib/gitlab/upgrader.rb
+++ b/lib/gitlab/upgrader.rb
@@ -12,6 +12,7 @@ module Gitlab
puts "You are using the latest GitLab version"
else
puts "Newer GitLab version is available"
+
answer = if ARGV.first == "-y"
"yes"
else
@@ -77,6 +78,7 @@ module Gitlab
update_commands.each do |title, cmd|
puts title
puts " -> #{cmd.join(' ')}"
+
if system(env, *cmd)
puts " -> OK"
else
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index ce6d0422c1f..0de183858aa 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -42,6 +42,7 @@ module Gitlab
else
raise "Unsupported action: #{action}"
end
+
if feature_enabled
params[:GitalyServer] = server
end
diff --git a/lib/system_check/simple_executor.rb b/lib/system_check/simple_executor.rb
index 8b145fb4511..d268f501b4a 100644
--- a/lib/system_check/simple_executor.rb
+++ b/lib/system_check/simple_executor.rb
@@ -66,6 +66,7 @@ module SystemCheck
if check.can_repair?
$stdout.print 'Trying to fix error automatically. ...'
+
if check.repair!
$stdout.puts 'Success'.color(:green)
return
diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index 9dcf44fdc3e..2383bcf954b 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -46,6 +46,7 @@ namespace :gitlab do
puts 'Removing all tables. Press `Ctrl-C` within 5 seconds to abort'.color(:yellow)
sleep(5)
end
+
# Drop all tables Load the schema to ensure we don't have any newer tables
# hanging out from a failed upgrade
$progress.puts 'Cleaning the database ... '.color(:blue)
@@ -222,6 +223,7 @@ namespace :gitlab do
task restore: :environment do
$progress.puts "Restoring container registry images ... ".color(:blue)
+
if Gitlab.config.registry.enabled
Backup::Registry.new.restore
$progress.puts "done".color(:green)
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 903e84359cd..31cd6bfe6e1 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -180,6 +180,7 @@ namespace :gitlab do
puts "can't check, you have no projects".color(:magenta)
return
end
+
puts ""
Project.find_each(batch_size: 100) do |project|
@@ -210,6 +211,7 @@ namespace :gitlab do
gitlab_shell_repo_base = gitlab_shell_path
check_cmd = File.expand_path('bin/check', gitlab_shell_repo_base)
puts "Running #{check_cmd}"
+
if system(check_cmd, chdir: gitlab_shell_repo_base)
puts 'gitlab-shell self-check successful'.color(:green)
else
@@ -285,6 +287,7 @@ namespace :gitlab do
return if process_count.zero?
print 'Number of Sidekiq processes ... '
+
if process_count == 1
puts '1'.color(:green)
else
diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake
index eb0f757aea7..04d56509ac6 100644
--- a/lib/tasks/gitlab/cleanup.rake
+++ b/lib/tasks/gitlab/cleanup.rake
@@ -84,6 +84,7 @@ namespace :gitlab do
next unless user.ldap_user?
print "#{user.name} (#{user.ldap_identity.extern_uid}) ..."
+
if Gitlab::LDAP::Access.allowed?(user)
puts " [OK]".color(:green)
else
diff --git a/lib/tasks/gitlab/dev.rake b/lib/tasks/gitlab/dev.rake
index ba221e44e5d..77c28615856 100644
--- a/lib/tasks/gitlab/dev.rake
+++ b/lib/tasks/gitlab/dev.rake
@@ -14,6 +14,7 @@ namespace :gitlab do
puts "Must specify a branch as an argument".color(:red)
exit 1
end
+
args
end
diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake
index 4507b841964..a2e68c0471b 100644
--- a/lib/tasks/gitlab/gitaly.rake
+++ b/lib/tasks/gitlab/gitaly.rake
@@ -5,9 +5,11 @@ namespace :gitlab do
require 'toml'
warn_user_is_not_gitlab
+
unless args.dir.present?
abort %(Please specify the directory where you want to install gitaly:\n rake "gitlab:gitaly:install[/home/git/gitaly]")
end
+
args.with_defaults(repo: 'https://gitlab.com/gitlab-org/gitaly.git')
version = Gitlab::GitalyClient.expected_server_version
diff --git a/lib/tasks/gitlab/list_repos.rake b/lib/tasks/gitlab/list_repos.rake
index b732db9db6e..d7f28691098 100644
--- a/lib/tasks/gitlab/list_repos.rake
+++ b/lib/tasks/gitlab/list_repos.rake
@@ -8,6 +8,7 @@ namespace :gitlab do
namespace_ids = Namespace.where(['updated_at > ?', date]).pluck(:id).sort
scope = scope.where('id IN (?) OR namespace_id in (?)', project_ids, namespace_ids)
end
+
scope.find_each do |project|
base = File.join(project.repository_storage_path, project.disk_path)
puts base + '.git'
diff --git a/lib/tasks/gitlab/update_templates.rake b/lib/tasks/gitlab/update_templates.rake
index f44abc2b81b..a25f7ce59c7 100644
--- a/lib/tasks/gitlab/update_templates.rake
+++ b/lib/tasks/gitlab/update_templates.rake
@@ -10,6 +10,7 @@ namespace :gitlab do
puts "This rake task is not meant fo production instances".red
exit(1)
end
+
admin = User.find_by(admin: true)
unless admin
diff --git a/lib/tasks/gitlab/workhorse.rake b/lib/tasks/gitlab/workhorse.rake
index e7ac0b5859f..308ffb0e284 100644
--- a/lib/tasks/gitlab/workhorse.rake
+++ b/lib/tasks/gitlab/workhorse.rake
@@ -3,9 +3,11 @@ namespace :gitlab do
desc "GitLab | Install or upgrade gitlab-workhorse"
task :install, [:dir, :repo] => :environment do |t, args|
warn_user_is_not_gitlab
+
unless args.dir.present?
abort %(Please specify the directory where you want to install gitlab-workhorse:\n rake "gitlab:workhorse:install[/home/git/gitlab-workhorse]")
end
+
args.with_defaults(repo: 'https://gitlab.com/gitlab-org/gitlab-workhorse.git')
version = Gitlab::Workhorse.version
diff --git a/lib/tasks/migrate/migrate_iids.rake b/lib/tasks/migrate/migrate_iids.rake
index fc2cea8c016..aa2d01730d7 100644
--- a/lib/tasks/migrate/migrate_iids.rake
+++ b/lib/tasks/migrate/migrate_iids.rake
@@ -4,6 +4,7 @@ task migrate_iids: :environment do
Issue.where(iid: nil).find_each(batch_size: 100) do |issue|
begin
issue.set_iid
+
if issue.update_attribute(:iid, issue.iid)
print '.'
else
@@ -19,6 +20,7 @@ task migrate_iids: :environment do
MergeRequest.where(iid: nil).find_each(batch_size: 100) do |mr|
begin
mr.set_iid
+
if mr.update_attribute(:iid, mr.iid)
print '.'
else
@@ -34,6 +36,7 @@ task migrate_iids: :environment do
Milestone.where(iid: nil).find_each(batch_size: 100) do |m|
begin
m.set_iid
+
if m.update_attribute(:iid, m.iid)
print '.'
else
diff --git a/rubocop/cop/line_break_around_conditional_block.rb b/rubocop/cop/line_break_around_conditional_block.rb
new file mode 100644
index 00000000000..3e7021e724e
--- /dev/null
+++ b/rubocop/cop/line_break_around_conditional_block.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ # Ensures a line break around conditional blocks.
+ #
+ # @example
+ # # bad
+ # do_something
+ # if condition
+ # do_extra_stuff
+ # end
+ # do_something_more
+ #
+ # # good
+ # do_something
+ #
+ # if condition
+ # do_extra_stuff
+ # end
+ #
+ # do_something_more
+ #
+ # # bad
+ # do_something
+ # unless condition
+ # do_extra_stuff
+ # end
+ #
+ # do_something_more
+ #
+ # # good
+ # def a_method
+ # if condition
+ # do_something
+ # end
+ # end
+ #
+ # # good
+ # on_block do
+ # if condition
+ # do_something
+ # end
+ # end
+ class LineBreakAroundConditionalBlock < RuboCop::Cop::Cop
+ MSG = 'Add a line break around conditional blocks'
+
+ def on_if(node)
+ return if node.single_line?
+ return unless node.if? || node.unless?
+
+ add_offense(node, location: :expression, message: MSG) unless previous_line_valid?(node)
+ add_offense(node, location: :expression, message: MSG) unless last_line_valid?(node)
+ end
+
+ def autocorrect(node)
+ lambda do |corrector|
+ line = range_by_whole_lines(node.source_range)
+ unless previous_line_valid?(node)
+ corrector.insert_before(line, "\n")
+ end
+
+ unless last_line_valid?(node)
+ corrector.insert_after(line, "\n")
+ end
+ end
+ end
+
+ private
+
+ def previous_line_valid?(node)
+ previous_line(node).empty? ||
+ start_clause_line?(previous_line(node)) ||
+ block_start?(previous_line(node)) ||
+ begin_line?(previous_line(node)) ||
+ assignment_line?(previous_line(node))
+ end
+
+ def last_line_valid?(node)
+ last_line(node).empty? ||
+ end_line?(last_line(node)) ||
+ end_clause_line?(last_line(node))
+ end
+
+ def previous_line(node)
+ processed_source[node.loc.line - 2]
+ end
+
+ def last_line(node)
+ processed_source[node.loc.last_line]
+ end
+
+ def start_clause_line?(line)
+ line =~ /^\s*(def|=end|#|module|class|if|unless|else|elsif|ensure|when)/
+ end
+
+ def end_clause_line?(line)
+ line =~ /^\s*(rescue|else|elsif|when)/
+ end
+
+ def begin_line?(line)
+ # an assignment followed by a begin or ust a begin
+ line =~ /^\s*(@?(\w|\|+|=|\[|\]|\s)+begin|begin)/
+ end
+
+ def assignment_line?(line)
+ line =~ /^\s*.*=/
+ end
+
+ def block_start?(line)
+ line.match(/ (do|{)( \|.*?\|)?\s?$/)
+ end
+
+ def end_line?(line)
+ line =~ /^\s*(end|})/
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 2f63babc425..57af87f7fb9 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -1,5 +1,6 @@
require_relative 'cop/gitlab/module_with_instance_variables'
require_relative 'cop/include_sidekiq_worker'
+require_relative 'cop/line_break_around_conditional_block'
require_relative 'cop/migration/add_column'
require_relative 'cop/migration/add_concurrent_foreign_key'
require_relative 'cop/migration/add_concurrent_index'
diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb
index 39460834d06..60956511834 100644
--- a/spec/factories/protected_branches.rb
+++ b/spec/factories/protected_branches.rb
@@ -53,6 +53,7 @@ FactoryBot.define do
if evaluator.default_access_level && evaluator.default_push_level
protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER)
end
+
if evaluator.default_access_level && evaluator.default_merge_level
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER)
end
diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb
index 587ece22ec7..cf283119f36 100644
--- a/spec/features/issues/bulk_assignment_labels_spec.rb
+++ b/spec/features/issues/bulk_assignment_labels_spec.rb
@@ -377,6 +377,7 @@ feature 'Issues > Labels bulk assignment' do
items.map do |item|
click_link item
end
+
if unmark
items.map do |item|
# Make sure we are unmarking the item no matter the state it has currently
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index ffa17d296e8..f246bb79ab7 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -142,6 +142,7 @@ describe API::CommitStatuses do
expect(json_response['ref']).not_to be_empty
expect(json_response['target_url']).to be_nil
expect(json_response['description']).to be_nil
+
if status == 'failed'
expect(CommitStatus.find(json_response['id'])).to be_api_failure
end
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 679d391caa5..cb66d23b77c 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -1142,6 +1142,7 @@ describe API::Runner do
else
{ 'file' => file }
end
+
post api("/jobs/#{job.id}/artifacts"), params, headers
end
end
diff --git a/spec/rubocop/cop/line_break_around_conditional_block_spec.rb b/spec/rubocop/cop/line_break_around_conditional_block_spec.rb
new file mode 100644
index 00000000000..7ddf9141fcd
--- /dev/null
+++ b/spec/rubocop/cop/line_break_around_conditional_block_spec.rb
@@ -0,0 +1,411 @@
+require 'spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../rubocop/cop/line_break_around_conditional_block'
+
+describe RuboCop::Cop::LineBreakAroundConditionalBlock do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ shared_examples 'examples with conditional' do |conditional|
+ it "flags violation for #{conditional} without line break before" do
+ source = <<~RUBY
+ do_something
+ #{conditional} condition
+ do_something_more
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses.size).to eq(1)
+ offense = cop.offenses.first
+
+ expect(offense.line).to eq(2)
+ expect(cop.highlights).to eq(["#{conditional} condition\n do_something_more\nend"])
+ expect(offense.message).to eq('Add a line break around conditional blocks')
+ end
+
+ it "flags violation for #{conditional} without line break after" do
+ source = <<~RUBY
+ #{conditional} condition
+ do_something
+ end
+ do_something_more
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses.size).to eq(1)
+ offense = cop.offenses.first
+
+ expect(offense.line).to eq(1)
+ expect(cop.highlights).to eq(["#{conditional} condition\n do_something\nend"])
+ expect(offense.message).to eq('Add a line break around conditional blocks')
+ end
+
+ it "doesn't flag violation for #{conditional} with line break before and after" do
+ source = <<~RUBY
+ #{conditional} condition
+ do_something
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a method definition" do
+ source = <<~RUBY
+ def a_method
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a class definition" do
+ source = <<~RUBY
+ class Foo
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a module definition" do
+ source = <<~RUBY
+ module Foo
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a begin definition" do
+ source = <<~RUBY
+ begin
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an assign/begin definition" do
+ source = <<~RUBY
+ @project ||= begin
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a block definition" do
+ source = <<~RUBY
+ on_block(param_a) do |item|
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a block definition using brackets" do
+ source = <<~RUBY
+ on_block(param_a) { |item|
+ #{conditional} condition
+ do_something
+ end
+ }
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a comment" do
+ source = <<~RUBY
+ # a short comment
+ #{conditional} condition
+ do_something
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an assignment" do
+ source = <<~RUBY
+ foo =
+ #{conditional} condition
+ do_something
+ else
+ do_something_more
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a multiline comment" do
+ source = <<~RUBY
+ =begin
+ a multiline comment
+ =end
+ #{conditional} condition
+ do_something
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by another conditional" do
+ source = <<~RUBY
+ #{conditional} condition_a
+ #{conditional} condition_b
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an else" do
+ source = <<~RUBY
+ if condition_a
+ do_something
+ else
+ #{conditional} condition_b
+ do_something_extra
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an elsif" do
+ source = <<~RUBY
+ if condition_a
+ do_something
+ elsif condition_b
+ #{conditional} condition_c
+ do_something_extra
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an ensure" do
+ source = <<~RUBY
+ def a_method
+ ensure
+ #{conditional} condition_c
+ do_something_extra
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a when" do
+ source = <<~RUBY
+ case field
+ when value
+ #{conditional} condition_c
+ do_something_extra
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by an end" do
+ source = <<~RUBY
+ class Foo
+
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by an else" do
+ source = <<~RUBY
+ #{conditional} condition_a
+ #{conditional} condition_b
+ do_something
+ end
+ else
+ do_something_extra
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by a when" do
+ source = <<~RUBY
+ case
+ when condition_a
+ #{conditional} condition_b
+ do_something
+ end
+ when condition_c
+ do_something_extra
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by an elsif" do
+ source = <<~RUBY
+ if condition_a
+ #{conditional} condition_b
+ do_something
+ end
+ elsif condition_c
+ do_something_extra
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by a rescue" do
+ source = <<~RUBY
+ def a_method
+ #{conditional} condition
+ do_something
+ end
+ rescue
+ do_something_extra
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "autocorrects #{conditional} without line break before" do
+ source = <<~RUBY
+ do_something
+ #{conditional} condition
+ do_something_more
+ end
+ RUBY
+ autocorrected = autocorrect_source(source)
+
+ expected_source = <<~RUBY
+ do_something
+
+ #{conditional} condition
+ do_something_more
+ end
+ RUBY
+ expect(autocorrected).to eql(expected_source)
+ end
+
+ it "autocorrects #{conditional} without line break after" do
+ source = <<~RUBY
+ #{conditional} condition
+ do_something
+ end
+ do_something_more
+ RUBY
+ autocorrected = autocorrect_source(source)
+
+ expected_source = <<~RUBY
+ #{conditional} condition
+ do_something
+ end
+
+ do_something_more
+ RUBY
+ expect(autocorrected).to eql(expected_source)
+ end
+
+ it "autocorrects #{conditional} without line break before and after" do
+ source = <<~RUBY
+ do_something
+ #{conditional} condition
+ do_something_more
+ end
+ do_something_extra
+ RUBY
+ autocorrected = autocorrect_source(source)
+
+ expected_source = <<~RUBY
+ do_something
+
+ #{conditional} condition
+ do_something_more
+ end
+
+ do_something_extra
+ RUBY
+ expect(autocorrected).to eql(expected_source)
+ end
+ end
+
+ %w[if unless].each do |example|
+ it_behaves_like 'examples with conditional', example
+ end
+
+ it "doesn't flag violation for if with elsif" do
+ source = <<~RUBY
+ if condition
+ do_something
+ elsif another_condition
+ do_something_more
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 39f6388c25e..ef68742a463 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -150,6 +150,7 @@ describe Projects::TransferService do
before do
group.add_owner(user)
+
unless gitlab_shell.add_repository(repository_storage, "#{group.full_path}/#{project.path}")
raise 'failed to add repository'
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 4e640a82dfc..965fd39c967 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -727,6 +727,7 @@ describe SystemNoteService do
else
"#{Settings.gitlab.base_url}/#{project.namespace.path}/#{project.path}/merge_requests/#{merge_request.iid}"
end
+
link = double(object: { 'url' => url })
links << link
expect(link).to receive(:save!)
diff --git a/spec/support/features/discussion_comments_shared_example.rb b/spec/support/features/discussion_comments_shared_example.rb
index c24940393f9..fa94aa2ae3d 100644
--- a/spec/support/features/discussion_comments_shared_example.rb
+++ b/spec/support/features/discussion_comments_shared_example.rb
@@ -113,6 +113,7 @@ shared_examples 'discussion comments' do |resource_name|
else
expect(find(submit_selector).value).to eq 'Start discussion'
end
+
expect(page).not_to have_selector menu_selector
end
@@ -200,6 +201,7 @@ shared_examples 'discussion comments' do |resource_name|
else
expect(find(submit_selector).value).to eq 'Comment'
end
+
expect(page).not_to have_selector menu_selector
end
diff --git a/spec/support/filtered_search_helpers.rb b/spec/support/filtered_search_helpers.rb
index 05021ea9054..f3f96bd1f0a 100644
--- a/spec/support/filtered_search_helpers.rb
+++ b/spec/support/filtered_search_helpers.rb
@@ -61,9 +61,11 @@ module FilteredSearchHelpers
token_emoji = tokens[index][:emoji_name]
expect(el.find('.name')).to have_content(token_name)
+
if token_value
expect(el.find('.value')).to have_content(token_value)
end
+
# gl-emoji content is blank when the emoji unicode is not supported
if token_emoji
selector = %(gl-emoji[data-name="#{token_emoji}"])
diff --git a/spec/support/generate-seed-repo-rb b/spec/support/generate-seed-repo-rb
index 4ee33f9725b..876b3b8242d 100755
--- a/spec/support/generate-seed-repo-rb
+++ b/spec/support/generate-seed-repo-rb
@@ -24,6 +24,7 @@ def main
unless system(*%W[git clone --bare #{SOURCE} #{REPO_NAME}], chdir: dir)
abort "git clone failed"
end
+
repo = File.join(dir, REPO_NAME)
erb = ERB.new(DATA.read)
erb.run(binding)
diff --git a/spec/support/matchers/access_matchers_for_controller.rb b/spec/support/matchers/access_matchers_for_controller.rb
index cdb62a5deee..42a9ed9ff34 100644
--- a/spec/support/matchers/access_matchers_for_controller.rb
+++ b/spec/support/matchers/access_matchers_for_controller.rb
@@ -43,6 +43,7 @@ module AccessMatchersForController
user = create(:user)
membership.public_send(:"add_#{role}", user)
end
+
user
end
diff --git a/spec/support/select2_helper.rb b/spec/support/select2_helper.rb
index 55da961e173..90618ba5b19 100644
--- a/spec/support/select2_helper.rb
+++ b/spec/support/select2_helper.rb
@@ -17,6 +17,7 @@ module Select2Helper
selector = options.fetch(:from)
first(selector, visible: false)
+
if options[:multiple]
execute_script("$('#{selector}').select2('val', ['#{value}']).trigger('change');")
else
diff --git a/spec/support/stub_env.rb b/spec/support/stub_env.rb
index f621463e621..695152e2d4e 100644
--- a/spec/support/stub_env.rb
+++ b/spec/support/stub_env.rb
@@ -4,6 +4,7 @@ module StubENV
def stub_env(key_or_hash, value = nil)
init_stub unless env_stubbed?
+
if key_or_hash.is_a? Hash
key_or_hash.each { |k, v| add_stubbed_value(k, v) }
else
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 664698fcbaf..25ff6094408 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -325,6 +325,7 @@ module TestEnv
if component_needs_update?(install_dir, version)
# Cleanup the component entirely to ensure we start fresh
FileUtils.rm_rf(install_dir)
+
unless system('rake', task)
raise ComponentFailedToInstallError
end
diff --git a/spec/support/wait_for_requests.rb b/spec/support/wait_for_requests.rb
index f4130d68271..fda0e29f983 100644
--- a/spec/support/wait_for_requests.rb
+++ b/spec/support/wait_for_requests.rb
@@ -53,6 +53,7 @@ module WaitForRequests
wait_until = Time.now + max_wait_time.seconds
loop do
break if yield
+
if Time.now > wait_until
raise "Condition not met: #{condition_name}"
else
--
cgit v1.2.1
From 3b6fb6b8679abc7915be669bd937cb0178721c8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cindy=20Pallares=20=F0=9F=A6=89?=
Date: Fri, 29 Dec 2017 17:39:27 +0000
Subject: Recommend against the use of EFS
---
doc/administration/high_availability/nfs.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md
index e09ccaba08c..d8928a7fe4c 100644
--- a/doc/administration/high_availability/nfs.md
+++ b/doc/administration/high_availability/nfs.md
@@ -32,7 +32,9 @@ options:
## AWS Elastic File System
-GitLab does not recommend using AWS Elastic File System (EFS).
+GitLab strongly recommends against using AWS Elastic File System (EFS).
+Our support team will not be able to assist on performance issues related to
+file system access.
Customers and users have reported that AWS EFS does not perform well for GitLab's
use-case. There are several issues that can cause problems. For these reasons
--
cgit v1.2.1
From 7a01d667ce406d880225259bfc8595e7add836d9 Mon Sep 17 00:00:00 2001
From: Marcia Ramos
Date: Thu, 11 Jan 2018 17:12:02 +0000
Subject: Docs: move article "Laravel and Envoy w/ CI/CD"
---
doc/articles/index.md | 1 -
.../img/container_registry_checkbox.png | Bin 4730 -> 0 bytes
.../img/container_registry_page_empty_image.png | Bin 56091 -> 0 bytes
.../img/container_registry_page_with_image.jpg | Bin 93531 -> 0 bytes
.../img/deploy_keys_page.png | Bin 339666 -> 0 bytes
.../img/environment_page.png | Bin 185393 -> 0 bytes
.../img/environments_page.png | Bin 134742 -> 0 bytes
.../img/laravel_welcome_page.png | Bin 5785 -> 0 bytes
.../img/laravel_with_gitlab_and_envoy.png | Bin 177704 -> 0 bytes
.../img/pipeline_page.png | Bin 172664 -> 0 bytes
.../img/pipelines_page.png | Bin 119955 -> 0 bytes
.../img/pipelines_page_deploy_button.png | Bin 141393 -> 0 bytes
.../img/production_server_app_directory.png | Bin 11082 -> 0 bytes
.../img/production_server_current_directory.png | Bin 21993 -> 0 bytes
.../img/secret_variables_page.png | Bin 233764 -> 0 bytes
.../laravel_with_gitlab_and_envoy/index.md | 681 +-------------------
doc/ci/README.md | 2 +-
doc/ci/examples/README.md | 1 +
.../img/container_registry_checkbox.png | Bin 0 -> 4730 bytes
.../img/container_registry_page_empty_image.png | Bin 0 -> 56091 bytes
.../img/container_registry_page_with_image.jpg | Bin 0 -> 93531 bytes
.../img/deploy_keys_page.png | Bin 0 -> 339666 bytes
.../img/environment_page.png | Bin 0 -> 185393 bytes
.../img/environments_page.png | Bin 0 -> 134742 bytes
.../img/laravel_welcome_page.png | Bin 0 -> 5785 bytes
.../img/laravel_with_gitlab_and_envoy.png | Bin 0 -> 177704 bytes
.../img/pipeline_page.png | Bin 0 -> 172664 bytes
.../img/pipelines_page.png | Bin 0 -> 119955 bytes
.../img/pipelines_page_deploy_button.png | Bin 0 -> 141393 bytes
.../img/production_server_app_directory.png | Bin 0 -> 11082 bytes
.../img/production_server_current_directory.png | Bin 0 -> 21993 bytes
.../img/secret_variables_page.png | Bin 0 -> 233764 bytes
.../laravel_with_gitlab_and_envoy/index.md | 684 +++++++++++++++++++++
33 files changed, 687 insertions(+), 682 deletions(-)
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_page_with_image.jpg
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/environment_page.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/environments_page.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/laravel_welcome_page.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/laravel_with_gitlab_and_envoy.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/pipeline_page.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/pipelines_page.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/production_server_app_directory.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/production_server_current_directory.png
delete mode 100644 doc/articles/laravel_with_gitlab_and_envoy/img/secret_variables_page.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_with_image.jpg
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/laravel_welcome_page.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/laravel_with_gitlab_and_envoy.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/production_server_app_directory.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/production_server_current_directory.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.png
create mode 100644 doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
diff --git a/doc/articles/index.md b/doc/articles/index.md
index d8a7874b96d..41fe8005d1f 100644
--- a/doc/articles/index.md
+++ b/doc/articles/index.md
@@ -17,7 +17,6 @@ Build, test, and deploy the software you develop with [GitLab CI/CD](../ci/READM
| Article title | Category | Publishing date |
| :------------ | :------: | --------------: |
| [Autoscaling GitLab Runners on AWS](runner_autoscale_aws/index.md) | Admin guide | 2017-11-24 |
-| [How to test and deploy Laravel/PHP applications with GitLab CI/CD and Envoy](laravel_with_gitlab_and_envoy/index.md) | Tutorial | 2017-08-31 |
| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017-07-13 |
| [Dockerizing GitLab Review Apps](https://about.gitlab.com/2017/07/11/dockerizing-review-apps/) | Concepts | 2017-07-11 |
| [Continuous Integration: From Jenkins to GitLab Using Docker](https://about.gitlab.com/2017/07/27/docker-my-precious/) | Concepts | 2017-07-27 |
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png b/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png
deleted file mode 100644
index a56c07a0da7..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png b/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png
deleted file mode 100644
index b1406fed6b8..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_page_with_image.jpg b/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_page_with_image.jpg
deleted file mode 100644
index d1f0cbc08ab..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/container_registry_page_with_image.jpg and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png b/doc/articles/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png
deleted file mode 100644
index 9aae11b8679..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/environment_page.png b/doc/articles/laravel_with_gitlab_and_envoy/img/environment_page.png
deleted file mode 100644
index a06b6d417cd..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/environment_page.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/environments_page.png b/doc/articles/laravel_with_gitlab_and_envoy/img/environments_page.png
deleted file mode 100644
index d357ecda7d2..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/environments_page.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/laravel_welcome_page.png b/doc/articles/laravel_with_gitlab_and_envoy/img/laravel_welcome_page.png
deleted file mode 100644
index 3bb21fd12b4..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/laravel_welcome_page.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/laravel_with_gitlab_and_envoy.png b/doc/articles/laravel_with_gitlab_and_envoy/img/laravel_with_gitlab_and_envoy.png
deleted file mode 100644
index bc188f83fb1..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/laravel_with_gitlab_and_envoy.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/pipeline_page.png b/doc/articles/laravel_with_gitlab_and_envoy/img/pipeline_page.png
deleted file mode 100644
index baf8dec499c..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/pipeline_page.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/pipelines_page.png b/doc/articles/laravel_with_gitlab_and_envoy/img/pipelines_page.png
deleted file mode 100644
index d96c43bcf16..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/pipelines_page.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png b/doc/articles/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png
deleted file mode 100644
index 997db10189f..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/production_server_app_directory.png b/doc/articles/laravel_with_gitlab_and_envoy/img/production_server_app_directory.png
deleted file mode 100644
index 6dbc29fc25c..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/production_server_app_directory.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/production_server_current_directory.png b/doc/articles/laravel_with_gitlab_and_envoy/img/production_server_current_directory.png
deleted file mode 100644
index 8a6dcccfa38..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/production_server_current_directory.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/img/secret_variables_page.png b/doc/articles/laravel_with_gitlab_and_envoy/img/secret_variables_page.png
deleted file mode 100644
index 658c0b5bcac..00000000000
Binary files a/doc/articles/laravel_with_gitlab_and_envoy/img/secret_variables_page.png and /dev/null differ
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/index.md b/doc/articles/laravel_with_gitlab_and_envoy/index.md
index b20bd8c247a..b092cdb0f7a 100644
--- a/doc/articles/laravel_with_gitlab_and_envoy/index.md
+++ b/doc/articles/laravel_with_gitlab_and_envoy/index.md
@@ -1,680 +1 @@
-# Test and deploy Laravel applications with GitLab CI/CD and Envoy
-
-> **[Article Type](../../development/writing_documentation.md#types-of-technical-articles):** tutorial ||
-> **Level:** intermediary ||
-> **Author:** [Mehran Rasulian](https://gitlab.com/mehranrasulian) ||
-> **Publication date:** 2017-08-31
-
-## Introduction
-
-GitLab features our applications with Continuous Integration, and it is possible to easily deploy the new code changes to the production server whenever we want.
-
-In this tutorial, we'll show you how to initialize a [Laravel](http://laravel.com/) application and setup our [Envoy](https://laravel.com/docs/envoy) tasks, then we'll jump into see how to test and deploy it with [GitLab CI/CD](../../ci/README.md) via [Continuous Delivery](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/).
-
-We assume you have a basic experience with Laravel, Linux servers,
-and you know how to use GitLab.
-
-Laravel is a high quality web framework written in PHP.
-It has a great community with a [fantastic documentation](https://laravel.com/docs).
-Aside from the usual routing, controllers, requests, responses, views, and (blade) templates, out of the box Laravel provides plenty of additional services such as cache, events, localization, authentication and many others.
-
-We will use [Envoy](https://laravel.com/docs/master/envoy) as an SSH task runner based on PHP.
-It uses a clean, minimal [Blade syntax](https://laravel.com/docs/blade) to setup tasks that can run on remote servers, such as, cloning your project from the repository, installing the Composer dependencies, and running [Artisan commands](https://laravel.com/docs/artisan).
-
-## Initialize our Laravel app on GitLab
-
-We assume [you have installed a new laravel project](https://laravel.com/docs/installation#installation), so let's start with a unit test, and initialize Git for the project.
-
-### Unit Test
-
-Every new installation of Laravel (currently 5.4) comes with two type of tests, 'Feature' and 'Unit', placed in the tests directory.
-Here's a unit test from `test/Unit/ExampleTest.php`:
-
-```php
-assertTrue(true);
- }
-}
-```
-
-This test is as simple as asserting that the given value is true.
-
-Laravel uses `PHPUnit` for tests by default.
-If we run `vendor/bin/phpunit` we should see the green output:
-
-```bash
-vendor/bin/phpunit
-OK (1 test, 1 assertions)
-```
-
-This test will be used later for continuously testing our app with GitLab CI/CD.
-
-### Push to GitLab
-
-Since we have our app up and running locally, it's time to push the codebase to our remote repository.
-Let's create [a new project](../../gitlab-basics/create-project.md) in GitLab named `laravel-sample`.
-After that, follow the command line instructions displayed on the project's homepage to initiate the repository on our machine and push the first commit.
-
-
-```bash
-cd laravel-sample
-git init
-git remote add origin git@gitlab.example.com:/laravel-sample.git
-git add .
-git commit -m 'Initial Commit'
-git push -u origin master
-```
-
-## Configure the production server
-
-Before we begin setting up Envoy and GitLab CI/CD, let's quickly make sure the production server is ready for deployment.
-We have installed LEMP stack which stands for Linux, Nginx, MySQL and PHP on our Ubuntu 16.04.
-
-### Create a new user
-
-Let's now create a new user that will be used to deploy our website and give it
-the needed permissions using [Linux ACL](https://serversforhackers.com/video/linux-acls):
-
-```bash
-# Create user deployer
-sudo adduser deployer
-# Give the read-write-execute permissions to deployer user for directory /var/www
-sudo setfacl -R -m u:deployer:rwx /var/www
-```
-
-If you don't have ACL installed on your Ubuntu server, use this command to install it:
-
-```bash
-sudo apt install acl
-```
-
-### Add SSH key
-
-Let's suppose we want to deploy our app to the production server from a private repository on GitLab. First, we need to [generate a new SSH key pair **with no passphrase**](../../ssh/README.md) for the deployer user.
-
-After that, we need to copy the private key, which will be used to connect to our server as the deployer user with SSH, to be able to automate our deployment process:
-
-```bash
-# As the deployer user on server
-#
-# Copy the content of public key to authorized_keys
-cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
-# Copy the private key text block
-cat ~/.ssh/id_rsa
-```
-
-Now, let's add it to your GitLab project as a [secret variable](../../ci/variables/README.md#secret-variables).
-Secret variables are user-defined variables and are stored out of `.gitlab-ci.yml`, for security purposes.
-They can be added per project by navigating to the project's **Settings** > **CI/CD**.
-
-![secret variables page](img/secret_variables_page.png)
-
-To the field **KEY**, add the name `SSH_PRIVATE_KEY`, and to the **VALUE** field, paste the private key you've copied earlier.
-We'll use this variable in the `.gitlab-ci.yml` later, to easily connect to our remote server as the deployer user without entering its password.
-
-We also need to add the public key to **Project** > **Settings** > **Repository** as [Deploy Keys](../../ssh/README.md/#deploy-keys), which gives us the ability to access our repository from the server through [SSH protocol](../../gitlab-basics/command-line-commands.md/#start-working-on-your-project).
-
-
-```bash
-# As the deployer user on the server
-#
-# Copy the public key
-cat ~/.ssh/id_rsa.pub
-```
-
-![deploy keys page](img/deploy_keys_page.png)
-
-To the field **Title**, add any name you want, and paste the public key into the **Key** field.
-
-Now, let's clone our repository on the server just to make sure the `deployer` user has access to the repository.
-
-```bash
-# As the deployer user on server
-#
-git clone git@gitlab.example.com:/laravel-sample.git
-```
-
->**Note:**
-Answer **yes** if asked `Are you sure you want to continue connecting (yes/no)?`.
-It adds GitLab.com to the known hosts.
-
-### Configuring Nginx
-
-Now, let's make sure our web server configuration points to the `current/public` rather than `public`.
-
-Open the default Nginx server block configuration file by typing:
-
-```bash
-sudo nano /etc/nginx/sites-available/default
-```
-
-The configuration should be like this.
-
-```
-server {
- root /var/www/app/current/public;
- server_name example.com;
- # Rest of the configuration
-}
-```
-
->**Note:**
-You may replace the app's name in `/var/www/app/current/public` with the folder name of your application.
-
-## Setting up Envoy
-
-So we have our Laravel app ready for production.
-The next thing is to use Envoy to perform the deploy.
-
-To use Envoy, we should first install it on our local machine [using the given instructions by Laravel](https://laravel.com/docs/envoy/#introduction).
-
-### How Envoy works
-
-The pros of Envoy is that it doesn't require Blade engine, it just uses Blade syntax to define tasks.
-To start, we create an `Envoy.blade.php` in the root of our app with a simple task to test Envoy.
-
-
-```php
-@servers(['web' => 'remote_username@remote_host'])
-
-@task('list', [on => 'web'])
- ls -l
-@endtask
-```
-
-As you may expect, we have an array within `@servers` directive at the top of the file, which contains a key named `web` with a value of the server's address (e.g. `deployer@192.168.1.1`).
-Then within our `@task` directive we define the bash commands that should be run on the server when the task is executed.
-
-On the local machine use the `run` command to run Envoy tasks.
-
-```bash
-envoy run list
-```
-
-It should execute the `list` task we defined earlier, which connects to the server and lists directory contents.
-
-Envoy is not a dependency of Laravel, therefore you can use it for any PHP application.
-
-### Zero downtime deployment
-
-Every time we deploy to the production server, Envoy downloads the latest release of our app from GitLab repository and replace it with preview's release.
-Envoy does this without any [downtime](https://en.wikipedia.org/wiki/Downtime),
-so we don't have to worry during the deployment while someone might be reviewing the site.
-Our deployment plan is to clone the latest release from GitLab repository, install the Composer dependencies and finally, activate the new release.
-
-#### @setup directive
-
-The first step of our deployment process is to define a set of variables within [@setup](https://laravel.com/docs/envoy/#setup) directive.
-You may change the `app` to your application's name:
-
-
-```php
-...
-
-@setup
- $repository = 'git@gitlab.example.com:/laravel-sample.git';
- $releases_dir = '/var/www/app/releases';
- $app_dir = '/var/www/app';
- $release = date('YmdHis');
- $new_release_dir = $releases_dir .'/'. $release;
-@endsetup
-
-...
-```
-
-- `$repository` is the address of our repository
-- `$releases_dir` directory is where we deploy the app
-- `$app_dir` is the actual location of the app that is live on the server
-- `$release` contains a date, so every time that we deploy a new release of our app, we get a new folder with the current date as name
-- `$new_release_dir` is the full path of the new release which is used just to make the tasks cleaner
-
-#### @story directive
-
-The [@story](https://laravel.com/docs/envoy/#stories) directive allows us define a list of tasks that can be run as a single task.
-Here we have three tasks called `clone_repository`, `run_composer`, `update_symlinks`. These variables are usable to making our task's codes more cleaner:
-
-
-```php
-...
-
-@story('deploy')
- clone_repository
- run_composer
- update_symlinks
-@endstory
-
-...
-```
-
-Let's create these three tasks one by one.
-
-#### Clone the repository
-
-The first task will create the `releases` directory (if it doesn't exist), and then clone the `master` branch of the repository (by default) into the new release directory, given by the `$new_release_dir` variable.
-The `releases` directory will hold all our deployments:
-
-```php
-...
-
-@task('clone_repository')
- echo 'Cloning repository'
- [ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
- git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
-@endtask
-
-...
-```
-
-While our project grows, its Git history will be very very long over time.
-Since we are creating a directory per release, it might not be necessary to have the history of the project downloaded for each release.
-The `--depth 1` option is a great solution which saves systems time and disk space as well.
-
-#### Installing dependencies with Composer
-
-As you may know, this task just navigates to the new release directory and runs Composer to install the application dependencies:
-
-```php
-...
-
-@task('run_composer')
- echo "Starting deployment ({{ $release }})"
- cd {{ $new_release_dir }}
- composer install --prefer-dist --no-scripts -q -o
-@endtask
-
-...
-```
-
-#### Activate new release
-
-Next thing to do after preparing the requirements of our new release, is to remove the storage directory from it and to create two symbolic links to point the application's `storage` directory and `.env` file to the new release.
-Then, we need to create another symbolic link to the new release with the name of `current` placed in the app directory.
-The `current` symbolic link always points to the latest release of our app:
-
-```php
-...
-
-@task('update_symlinks')
- echo "Linking storage directory"
- rm -rf {{ $new_release_dir }}/storage
- ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storage
-
- echo 'Linking .env file'
- ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env
-
- echo 'Linking current release'
- ln -nfs {{ $new_release_dir }} {{ $app_dir }}/current
-@endtask
-```
-
-As you see, we use `-nfs` as an option for `ln` command, which says that the `storage`, `.env` and `current` no longer points to the preview's release and will point them to the new release by force (`f` from `-nfs` means force), which is the case when we are doing multiple deployments.
-
-### Full script
-
-The script is ready, but make sure to change the `deployer@192.168.1.1` to your server and also change `/var/www/app` with the directory you want to deploy your app.
-
-At the end, our `Envoy.blade.php` file will look like this:
-
-```php
-@servers(['web' => 'deployer@192.168.1.1'])
-
-@setup
- $repository = 'git@gitlab.example.com:/laravel-sample.git';
- $releases_dir = '/var/www/app/releases';
- $app_dir = '/var/www/app';
- $release = date('YmdHis');
- $new_release_dir = $releases_dir .'/'. $release;
-@endsetup
-
-@story('deploy')
- clone_repository
- run_composer
- update_symlinks
-@endstory
-
-@task('clone_repository')
- echo 'Cloning repository'
- [ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
- git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
-@endtask
-
-@task('run_composer')
- echo "Starting deployment ({{ $release }})"
- cd {{ $new_release_dir }}
- composer install --prefer-dist --no-scripts -q -o
-@endtask
-
-@task('update_symlinks')
- echo "Linking storage directory"
- rm -rf {{ $new_release_dir }}/storage
- ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storage
-
- echo 'Linking .env file'
- ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env
-
- echo 'Linking current release'
- ln -nfs {{ $new_release_dir }} {{ $app_dir }}/current
-@endtask
-```
-
-One more thing we should do before any deployment is to manually copy our application `storage` folder to the `/var/www/app` directory on the server for the first time.
-You might want to create another Envoy task to do that for you.
-We also create the `.env` file in the same path to setup our production environment variables for Laravel.
-These are persistent data and will be shared to every new release.
-
-Now, we would need to deploy our app by running `envoy run deploy`, but it won't be necessary since GitLab can handle that for us with CI's [environments](../../ci/environments.md), which will be described [later](#setting-up-gitlab-ci-cd) in this tutorial.
-
-Now it's time to commit [Envoy.blade.php](https://gitlab.com/mehranrasulian/laravel-sample/blob/master/Envoy.blade.php) and push it to the `master` branch.
-To keep things simple, we commit directly to `master`, without using [feature-branches](../../workflow/gitlab_flow.md/#github-flow-as-a-simpler-alternative) since collaboration is beyond the scope of this tutorial.
-In a real world project, teams may use [Issue Tracker](../../user/project/issues/index.md) and [Merge Requests](../../user/project/merge_requests/index.md) to move their code across branches:
-
-```bash
-git add Envoy.blade.php
-git commit -m 'Add Envoy'
-git push origin master
-```
-
-## Continuous Integration with GitLab
-
-We have our app ready on GitLab, and we also can deploy it manually.
-But let's take a step forward to do it automatically with [Continuous Delivery](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#continuous-delivery) method.
-We need to check every commit with a set of automated tests to become aware of issues at the earliest, and then, we can deploy to the target environment if we are happy with the result of the tests.
-
-[GitLab CI/CD](../../ci/README.md) allows us to use [Docker](https://docker.com/) engine to handle the process of testing and deploying our app.
-In the case you're not familiar with Docker, refer to [How to Automate Docker Deployments](http://paislee.io/how-to-automate-docker-deployments/).
-
-To be able to build, test, and deploy our app with GitLab CI/CD, we need to prepare our work environment.
-To do that, we'll use a Docker image which has the minimum requirements that a Laravel app needs to run.
-[There are other ways](../../ci/examples/php.md/#test-php-projects-using-the-docker-executor) to do that as well, but they may lead our builds run slowly, which is not what we want when there are faster options to use.
-
-With Docker images our builds run incredibly faster!
-
-### Create a Container Image
-
-Let's create a [Dockerfile](https://gitlab.com/mehranrasulian/laravel-sample/blob/master/Dockerfile) in the root directory of our app with the following content:
-
-```bash
-# Set the base image for subsequent instructions
-FROM php:7.1
-
-# Update packages
-RUN apt-get update
-
-# Install PHP and composer dependencies
-RUN apt-get install -qq git curl libmcrypt-dev libjpeg-dev libpng-dev libfreetype6-dev libbz2-dev
-
-# Clear out the local repository of retrieved package files
-RUN apt-get clean
-
-# Install needed extensions
-# Here you can install any other extension that you need during the test and deployment process
-RUN docker-php-ext-install mcrypt pdo_mysql zip
-
-# Install Composer
-RUN curl --silent --show-error https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
-
-# Install Laravel Envoy
-RUN composer global require "laravel/envoy=~1.0"
-```
-
-We added the [official PHP 7.1 Docker image](https://hub.docker.com/r/_/php/), which consist of a minimum installation of Debian Jessie with PHP pre-installed, and works perfectly for our use case.
-
-We used `docker-php-ext-install` (provided by the official PHP Docker image) to install the PHP extensions we need.
-
-#### Setting Up GitLab Container Registry
-
-Now that we have our `Dockerfile` let's build and push it to our [GitLab Container Registry](../../user/project/container_registry.md).
-
-> The registry is the place to store and tag images for later use. Developers may want to maintain their own registry for private, company images, or for throw-away images used only in testing. Using GitLab Container Registry means you don't need to set up and administer yet another service or use a public registry.
-
-On your GitLab project repository navigate to the **Registry** tab.
-
-![container registry page empty image](img/container_registry_page_empty_image.png)
-
-You may need to [enable Container Registry](../../user/project/container_registry.md#enable-the-container-registry-for-your-project) to your project to see this tab. You'll find it under your project's **Settings > General > Sharing and permissions**.
-
-![container registry checkbox](img/container_registry_checkbox.png)
-
-To start using Container Registry on our machine, we first need to login to the GitLab registry using our GitLab username and password:
-
-```bash
-docker login registry.gitlab.com
-```
-Then we can build and push our image to GitLab:
-
-```bash
-docker build -t registry.gitlab.com//laravel-sample .
-
-docker push registry.gitlab.com//laravel-sample
-```
-
->**Note:**
-To run the above commands, we first need to have [Docker](https://docs.docker.com/engine/installation/) installed on our machine.
-
-Congratulations! You just pushed the first Docker image to the GitLab Registry, and if you refresh the page you should be able to see it:
-
-![container registry page with image](img/container_registry_page_with_image.jpg)
-
->**Note:**
-You can also [use GitLab CI/CD](https://about.gitlab.com/2016/05/23/gitlab-container-registry/#use-with-gitlab-ci) to build and push your Docker images, rather than doing that on your machine.
-
-We'll use this image further down in the `.gitlab-ci.yml` configuration file to handle the process of testing and deploying our app.
-
-Let's commit the `Dockerfile` file.
-
-```bash
-git add Dockerfile
-git commit -m 'Add Dockerfile'
-git push origin master
-```
-
-### Setting up GitLab CI/CD
-
-In order to build and test our app with GitLab CI/CD, we need a file called `.gitlab-ci.yml` in our repository's root. It is similar to Circle CI and Travis CI, but built-in GitLab.
-
-Our `.gitlab-ci.yml` file will look like this:
-
-```yaml
-image: registry.gitlab.com//laravel-sample:latest
-
-services:
- - mysql:5.7
-
-variables:
- MYSQL_DATABASE: homestead
- MYSQL_ROOT_PASSWORD: secret
- DB_HOST: mysql
- DB_USERNAME: root
-
-stages:
- - test
- - deploy
-
-unit_test:
- stage: test
- script:
- - cp .env.example .env
- - composer install
- - php artisan key:generate
- - php artisan migrate
- - vendor/bin/phpunit
-
-deploy_production:
- stage: deploy
- script:
- - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- - eval $(ssh-agent -s)
- - ssh-add <(echo "$SSH_PRIVATE_KEY")
- - mkdir -p ~/.ssh
- - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
-
- - ~/.composer/vendor/bin/envoy run deploy
- environment:
- name: production
- url: http://192.168.1.1
- when: manual
- only:
- - master
-```
-
-That's a lot to take in, isn't it? Let's run through it step by step.
-
-#### Image and Services
-
-[GitLab Runners](../../ci/runners/README.md) run the script defined by `.gitlab-ci.yml`.
-The `image` keyword tells the Runners which image to use.
-The `services` keyword defines additional images [that are linked to the main image](../../ci/docker/using_docker_images.md/#what-is-a-service).
-Here we use the container image we created before as our main image and also use MySQL 5.7 as a service.
-
-```yaml
-image: registry.gitlab.com//laravel-sample:latest
-
-services:
- - mysql:5.7
-
-...
-```
-
->**Note:**
-If you wish to test your app with different PHP versions and [database management systems](../../ci/services/README.md), you can define different `image` and `services` keywords for each test job.
-
-#### Variables
-
-GitLab CI/CD allows us to use [environment variables](../../ci/yaml/README.md#variables) in our jobs.
-We defined MySQL as our database management system, which comes with a superuser root created by default.
-
-So we should adjust the configuration of MySQL instance by defining `MYSQL_DATABASE` variable as our database name and `MYSQL_ROOT_PASSWORD` variable as the password of `root`.
-Find out more about MySQL variables at the [official MySQL Docker Image](https://hub.docker.com/r/_/mysql/).
-
-Also set the variables `DB_HOST` to `mysql` and `DB_USERNAME` to `root`, which are Laravel specific variables.
-We define `DB_HOST` as `mysql` instead of `127.0.0.1`, as we use MySQL Docker image as a service which [is linked to the main Docker image](../../ci/docker/using_docker_images.md/#how-services-are-linked-to-the-build).
-
-```yaml
-...
-
-variables:
- MYSQL_DATABASE: homestead
- MYSQL_ROOT_PASSWORD: secret
- DB_HOST: mysql
- DB_USERNAME: root
-
-...
-```
-
-#### Unit Test as the first job
-
-We defined the required shell scripts as an array of the [script](../../ci/yaml/README.md#script) variable to be executed when running `unit_test` job.
-
-These scripts are some Artisan commands to prepare the Laravel, and, at the end of the script, we'll run the tests by `PHPUnit`.
-
-```yaml
-...
-
-unit_test:
- script:
- # Install app dependencies
- - composer install
- # Setup .env
- - cp .env.example .env
- # Generate an environment key
- - php artisan key:generate
- # Run migrations
- - php artisan migrate
- # Run tests
- - vendor/bin/phpunit
-
-...
-```
-
-#### Deploy to production
-
-The job `deploy_production` will deploy the app to the production server.
-To deploy our app with Envoy, we had to set up the `$SSH_PRIVATE_KEY` variable as an [SSH private key](../../ci/ssh_keys/README.md/#ssh-keys-when-using-the-docker-executor).
-If the SSH keys have added successfully, we can run Envoy.
-
-As mentioned before, GitLab supports [Continuous Delivery](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#continuous-delivery) methods as well.
-The [environment](../../ci/yaml/README.md#environment) keyword tells GitLab that this job deploys to the `production` environment.
-The `url` keyword is used to generate a link to our application on the GitLab Environments page.
-The `only` keyword tells GitLab CI that the job should be executed only when the pipeline is building the `master` branch.
-Lastly, `when: manual` is used to turn the job from running automatically to a manual action.
-
-```yaml
-...
-
-deploy_production:
- script:
- # Add the private SSH key to the build environment
- - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- - eval $(ssh-agent -s)
- - ssh-add <(echo "$SSH_PRIVATE_KEY")
- - mkdir -p ~/.ssh
- - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
-
- # Run Envoy
- - ~/.composer/vendor/bin/envoy run deploy
-
- environment:
- name: production
- url: http://192.168.1.1
- when: manual
- only:
- - master
-```
-
-You may also want to add another job for [staging environment](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments), to final test your application before deploying to production.
-
-### Turn on GitLab CI/CD
-
-We have prepared everything we need to test and deploy our app with GitLab CI/CD.
-To do that, commit and push `.gitlab-ci.yml` to the `master` branch. It will trigger a pipeline, which you can watch live under your project's **Pipelines**.
-
-![pipelines page](img/pipelines_page.png)
-
-Here we see our **Test** and **Deploy** stages.
-The **Test** stage has the `unit_test` build running.
-click on it to see the Runner's output.
-
-![pipeline page](img/pipeline_page.png)
-
-After our code passed through the pipeline successfully, we can deploy to our production server by clicking the **play** button on the right side.
-
-![pipelines page deploy button](img/pipelines_page_deploy_button.png)
-
-Once the deploy pipeline passed successfully, navigate to **Pipelines > Environments**.
-
-![environments page](img/environments_page.png)
-
-If something doesn't work as expected, you can roll back to the latest working version of your app.
-
-![environment page](img/environment_page.png)
-
-By clicking on the external link icon specified on the right side, GitLab opens the production website.
-Our deployment successfully was done and we can see the application is live.
-
-![laravel welcome page](img/laravel_welcome_page.png)
-
-In the case that you're interested to know how is the application directory structure on the production server after deployment, here are three directories named `current`, `releases` and `storage`.
-As you know, the `current` directory is a symbolic link that points to the latest release.
-The `.env` file consists of our Laravel environment variables.
-
-![production server app directory](img/production_server_app_directory.png)
-
-If you navigate to the `current` directory, you should see the application's content.
-As you see, the `.env` is pointing to the `/var/www/app/.env` file and also `storage` is pointing to the `/var/www/app/storage/` directory.
-
-![production server current directory](img/production_server_current_directory.png)
-
-## Conclusion
-
-We configured GitLab CI to perform automated tests and used the method of [Continuous Delivery](https://continuousdelivery.com/) to deploy to production a Laravel application with Envoy, directly from the codebase.
-
-Envoy also was a great match to help us deploy the application without writing our custom bash script and doing Linux magics.
+This document was moved to [another location](../../ci/examples/laravel_with_gitlab_and_envoy/index.md).
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 05d792dea0f..5829aaee9c9 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -120,7 +120,7 @@ Here is an collection of tutorials and guides on setting up your CI pipeline.
- [Run PHP Composer & NPM scripts then deploy them to a staging server](examples/deployment/composer-npm-deploy.md)
- [Analyze code quality with the Code Climate CLI](examples/code_climate.md)
- **Articles**
- - [How to test and deploy Laravel/PHP applications with GitLab CI/CD and Envoy](../articles/laravel_with_gitlab_and_envoy/index.md)
+ - [How to test and deploy Laravel/PHP applications with GitLab CI/CD and Envoy](examples/laravel_with_gitlab_and_envoy/index.md)
- [How to deploy Maven projects to Artifactory with GitLab CI/CD](examples/artifactory_and_gitlab/index.md)
- [Automated Debian packaging](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/)
- [Spring boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/)
diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md
index 25a0c5dcff5..d4590d0f495 100644
--- a/doc/ci/examples/README.md
+++ b/doc/ci/examples/README.md
@@ -16,6 +16,7 @@ Apart from those, here is an collection of tutorials and guides on setting up yo
- [Testing a PHP application](php.md)
- [Run PHP Composer & NPM scripts then deploy them to a staging server](deployment/composer-npm-deploy.md)
+- [How to test and deploy Laravel/PHP applications with GitLab CI/CD and Envoy](laravel_with_gitlab_and_envoy/index.md)
### Ruby
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png
new file mode 100644
index 00000000000..a56c07a0da7
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_checkbox.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png
new file mode 100644
index 00000000000..b1406fed6b8
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_empty_image.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_with_image.jpg b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_with_image.jpg
new file mode 100644
index 00000000000..d1f0cbc08ab
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/container_registry_page_with_image.jpg differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png
new file mode 100644
index 00000000000..9aae11b8679
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/deploy_keys_page.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.png
new file mode 100644
index 00000000000..a06b6d417cd
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environment_page.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.png
new file mode 100644
index 00000000000..d357ecda7d2
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/environments_page.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/laravel_welcome_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/laravel_welcome_page.png
new file mode 100644
index 00000000000..3bb21fd12b4
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/laravel_welcome_page.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/laravel_with_gitlab_and_envoy.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/laravel_with_gitlab_and_envoy.png
new file mode 100644
index 00000000000..bc188f83fb1
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/laravel_with_gitlab_and_envoy.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.png
new file mode 100644
index 00000000000..baf8dec499c
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipeline_page.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.png
new file mode 100644
index 00000000000..d96c43bcf16
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png
new file mode 100644
index 00000000000..997db10189f
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/pipelines_page_deploy_button.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/production_server_app_directory.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/production_server_app_directory.png
new file mode 100644
index 00000000000..6dbc29fc25c
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/production_server_app_directory.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/production_server_current_directory.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/production_server_current_directory.png
new file mode 100644
index 00000000000..8a6dcccfa38
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/production_server_current_directory.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.png b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.png
new file mode 100644
index 00000000000..658c0b5bcac
Binary files /dev/null and b/doc/ci/examples/laravel_with_gitlab_and_envoy/img/secret_variables_page.png differ
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
new file mode 100644
index 00000000000..e1aff6fdf36
--- /dev/null
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
@@ -0,0 +1,684 @@
+---
+redirect_from: 'https://docs.gitlab.com/ee/articles/laravel_with_gitlab_and_envoy/index.html'
+---
+
+# Test and deploy Laravel applications with GitLab CI/CD and Envoy
+
+> **[Article Type](../../../development/writing_documentation.md#types-of-technical-articles):** tutorial ||
+> **Level:** intermediary ||
+> **Author:** [Mehran Rasulian](https://gitlab.com/mehranrasulian) ||
+> **Publication date:** 2017-08-31
+
+## Introduction
+
+GitLab features our applications with Continuous Integration, and it is possible to easily deploy the new code changes to the production server whenever we want.
+
+In this tutorial, we'll show you how to initialize a [Laravel](http://laravel.com/) application and setup our [Envoy](https://laravel.com/docs/envoy) tasks, then we'll jump into see how to test and deploy it with [GitLab CI/CD](../README.md) via [Continuous Delivery](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/).
+
+We assume you have a basic experience with Laravel, Linux servers,
+and you know how to use GitLab.
+
+Laravel is a high quality web framework written in PHP.
+It has a great community with a [fantastic documentation](https://laravel.com/docs).
+Aside from the usual routing, controllers, requests, responses, views, and (blade) templates, out of the box Laravel provides plenty of additional services such as cache, events, localization, authentication and many others.
+
+We will use [Envoy](https://laravel.com/docs/master/envoy) as an SSH task runner based on PHP.
+It uses a clean, minimal [Blade syntax](https://laravel.com/docs/blade) to setup tasks that can run on remote servers, such as, cloning your project from the repository, installing the Composer dependencies, and running [Artisan commands](https://laravel.com/docs/artisan).
+
+## Initialize our Laravel app on GitLab
+
+We assume [you have installed a new laravel project](https://laravel.com/docs/installation#installation), so let's start with a unit test, and initialize Git for the project.
+
+### Unit Test
+
+Every new installation of Laravel (currently 5.4) comes with two type of tests, 'Feature' and 'Unit', placed in the tests directory.
+Here's a unit test from `test/Unit/ExampleTest.php`:
+
+```php
+assertTrue(true);
+ }
+}
+```
+
+This test is as simple as asserting that the given value is true.
+
+Laravel uses `PHPUnit` for tests by default.
+If we run `vendor/bin/phpunit` we should see the green output:
+
+```bash
+vendor/bin/phpunit
+OK (1 test, 1 assertions)
+```
+
+This test will be used later for continuously testing our app with GitLab CI/CD.
+
+### Push to GitLab
+
+Since we have our app up and running locally, it's time to push the codebase to our remote repository.
+Let's create [a new project](../../../gitlab-basics/create-project.md) in GitLab named `laravel-sample`.
+After that, follow the command line instructions displayed on the project's homepage to initiate the repository on our machine and push the first commit.
+
+
+```bash
+cd laravel-sample
+git init
+git remote add origin git@gitlab.example.com:/laravel-sample.git
+git add .
+git commit -m 'Initial Commit'
+git push -u origin master
+```
+
+## Configure the production server
+
+Before we begin setting up Envoy and GitLab CI/CD, let's quickly make sure the production server is ready for deployment.
+We have installed LEMP stack which stands for Linux, Nginx, MySQL and PHP on our Ubuntu 16.04.
+
+### Create a new user
+
+Let's now create a new user that will be used to deploy our website and give it
+the needed permissions using [Linux ACL](https://serversforhackers.com/video/linux-acls):
+
+```bash
+# Create user deployer
+sudo adduser deployer
+# Give the read-write-execute permissions to deployer user for directory /var/www
+sudo setfacl -R -m u:deployer:rwx /var/www
+```
+
+If you don't have ACL installed on your Ubuntu server, use this command to install it:
+
+```bash
+sudo apt install acl
+```
+
+### Add SSH key
+
+Let's suppose we want to deploy our app to the production server from a private repository on GitLab. First, we need to [generate a new SSH key pair **with no passphrase**](../../../ssh/README.md) for the deployer user.
+
+After that, we need to copy the private key, which will be used to connect to our server as the deployer user with SSH, to be able to automate our deployment process:
+
+```bash
+# As the deployer user on server
+#
+# Copy the content of public key to authorized_keys
+cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
+# Copy the private key text block
+cat ~/.ssh/id_rsa
+```
+
+Now, let's add it to your GitLab project as a [secret variable](../../variables/README.md#secret-variables).
+Secret variables are user-defined variables and are stored out of `.gitlab-ci.yml`, for security purposes.
+They can be added per project by navigating to the project's **Settings** > **CI/CD**.
+
+![secret variables page](img/secret_variables_page.png)
+
+To the field **KEY**, add the name `SSH_PRIVATE_KEY`, and to the **VALUE** field, paste the private key you've copied earlier.
+We'll use this variable in the `.gitlab-ci.yml` later, to easily connect to our remote server as the deployer user without entering its password.
+
+We also need to add the public key to **Project** > **Settings** > **Repository** as [Deploy Keys](../../../ssh/README.md/#deploy-keys), which gives us the ability to access our repository from the server through [SSH protocol](../../../gitlab-basics/command-line-commands.md/#start-working-on-your-project).
+
+
+```bash
+# As the deployer user on the server
+#
+# Copy the public key
+cat ~/.ssh/id_rsa.pub
+```
+
+![deploy keys page](img/deploy_keys_page.png)
+
+To the field **Title**, add any name you want, and paste the public key into the **Key** field.
+
+Now, let's clone our repository on the server just to make sure the `deployer` user has access to the repository.
+
+```bash
+# As the deployer user on server
+#
+git clone git@gitlab.example.com:/laravel-sample.git
+```
+
+>**Note:**
+Answer **yes** if asked `Are you sure you want to continue connecting (yes/no)?`.
+It adds GitLab.com to the known hosts.
+
+### Configuring Nginx
+
+Now, let's make sure our web server configuration points to the `current/public` rather than `public`.
+
+Open the default Nginx server block configuration file by typing:
+
+```bash
+sudo nano /etc/nginx/sites-available/default
+```
+
+The configuration should be like this.
+
+```
+server {
+ root /var/www/app/current/public;
+ server_name example.com;
+ # Rest of the configuration
+}
+```
+
+>**Note:**
+You may replace the app's name in `/var/www/app/current/public` with the folder name of your application.
+
+## Setting up Envoy
+
+So we have our Laravel app ready for production.
+The next thing is to use Envoy to perform the deploy.
+
+To use Envoy, we should first install it on our local machine [using the given instructions by Laravel](https://laravel.com/docs/envoy/#introduction).
+
+### How Envoy works
+
+The pros of Envoy is that it doesn't require Blade engine, it just uses Blade syntax to define tasks.
+To start, we create an `Envoy.blade.php` in the root of our app with a simple task to test Envoy.
+
+
+```php
+@servers(['web' => 'remote_username@remote_host'])
+
+@task('list', [on => 'web'])
+ ls -l
+@endtask
+```
+
+As you may expect, we have an array within `@servers` directive at the top of the file, which contains a key named `web` with a value of the server's address (e.g. `deployer@192.168.1.1`).
+Then within our `@task` directive we define the bash commands that should be run on the server when the task is executed.
+
+On the local machine use the `run` command to run Envoy tasks.
+
+```bash
+envoy run list
+```
+
+It should execute the `list` task we defined earlier, which connects to the server and lists directory contents.
+
+Envoy is not a dependency of Laravel, therefore you can use it for any PHP application.
+
+### Zero downtime deployment
+
+Every time we deploy to the production server, Envoy downloads the latest release of our app from GitLab repository and replace it with preview's release.
+Envoy does this without any [downtime](https://en.wikipedia.org/wiki/Downtime),
+so we don't have to worry during the deployment while someone might be reviewing the site.
+Our deployment plan is to clone the latest release from GitLab repository, install the Composer dependencies and finally, activate the new release.
+
+#### @setup directive
+
+The first step of our deployment process is to define a set of variables within [@setup](https://laravel.com/docs/envoy/#setup) directive.
+You may change the `app` to your application's name:
+
+
+```php
+...
+
+@setup
+ $repository = 'git@gitlab.example.com:/laravel-sample.git';
+ $releases_dir = '/var/www/app/releases';
+ $app_dir = '/var/www/app';
+ $release = date('YmdHis');
+ $new_release_dir = $releases_dir .'/'. $release;
+@endsetup
+
+...
+```
+
+- `$repository` is the address of our repository
+- `$releases_dir` directory is where we deploy the app
+- `$app_dir` is the actual location of the app that is live on the server
+- `$release` contains a date, so every time that we deploy a new release of our app, we get a new folder with the current date as name
+- `$new_release_dir` is the full path of the new release which is used just to make the tasks cleaner
+
+#### @story directive
+
+The [@story](https://laravel.com/docs/envoy/#stories) directive allows us define a list of tasks that can be run as a single task.
+Here we have three tasks called `clone_repository`, `run_composer`, `update_symlinks`. These variables are usable to making our task's codes more cleaner:
+
+
+```php
+...
+
+@story('deploy')
+ clone_repository
+ run_composer
+ update_symlinks
+@endstory
+
+...
+```
+
+Let's create these three tasks one by one.
+
+#### Clone the repository
+
+The first task will create the `releases` directory (if it doesn't exist), and then clone the `master` branch of the repository (by default) into the new release directory, given by the `$new_release_dir` variable.
+The `releases` directory will hold all our deployments:
+
+```php
+...
+
+@task('clone_repository')
+ echo 'Cloning repository'
+ [ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
+ git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
+@endtask
+
+...
+```
+
+While our project grows, its Git history will be very very long over time.
+Since we are creating a directory per release, it might not be necessary to have the history of the project downloaded for each release.
+The `--depth 1` option is a great solution which saves systems time and disk space as well.
+
+#### Installing dependencies with Composer
+
+As you may know, this task just navigates to the new release directory and runs Composer to install the application dependencies:
+
+```php
+...
+
+@task('run_composer')
+ echo "Starting deployment ({{ $release }})"
+ cd {{ $new_release_dir }}
+ composer install --prefer-dist --no-scripts -q -o
+@endtask
+
+...
+```
+
+#### Activate new release
+
+Next thing to do after preparing the requirements of our new release, is to remove the storage directory from it and to create two symbolic links to point the application's `storage` directory and `.env` file to the new release.
+Then, we need to create another symbolic link to the new release with the name of `current` placed in the app directory.
+The `current` symbolic link always points to the latest release of our app:
+
+```php
+...
+
+@task('update_symlinks')
+ echo "Linking storage directory"
+ rm -rf {{ $new_release_dir }}/storage
+ ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storage
+
+ echo 'Linking .env file'
+ ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env
+
+ echo 'Linking current release'
+ ln -nfs {{ $new_release_dir }} {{ $app_dir }}/current
+@endtask
+```
+
+As you see, we use `-nfs` as an option for `ln` command, which says that the `storage`, `.env` and `current` no longer points to the preview's release and will point them to the new release by force (`f` from `-nfs` means force), which is the case when we are doing multiple deployments.
+
+### Full script
+
+The script is ready, but make sure to change the `deployer@192.168.1.1` to your server and also change `/var/www/app` with the directory you want to deploy your app.
+
+At the end, our `Envoy.blade.php` file will look like this:
+
+```php
+@servers(['web' => 'deployer@192.168.1.1'])
+
+@setup
+ $repository = 'git@gitlab.example.com:/laravel-sample.git';
+ $releases_dir = '/var/www/app/releases';
+ $app_dir = '/var/www/app';
+ $release = date('YmdHis');
+ $new_release_dir = $releases_dir .'/'. $release;
+@endsetup
+
+@story('deploy')
+ clone_repository
+ run_composer
+ update_symlinks
+@endstory
+
+@task('clone_repository')
+ echo 'Cloning repository'
+ [ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
+ git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
+@endtask
+
+@task('run_composer')
+ echo "Starting deployment ({{ $release }})"
+ cd {{ $new_release_dir }}
+ composer install --prefer-dist --no-scripts -q -o
+@endtask
+
+@task('update_symlinks')
+ echo "Linking storage directory"
+ rm -rf {{ $new_release_dir }}/storage
+ ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storage
+
+ echo 'Linking .env file'
+ ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env
+
+ echo 'Linking current release'
+ ln -nfs {{ $new_release_dir }} {{ $app_dir }}/current
+@endtask
+```
+
+One more thing we should do before any deployment is to manually copy our application `storage` folder to the `/var/www/app` directory on the server for the first time.
+You might want to create another Envoy task to do that for you.
+We also create the `.env` file in the same path to setup our production environment variables for Laravel.
+These are persistent data and will be shared to every new release.
+
+Now, we would need to deploy our app by running `envoy run deploy`, but it won't be necessary since GitLab can handle that for us with CI's [environments](../../environments.md), which will be described [later](#setting-up-gitlab-ci-cd) in this tutorial.
+
+Now it's time to commit [Envoy.blade.php](https://gitlab.com/mehranrasulian/laravel-sample/blob/master/Envoy.blade.php) and push it to the `master` branch.
+To keep things simple, we commit directly to `master`, without using [feature-branches](../../../workflow/gitlab_flow.md/#github-flow-as-a-simpler-alternative) since collaboration is beyond the scope of this tutorial.
+In a real world project, teams may use [Issue Tracker](../../../user/project/issues/index.md) and [Merge Requests](../../../user/project/merge_requests/index.md) to move their code across branches:
+
+```bash
+git add Envoy.blade.php
+git commit -m 'Add Envoy'
+git push origin master
+```
+
+## Continuous Integration with GitLab
+
+We have our app ready on GitLab, and we also can deploy it manually.
+But let's take a step forward to do it automatically with [Continuous Delivery](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#continuous-delivery) method.
+We need to check every commit with a set of automated tests to become aware of issues at the earliest, and then, we can deploy to the target environment if we are happy with the result of the tests.
+
+[GitLab CI/CD](../../README.md) allows us to use [Docker](https://docker.com/) engine to handle the process of testing and deploying our app.
+In the case you're not familiar with Docker, refer to [How to Automate Docker Deployments](http://paislee.io/how-to-automate-docker-deployments/).
+
+To be able to build, test, and deploy our app with GitLab CI/CD, we need to prepare our work environment.
+To do that, we'll use a Docker image which has the minimum requirements that a Laravel app needs to run.
+[There are other ways](../php.md/#test-php-projects-using-the-docker-executor) to do that as well, but they may lead our builds run slowly, which is not what we want when there are faster options to use.
+
+With Docker images our builds run incredibly faster!
+
+### Create a Container Image
+
+Let's create a [Dockerfile](https://gitlab.com/mehranrasulian/laravel-sample/blob/master/Dockerfile) in the root directory of our app with the following content:
+
+```bash
+# Set the base image for subsequent instructions
+FROM php:7.1
+
+# Update packages
+RUN apt-get update
+
+# Install PHP and composer dependencies
+RUN apt-get install -qq git curl libmcrypt-dev libjpeg-dev libpng-dev libfreetype6-dev libbz2-dev
+
+# Clear out the local repository of retrieved package files
+RUN apt-get clean
+
+# Install needed extensions
+# Here you can install any other extension that you need during the test and deployment process
+RUN docker-php-ext-install mcrypt pdo_mysql zip
+
+# Install Composer
+RUN curl --silent --show-error https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+
+# Install Laravel Envoy
+RUN composer global require "laravel/envoy=~1.0"
+```
+
+We added the [official PHP 7.1 Docker image](https://hub.docker.com/r/_/php/), which consist of a minimum installation of Debian Jessie with PHP pre-installed, and works perfectly for our use case.
+
+We used `docker-php-ext-install` (provided by the official PHP Docker image) to install the PHP extensions we need.
+
+#### Setting Up GitLab Container Registry
+
+Now that we have our `Dockerfile` let's build and push it to our [GitLab Container Registry](../../../user/project/container_registry.md).
+
+> The registry is the place to store and tag images for later use. Developers may want to maintain their own registry for private, company images, or for throw-away images used only in testing. Using GitLab Container Registry means you don't need to set up and administer yet another service or use a public registry.
+
+On your GitLab project repository navigate to the **Registry** tab.
+
+![container registry page empty image](img/container_registry_page_empty_image.png)
+
+You may need to [enable Container Registry](../../../user/project/container_registry.md#enable-the-container-registry-for-your-project) to your project to see this tab. You'll find it under your project's **Settings > General > Sharing and permissions**.
+
+![container registry checkbox](img/container_registry_checkbox.png)
+
+To start using Container Registry on our machine, we first need to login to the GitLab registry using our GitLab username and password:
+
+```bash
+docker login registry.gitlab.com
+```
+Then we can build and push our image to GitLab:
+
+```bash
+docker build -t registry.gitlab.com//laravel-sample .
+
+docker push registry.gitlab.com//laravel-sample
+```
+
+>**Note:**
+To run the above commands, we first need to have [Docker](https://docs.docker.com/engine/installation/) installed on our machine.
+
+Congratulations! You just pushed the first Docker image to the GitLab Registry, and if you refresh the page you should be able to see it:
+
+![container registry page with image](img/container_registry_page_with_image.jpg)
+
+>**Note:**
+You can also [use GitLab CI/CD](https://about.gitlab.com/2016/05/23/gitlab-container-registry/#use-with-gitlab-ci) to build and push your Docker images, rather than doing that on your machine.
+
+We'll use this image further down in the `.gitlab-ci.yml` configuration file to handle the process of testing and deploying our app.
+
+Let's commit the `Dockerfile` file.
+
+```bash
+git add Dockerfile
+git commit -m 'Add Dockerfile'
+git push origin master
+```
+
+### Setting up GitLab CI/CD
+
+In order to build and test our app with GitLab CI/CD, we need a file called `.gitlab-ci.yml` in our repository's root. It is similar to Circle CI and Travis CI, but built-in GitLab.
+
+Our `.gitlab-ci.yml` file will look like this:
+
+```yaml
+image: registry.gitlab.com//laravel-sample:latest
+
+services:
+ - mysql:5.7
+
+variables:
+ MYSQL_DATABASE: homestead
+ MYSQL_ROOT_PASSWORD: secret
+ DB_HOST: mysql
+ DB_USERNAME: root
+
+stages:
+ - test
+ - deploy
+
+unit_test:
+ stage: test
+ script:
+ - cp .env.example .env
+ - composer install
+ - php artisan key:generate
+ - php artisan migrate
+ - vendor/bin/phpunit
+
+deploy_production:
+ stage: deploy
+ script:
+ - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
+ - eval $(ssh-agent -s)
+ - ssh-add <(echo "$SSH_PRIVATE_KEY")
+ - mkdir -p ~/.ssh
+ - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
+
+ - ~/.composer/vendor/bin/envoy run deploy
+ environment:
+ name: production
+ url: http://192.168.1.1
+ when: manual
+ only:
+ - master
+```
+
+That's a lot to take in, isn't it? Let's run through it step by step.
+
+#### Image and Services
+
+[GitLab Runners](../../runners/README.md) run the script defined by `.gitlab-ci.yml`.
+The `image` keyword tells the Runners which image to use.
+The `services` keyword defines additional images [that are linked to the main image](../../docker/using_docker_images.md/#what-is-a-service).
+Here we use the container image we created before as our main image and also use MySQL 5.7 as a service.
+
+```yaml
+image: registry.gitlab.com//laravel-sample:latest
+
+services:
+ - mysql:5.7
+
+...
+```
+
+>**Note:**
+If you wish to test your app with different PHP versions and [database management systems](../../services/README.md), you can define different `image` and `services` keywords for each test job.
+
+#### Variables
+
+GitLab CI/CD allows us to use [environment variables](../../yaml/README.md#variables) in our jobs.
+We defined MySQL as our database management system, which comes with a superuser root created by default.
+
+So we should adjust the configuration of MySQL instance by defining `MYSQL_DATABASE` variable as our database name and `MYSQL_ROOT_PASSWORD` variable as the password of `root`.
+Find out more about MySQL variables at the [official MySQL Docker Image](https://hub.docker.com/r/_/mysql/).
+
+Also set the variables `DB_HOST` to `mysql` and `DB_USERNAME` to `root`, which are Laravel specific variables.
+We define `DB_HOST` as `mysql` instead of `127.0.0.1`, as we use MySQL Docker image as a service which [is linked to the main Docker image](../../docker/using_docker_images.md/#how-services-are-linked-to-the-build).
+
+```yaml
+...
+
+variables:
+ MYSQL_DATABASE: homestead
+ MYSQL_ROOT_PASSWORD: secret
+ DB_HOST: mysql
+ DB_USERNAME: root
+
+...
+```
+
+#### Unit Test as the first job
+
+We defined the required shell scripts as an array of the [script](../../yaml/README.md#script) variable to be executed when running `unit_test` job.
+
+These scripts are some Artisan commands to prepare the Laravel, and, at the end of the script, we'll run the tests by `PHPUnit`.
+
+```yaml
+...
+
+unit_test:
+ script:
+ # Install app dependencies
+ - composer install
+ # Setup .env
+ - cp .env.example .env
+ # Generate an environment key
+ - php artisan key:generate
+ # Run migrations
+ - php artisan migrate
+ # Run tests
+ - vendor/bin/phpunit
+
+...
+```
+
+#### Deploy to production
+
+The job `deploy_production` will deploy the app to the production server.
+To deploy our app with Envoy, we had to set up the `$SSH_PRIVATE_KEY` variable as an [SSH private key](../../ssh_keys/README.md/#ssh-keys-when-using-the-docker-executor).
+If the SSH keys have added successfully, we can run Envoy.
+
+As mentioned before, GitLab supports [Continuous Delivery](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#continuous-delivery) methods as well.
+The [environment](../../yaml/README.md#environment) keyword tells GitLab that this job deploys to the `production` environment.
+The `url` keyword is used to generate a link to our application on the GitLab Environments page.
+The `only` keyword tells GitLab CI that the job should be executed only when the pipeline is building the `master` branch.
+Lastly, `when: manual` is used to turn the job from running automatically to a manual action.
+
+```yaml
+...
+
+deploy_production:
+ script:
+ # Add the private SSH key to the build environment
+ - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
+ - eval $(ssh-agent -s)
+ - ssh-add <(echo "$SSH_PRIVATE_KEY")
+ - mkdir -p ~/.ssh
+ - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
+
+ # Run Envoy
+ - ~/.composer/vendor/bin/envoy run deploy
+
+ environment:
+ name: production
+ url: http://192.168.1.1
+ when: manual
+ only:
+ - master
+```
+
+You may also want to add another job for [staging environment](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments), to final test your application before deploying to production.
+
+### Turn on GitLab CI/CD
+
+We have prepared everything we need to test and deploy our app with GitLab CI/CD.
+To do that, commit and push `.gitlab-ci.yml` to the `master` branch. It will trigger a pipeline, which you can watch live under your project's **Pipelines**.
+
+![pipelines page](img/pipelines_page.png)
+
+Here we see our **Test** and **Deploy** stages.
+The **Test** stage has the `unit_test` build running.
+click on it to see the Runner's output.
+
+![pipeline page](img/pipeline_page.png)
+
+After our code passed through the pipeline successfully, we can deploy to our production server by clicking the **play** button on the right side.
+
+![pipelines page deploy button](img/pipelines_page_deploy_button.png)
+
+Once the deploy pipeline passed successfully, navigate to **Pipelines > Environments**.
+
+![environments page](img/environments_page.png)
+
+If something doesn't work as expected, you can roll back to the latest working version of your app.
+
+![environment page](img/environment_page.png)
+
+By clicking on the external link icon specified on the right side, GitLab opens the production website.
+Our deployment successfully was done and we can see the application is live.
+
+![laravel welcome page](img/laravel_welcome_page.png)
+
+In the case that you're interested to know how is the application directory structure on the production server after deployment, here are three directories named `current`, `releases` and `storage`.
+As you know, the `current` directory is a symbolic link that points to the latest release.
+The `.env` file consists of our Laravel environment variables.
+
+![production server app directory](img/production_server_app_directory.png)
+
+If you navigate to the `current` directory, you should see the application's content.
+As you see, the `.env` is pointing to the `/var/www/app/.env` file and also `storage` is pointing to the `/var/www/app/storage/` directory.
+
+![production server current directory](img/production_server_current_directory.png)
+
+## Conclusion
+
+We configured GitLab CI to perform automated tests and used the method of [Continuous Delivery](https://continuousdelivery.com/) to deploy to production a Laravel application with Envoy, directly from the codebase.
+
+Envoy also was a great match to help us deploy the application without writing our custom bash script and doing Linux magics.
--
cgit v1.2.1
From 8d569f9fe9bddaa09cb05c1c42b1c39b7bf3b3aa Mon Sep 17 00:00:00 2001
From: Lin Jen-Shin
Date: Fri, 5 Jan 2018 23:21:47 +0800
Subject: Document that we need rsync for backing up
---
doc/install/installation.md | 2 +-
doc/raketasks/backup_restore.md | 21 +++++++++++++++++----
doc/update/10.3-to-10.4.md | 2 ++
3 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 2b7352d3561..b2acd5e78b5 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -64,7 +64,7 @@ up-to-date and install it.
Install the required packages (needed to compile Ruby and native extensions to Ruby gems):
- sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libre2-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake
+ sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libre2-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate rsync python-docutils pkg-config cmake
Ubuntu 14.04 (Trusty Tahr) doesn't have the `libre2-dev` package available, but
you can [install re2 manually](https://github.com/google/re2/wiki/Install).
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 54c3e20d61d..50bb665216e 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -5,8 +5,8 @@
An application data backup creates an archive file that contains the database,
all repositories and all attachments.
-You can only restore a backup to **exactly the same version and type (CE/EE)**
-of GitLab on which it was created. The best way to migrate your repositories
+You can only restore a backup to **exactly the same version and type (CE/EE)**
+of GitLab on which it was created. The best way to migrate your repositories
from one server to another is through backup restore.
## Backup
@@ -14,6 +14,19 @@ from one server to another is through backup restore.
GitLab provides a simple command line interface to backup your whole installation,
and is flexible enough to fit your needs.
+### Requirements
+
+If you're using GitLab with the Omnibus package, you're all set. If you
+installed GitLab from source, make sure the following packages are installed:
+
+* rsync
+
+If you're using Ubuntu, you could run:
+
+```
+sudo apt-get install -y rsync
+```
+
### Backup timestamp
>**Note:**
@@ -431,7 +444,7 @@ The [restore prerequisites section](#restore-prerequisites) includes crucial
information. Make sure to read and test the whole restore process at least once
before attempting to perform it in a production environment.
-You can only restore a backup to **exactly the same version and type (CE/EE)** of
+You can only restore a backup to **exactly the same version and type (CE/EE)** of
GitLab that you created it on, for example CE 9.1.0.
### Restore prerequisites
@@ -511,7 +524,7 @@ sudo service gitlab restart
This procedure assumes that:
-- You have installed the **exact same version and type (CE/EE)** of GitLab
+- You have installed the **exact same version and type (CE/EE)** of GitLab
Omnibus with which the backup was created.
- You have run `sudo gitlab-ctl reconfigure` at least once.
- GitLab is running. If not, start it using `sudo gitlab-ctl start`.
diff --git a/doc/update/10.3-to-10.4.md b/doc/update/10.3-to-10.4.md
index 850cb3103f4..67b7e634c94 100644
--- a/doc/update/10.3-to-10.4.md
+++ b/doc/update/10.3-to-10.4.md
@@ -21,6 +21,8 @@ sudo service gitlab stop
### 2. Backup
+NOTE: If you installed GitLab from source, make sure `rsync` is installed.
+
```bash
cd /home/git/gitlab
--
cgit v1.2.1
From 1dc30595e34eac0fcfa28e0dca2b7a22c02bacc3 Mon Sep 17 00:00:00 2001
From: Michael Kozono
Date: Tue, 9 Jan 2018 13:06:21 -0800
Subject: Revert "Revert "Fix Route validation for unchanged path""
This reverts commit 3576d59ae95a61dd20e997a619dbc6c8e8a70276.
---
app/models/route.rb | 2 +-
spec/models/route_spec.rb | 60 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/app/models/route.rb b/app/models/route.rb
index 7ba3ec06041..412f5fb45a5 100644
--- a/app/models/route.rb
+++ b/app/models/route.rb
@@ -8,7 +8,7 @@ class Route < ActiveRecord::Base
presence: true,
uniqueness: { case_sensitive: false }
- validate :ensure_permanent_paths
+ validate :ensure_permanent_paths, if: :path_changed?
after_create :delete_conflicting_redirects
after_update :delete_conflicting_redirects, if: :path_changed?
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index ddad6862a63..2f141d96144 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -16,6 +16,66 @@ describe Route do
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path).case_insensitive }
+
+ describe '#ensure_permanent_paths' do
+ context 'when the route is not yet persisted' do
+ let(:new_route) { Route.new(path: 'foo', source: build(:group)) }
+
+ context 'when permanent conflicting redirects exist' do
+ it 'is invalid' do
+ redirect = RedirectRoute.new(path: 'foo/bar/baz', source: create(:group), permanent: true)
+ redirect.save!(validate: false)
+
+ expect(new_route.valid?).to be_falsey
+ expect(new_route.errors.first[1]).to eq('foo has been taken before. Please use another one')
+ end
+ end
+
+ context 'when no permanent conflicting redirects exist' do
+ it 'is valid' do
+ expect(new_route.valid?).to be_truthy
+ end
+ end
+ end
+
+ context 'when path has changed' do
+ before do
+ route.path = 'foo'
+ end
+
+ context 'when permanent conflicting redirects exist' do
+ it 'is invalid' do
+ redirect = RedirectRoute.new(path: 'foo/bar/baz', source: create(:group), permanent: true)
+ redirect.save!(validate: false)
+
+ expect(route.valid?).to be_falsey
+ expect(route.errors.first[1]).to eq('foo has been taken before. Please use another one')
+ end
+ end
+
+ context 'when no permanent conflicting redirects exist' do
+ it 'is valid' do
+ expect(route.valid?).to be_truthy
+ end
+ end
+ end
+
+ context 'when path has not changed' do
+ context 'when permanent conflicting redirects exist' do
+ it 'is valid' do
+ redirect = RedirectRoute.new(path: 'git_lab/foo/bar', source: create(:group), permanent: true)
+ redirect.save!(validate: false)
+
+ expect(route.valid?).to be_truthy
+ end
+ end
+ context 'when no permanent conflicting redirects exist' do
+ it 'is valid' do
+ expect(route.valid?).to be_truthy
+ end
+ end
+ end
+ end
end
describe 'callbacks' do
--
cgit v1.2.1
From 6fcef53525fbda24f58eddf11bc2275c58af9632 Mon Sep 17 00:00:00 2001
From: Clement Ho
Date: Thu, 11 Jan 2018 12:07:49 -0600
Subject: Refactor dispatcher project branches path
---
app/assets/javascripts/dispatcher.js | 7 +++----
app/assets/javascripts/pages/projects/branches/index/index.js | 7 +++++++
2 files changed, 10 insertions(+), 4 deletions(-)
create mode 100644 app/assets/javascripts/pages/projects/branches/index/index.js
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 72a6426e901..2a3ad119b82 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -30,7 +30,6 @@ import CommitsList from './commits';
import Issue from './issue';
import BindInOut from './behaviors/bind_in_out';
import SecretValues from './behaviors/secret_values';
-import DeleteModal from './branches/branches_delete_modal';
import Group from './group';
import ProjectsList from './projects_list';
import setupProjectEdit from './project_edit';
@@ -59,7 +58,6 @@ import GpgBadges from './gpg_badges';
import initChangesDropdown from './init_changes_dropdown';
import NewGroupChild from './groups/new_group_child';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
-import AjaxLoadingSpinner from './ajax_loading_spinner';
import GlFieldErrors from './gl_field_errors';
import GLForm from './gl_form';
import Shortcuts from './shortcuts';
@@ -246,8 +244,9 @@ import Activities from './activities';
new NewBranchForm($('.js-create-branch-form'), JSON.parse(document.getElementById('availableRefs').innerHTML));
break;
case 'projects:branches:index':
- AjaxLoadingSpinner.init();
- new DeleteModal();
+ import('./pages/projects/branches/index')
+ .then(callDefault)
+ .catch(fail);
break;
case 'projects:issues:new':
case 'projects:issues:edit':
diff --git a/app/assets/javascripts/pages/projects/branches/index/index.js b/app/assets/javascripts/pages/projects/branches/index/index.js
new file mode 100644
index 00000000000..cee0f19bf2a
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/branches/index/index.js
@@ -0,0 +1,7 @@
+import AjaxLoadingSpinner from '~/ajax_loading_spinner';
+import DeleteModal from '~/branches/branches_delete_modal';
+
+export default () => {
+ AjaxLoadingSpinner.init();
+ new DeleteModal(); // eslint-disable-line no-new
+};
--
cgit v1.2.1
From c517788e671a0a81b08dbad1fb4537f0f56a43d0 Mon Sep 17 00:00:00 2001
From: Michael Kozono
Date: Thu, 11 Jan 2018 10:22:40 -0800
Subject: Fix Rubocop offense
---
spec/models/route_spec.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index 2f141d96144..1266e0ea602 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -19,7 +19,7 @@ describe Route do
describe '#ensure_permanent_paths' do
context 'when the route is not yet persisted' do
- let(:new_route) { Route.new(path: 'foo', source: build(:group)) }
+ let(:new_route) { described_class.new(path: 'foo', source: build(:group)) }
context 'when permanent conflicting redirects exist' do
it 'is invalid' do
--
cgit v1.2.1
From ce3c70aded0e10af6434d8bfd011815640083f71 Mon Sep 17 00:00:00 2001
From: Eric Eastwood
Date: Wed, 10 Jan 2018 14:18:15 -0600
Subject: Update Ingress extra cost note to be more generic
Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/41163
---
app/assets/javascripts/clusters/components/applications.vue | 13 +++++++------
.../41163-improve-cluster-ingress-extra-cost-language.yml | 5 +++++
2 files changed, 12 insertions(+), 6 deletions(-)
create mode 100644 changelogs/unreleased/41163-improve-cluster-ingress-extra-cost-language.yml
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index 25cef44c1b8..57457ebd0a3 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -46,14 +46,15 @@
));
const extraCostParagraph = sprintf(
- _.escape(s__(`ClusterIntegration|%{boldNotice} This will add some
-extra resources like a load balancer,
-which incur additional costs. See %{pricingLink}`)),
- {
+ _.escape(s__(
+ `ClusterIntegration|%{boldNotice} This will add some extra resources
+ like a load balancer, which may incur additional costs depending on
+ the hosting provider Kubernetes is installed on. If you are using GKE,
+ you can %{pricingLink}.`,
+ )), {
boldNotice: `${_.escape(s__('ClusterIntegration|Note:'))}`,
pricingLink: `
- ${_.escape(s__('ClusterIntegration|GKE pricing'))}
- `,
+ ${_.escape(s__('ClusterIntegration|check the pricing here'))}`,
},
false,
);
diff --git a/changelogs/unreleased/41163-improve-cluster-ingress-extra-cost-language.yml b/changelogs/unreleased/41163-improve-cluster-ingress-extra-cost-language.yml
new file mode 100644
index 00000000000..9c48831855c
--- /dev/null
+++ b/changelogs/unreleased/41163-improve-cluster-ingress-extra-cost-language.yml
@@ -0,0 +1,5 @@
+---
+title: Improve wording about additional costs for Ingress on custom clusters
+merge_request:
+author:
+type: changed
--
cgit v1.2.1
From 601c24d5b6b4b10ea986223c7a38110435420dbe Mon Sep 17 00:00:00 2001
From: Michael Kozono
Date: Thu, 11 Jan 2018 11:17:38 -0800
Subject: Add RedirectRoute factory
---
spec/factories/redirect_routes.rb | 15 +++++++++++++++
spec/models/route_spec.rb | 6 +++---
2 files changed, 18 insertions(+), 3 deletions(-)
create mode 100644 spec/factories/redirect_routes.rb
diff --git a/spec/factories/redirect_routes.rb b/spec/factories/redirect_routes.rb
new file mode 100644
index 00000000000..c29c81c5df9
--- /dev/null
+++ b/spec/factories/redirect_routes.rb
@@ -0,0 +1,15 @@
+FactoryBot.define do
+ factory :redirect_route do
+ sequence(:path) { |n| "redirect#{n}" }
+ source factory: :group
+ permanent false
+
+ trait :permanent do
+ permanent true
+ end
+
+ trait :temporary do
+ permanent false
+ end
+ end
+end
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index 1266e0ea602..8a3b1034f3c 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -23,7 +23,7 @@ describe Route do
context 'when permanent conflicting redirects exist' do
it 'is invalid' do
- redirect = RedirectRoute.new(path: 'foo/bar/baz', source: create(:group), permanent: true)
+ redirect = build(:redirect_route, :permanent, path: 'foo/bar/baz')
redirect.save!(validate: false)
expect(new_route.valid?).to be_falsey
@@ -45,7 +45,7 @@ describe Route do
context 'when permanent conflicting redirects exist' do
it 'is invalid' do
- redirect = RedirectRoute.new(path: 'foo/bar/baz', source: create(:group), permanent: true)
+ redirect = build(:redirect_route, :permanent, path: 'foo/bar/baz')
redirect.save!(validate: false)
expect(route.valid?).to be_falsey
@@ -63,7 +63,7 @@ describe Route do
context 'when path has not changed' do
context 'when permanent conflicting redirects exist' do
it 'is valid' do
- redirect = RedirectRoute.new(path: 'git_lab/foo/bar', source: create(:group), permanent: true)
+ redirect = build(:redirect_route, :permanent, path: 'git_lab/foo/bar')
redirect.save!(validate: false)
expect(route.valid?).to be_truthy
--
cgit v1.2.1
From d4c8d1b7b2ba679c6eb5d55643abd48c621afc85 Mon Sep 17 00:00:00 2001
From: Michael Kozono
Date: Thu, 11 Jan 2018 11:22:13 -0800
Subject: Add changelog entry
---
changelogs/unreleased/mk-fix-permanent-redirect-validation.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 changelogs/unreleased/mk-fix-permanent-redirect-validation.yml
diff --git a/changelogs/unreleased/mk-fix-permanent-redirect-validation.yml b/changelogs/unreleased/mk-fix-permanent-redirect-validation.yml
new file mode 100644
index 00000000000..153b2ccc25c
--- /dev/null
+++ b/changelogs/unreleased/mk-fix-permanent-redirect-validation.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent invalid Route path if path is unchanged
+merge_request: 16397
+author:
+type: fixed
--
cgit v1.2.1
From f4319f6a1828993503dc6683b65a5895a5c2fb5b Mon Sep 17 00:00:00 2001
From: Stan Hu
Date: Thu, 11 Jan 2018 13:00:03 -0800
Subject: Remove warning noise in ProjectImportOptions
Squlches these warnings:
```
/opt/gitlab/embedded/service/gitlab-rails/app/workers/concerns/project_import_options.rb:5: warning: already initialized constant ProjectImportOptions::IMPORT_RETRY_COUNT
/opt/gitlab/embedded/service/gitlab-rails/app/workers/concerns/project_import_options.rb:5: warning: previous definition of IMPORT_RETRY_COUNT was here
```
---
app/workers/concerns/project_import_options.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/workers/concerns/project_import_options.rb b/app/workers/concerns/project_import_options.rb
index 10b971344f7..ef23990ad97 100644
--- a/app/workers/concerns/project_import_options.rb
+++ b/app/workers/concerns/project_import_options.rb
@@ -1,9 +1,9 @@
module ProjectImportOptions
extend ActiveSupport::Concern
- included do
- IMPORT_RETRY_COUNT = 5
+ IMPORT_RETRY_COUNT = 5
+ included do
sidekiq_options retry: IMPORT_RETRY_COUNT, status_expiration: StuckImportJobsWorker::IMPORT_JOBS_EXPIRATION
# We only want to mark the project as failed once we exhausted all retries
--
cgit v1.2.1
From 6aaf096e2fff10e12645e84d10d1b2fa4b11cf56 Mon Sep 17 00:00:00 2001
From: Takuya Noguchi
Date: Mon, 8 Jan 2018 02:37:06 +0900
Subject: Add reason to keep postgresql 9.2 for CI
---
.gitlab-ci.yml | 3 +++
changelogs/unreleased/41749-postgres-9-6-for-ci-tests.yml | 5 +++++
2 files changed, 8 insertions(+)
create mode 100644 changelogs/unreleased/41749-postgres-9-6-for-ci-tests.yml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4f47d3f0171..c0fa010b121 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -61,6 +61,9 @@ stages:
.use-pg: &use-pg
services:
+ # As of Jan 2018, we don't have a strong reason to upgrade to 9.6 for CI yet,
+ # so using the least common denominator ensures backwards compatibility
+ # (as many users are still using 9.2).
- postgres:9.2
- redis:alpine
diff --git a/changelogs/unreleased/41749-postgres-9-6-for-ci-tests.yml b/changelogs/unreleased/41749-postgres-9-6-for-ci-tests.yml
new file mode 100644
index 00000000000..2a3d00f8e5f
--- /dev/null
+++ b/changelogs/unreleased/41749-postgres-9-6-for-ci-tests.yml
@@ -0,0 +1,5 @@
+---
+title: Add reason to keep postgresql 9.2 for CI
+merge_request: 16277
+author: Takuya Noguchi
+type: other
--
cgit v1.2.1
From 74428414aa7e770be8a783bc52dd08feb5a63f64 Mon Sep 17 00:00:00 2001
From: Mike Greiling
Date: Thu, 11 Jan 2018 16:52:46 -0600
Subject: fix case where tooltip messes up :last-child selector
---
app/views/dashboard/issues.html.haml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 42941acc508..3e85535dae0 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -7,7 +7,7 @@
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls
- = link_to params.merge(rss_url_options), class: 'btn has-tooltip', title: 'Subscribe' do
+ = link_to params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe' do
= icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
--
cgit v1.2.1
From 333c1723ab94ca5a7820556a9260f4904fc42822 Mon Sep 17 00:00:00 2001
From: Eric Eastwood
Date: Thu, 11 Jan 2018 20:22:28 -0600
Subject: Fix Ctrl+Enter keyboard shortcut saving comment/note edit
Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/41956
---
app/assets/javascripts/notes/components/comment_form.vue | 5 +++--
app/assets/javascripts/notes/components/note_form.vue | 1 +
.../41956-fix-ctrl-enter-binding-to-save-comment.yml | 5 +++++
spec/javascripts/notes/components/comment_form_spec.js | 10 +++++++++-
spec/javascripts/notes/components/note_form_spec.js | 9 ++++++++-
5 files changed, 26 insertions(+), 4 deletions(-)
create mode 100644 changelogs/unreleased/41956-fix-ctrl-enter-binding-to-save-comment.yml
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 1f18c196137..3c8452ac808 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -271,7 +271,7 @@ Please check your network connection and try again.`;