Commit a6ddad78 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Merge remote-tracking branch 'ee/master' into ce-to-ee-2017-09-29

* ee/master:
  (EE) Create repositories via Gitaly
  Remove changelogs with invalid extensions
  Extend changelog checker to test file extensions
  Fix invalid changelog entries
  Manually add CHANGELOG entry for !13325
  Add static analysis job to find invalid YAML in changelogs
  Merge branch 'sh-fix-gitlab-qa-admin' into 'master'
  Adds a Gitaly n+1 notice to commit handling on access check
  Fix EE delta size check handling with annotated tags
  Makes code quality requests in parallel
  Fix Ruby code for disabling Auto DevOps banner
parents f88a6e0b 3f8c0079
...@@ -85,6 +85,8 @@ entry. ...@@ -85,6 +85,8 @@ entry.
- [FIXED] Fixed merge request changes bar jumping. - [FIXED] Fixed merge request changes bar jumping.
- [FIXED] Improve migrations using triggers. - [FIXED] Improve migrations using triggers.
- [FIXED] Fix ConvDev Index nav item and Monitoring submenu regression. - [FIXED] Fix ConvDev Index nav item and Monitoring submenu regression.
- [FIXED] disabling notifications globally now properly turns off group/project added
emails !13325
- [DEPRECATED] Deprecate custom SSH client configuration for the git user. !13930 - [DEPRECATED] Deprecate custom SSH client configuration for the git user. !13930
- [CHANGED] allow all users to delete their account. !13636 (Jacopo Beschi @jacopo-beschi) - [CHANGED] allow all users to delete their account. !13636 (Jacopo Beschi @jacopo-beschi)
- [CHANGED] Use full path of project's avatar in webhooks. !13649 (Vitaliy @blackst0ne Klachkov) - [CHANGED] Use full path of project's avatar in webhooks. !13649 (Vitaliy @blackst0ne Klachkov)
......
...@@ -414,7 +414,7 @@ group :ed25519 do ...@@ -414,7 +414,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 0.37.0', require: 'gitaly' gem 'gitaly-proto', '~> 0.38.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false gem 'toml-rb', '~> 0.3.15', require: false
......
...@@ -299,7 +299,7 @@ GEM ...@@ -299,7 +299,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
gitaly-proto (0.37.0) gitaly-proto (0.38.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.0) grpc (~> 1.0)
github-linguist (4.7.6) github-linguist (4.7.6)
...@@ -1060,7 +1060,7 @@ DEPENDENCIES ...@@ -1060,7 +1060,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0) gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.37.0) gitaly-proto (~> 0.38.0)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
......
...@@ -1035,7 +1035,7 @@ class Project < ActiveRecord::Base ...@@ -1035,7 +1035,7 @@ class Project < ActiveRecord::Base
# Forked import is handled asynchronously # Forked import is handled asynchronously
return if forked? && !force return if forked? && !force
if gitlab_shell.add_repository(repository_storage_path, disk_path) if gitlab_shell.add_repository(repository_storage, disk_path)
repository.after_create repository.after_create
true true
else else
......
...@@ -189,7 +189,7 @@ class ProjectWiki ...@@ -189,7 +189,7 @@ class ProjectWiki
private private
def init_repo(disk_path) def init_repo(disk_path)
gitlab_shell.add_repository(project.repository_storage_path, disk_path) gitlab_shell.add_repository(project.repository_storage, disk_path)
end end
def commit_details(action, message = nil, title = nil) def commit_details(action, message = nil, title = nil)
......
---
title: Adds hoverstates for collapsed Issue/Merge Request sidebar for Time tracking Icon
merge_request:
author:
---
title: Fix EE delta size check handling with annotated tags
merge_request:
author:
type: fixed
---
title: "Fix v3 api project_hooks POST and PUT operations for build_events"
merge_request: 12673
author: Richard Clamp
---
title: "reset text-align to initial to let elements with dir="auto" align texts to right in RTL languages ( default is left )"
merge_request: 12892
author: goshhob
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
title: Allow to use same periods for different housekeeping tasks (effectively title: Allow to use same periods for different housekeeping tasks (effectively
skipping the lesser task) skipping the lesser task)
merge_request: 13711 merge_request: 13711
author: @cernvcs author: cernvcs
type: added type: added
---
title: Handle unsubscribe from email notifications via replying to reply+%{key}+unsubscribe@ address
merge_request: 6597
author:
---
title: Refactor Timelogs structure to use foreign keys.
merge_request: 8769
author:
---
title: "Correction to documention for manual steps on the Jobs API"
merge_request: 11411
author: Zac Sturgess
\ No newline at end of file
---
title: "Fix API to serve binary diffs that are treated as text."
merge_request: 14038
--- ---
title: Add GitLab-Pages version to Admin Dashboard title: Add GitLab-Pages version to Admin Dashboard
merge_request: 14040 merge_request: 14040
author: @travismiller author: travismiller
type: added type: added
---
title: Added mock deployment and monitoring service with environments fixtures
merge_request:
author:
---
title: Detect when changelog entries are invalid
merge_request:
author:
type: other
---
title: Added ability to put emojis into repository name
merge_request: 7420
author: Vincent Composieux
...@@ -111,18 +111,15 @@ export default { ...@@ -111,18 +111,15 @@ export default {
this.isLoading = true; this.isLoading = true;
this.service.fetchCodeclimate(head_path) Promise.all([
.then(resp => resp.json()) this.service.fetchCodeclimate(head_path)
.then((data) => { .then(resp => resp.json()),
this.mr.setCodeclimateHeadMetrics(data); this.service.fetchCodeclimate(base_path)
this.service.fetchCodeclimate(base_path) .then(resp => resp.json()),
.then(response => response.json()) ])
.then(baseData => this.mr.setCodeclimateBaseMetrics(baseData)) .then((values) => {
.then(() => this.mr.compareCodeclimateMetrics()) this.mr.compareCodeclimateMetrics(values[0], values[1]);
.then(() => { this.isLoading = false;
this.isLoading = false;
})
.catch(() => this.handleError());
}) })
.catch(() => this.handleError()); .catch(() => this.handleError());
}, },
......
...@@ -53,24 +53,12 @@ export default class MergeRequestStore extends CEMergeRequestStore { ...@@ -53,24 +53,12 @@ export default class MergeRequestStore extends CEMergeRequestStore {
initCodeclimate(data) { initCodeclimate(data) {
this.codeclimate = data.codeclimate; this.codeclimate = data.codeclimate;
this.codeclimateMetrics = { this.codeclimateMetrics = {
headIssues: [],
baseIssues: [],
newIssues: [], newIssues: [],
resolvedIssues: [], resolvedIssues: [],
}; };
} }
setCodeclimateHeadMetrics(data) { compareCodeclimateMetrics(headIssues, baseIssues) {
this.codeclimateMetrics.headIssues = data;
}
setCodeclimateBaseMetrics(data) {
this.codeclimateMetrics.baseIssues = data;
}
compareCodeclimateMetrics() {
const { headIssues, baseIssues } = this.codeclimateMetrics;
this.codeclimateMetrics.newIssues = this.filterByFingerprint(headIssues, baseIssues); this.codeclimateMetrics.newIssues = this.filterByFingerprint(headIssues, baseIssues);
this.codeclimateMetrics.resolvedIssues = this.filterByFingerprint(baseIssues, headIssues); this.codeclimateMetrics.resolvedIssues = this.filterByFingerprint(baseIssues, headIssues);
} }
......
...@@ -7,6 +7,9 @@ module EE ...@@ -7,6 +7,9 @@ module EE
begin begin
tree_a = repo.lookup(change[:oldrev]) tree_a = repo.lookup(change[:oldrev])
tree_b = repo.lookup(change[:newrev]) tree_b = repo.lookup(change[:newrev])
return size_of_deltas unless diffable?(tree_a) && diffable?(tree_b)
diff = tree_a.diff(tree_b) diff = tree_a.diff(tree_b)
diff.each_delta do |d| diff.each_delta do |d|
...@@ -25,6 +28,10 @@ module EE ...@@ -25,6 +28,10 @@ module EE
size_of_deltas size_of_deltas
end end
end end
def self.diffable?(object)
[Rugged::Commit, Rugged::Tree].include?(object.class)
end
end end
end end
end end
...@@ -162,14 +162,17 @@ module Gitlab ...@@ -162,14 +162,17 @@ module Gitlab
# if newrev is blank, the branch was deleted # if newrev is blank, the branch was deleted
return if deletion? || !(commit_validation || validate_path_locks?) return if deletion? || !(commit_validation || validate_path_locks?)
commits.each do |commit| # n+1: https://gitlab.com/gitlab-org/gitlab-ee/issues/3593
if commit_validation Gitlab::GitalyClient.allow_n_plus_1_calls do
error = check_commit(commit, push_rule) commits.each do |commit|
raise GitAccess::UnauthorizedError, error if error if commit_validation
end error = check_commit(commit, push_rule)
raise GitAccess::UnauthorizedError, error if error
if error = check_commit_diff(commit, push_rule) end
raise GitAccess::UnauthorizedError, error
if error = check_commit_diff(commit, push_rule)
raise GitAccess::UnauthorizedError, error
end
end end
end end
end end
......
...@@ -23,11 +23,8 @@ module Gitlab ...@@ -23,11 +23,8 @@ module Gitlab
TagExistsError = Class.new(StandardError) TagExistsError = Class.new(StandardError)
class << self class << self
# Unlike `new`, `create` takes the storage path, not the storage name # Unlike `new`, `create` takes the repository path
def create(storage_path, name, bare: true, symlink_hooks_to: nil) def create(repo_path, bare: true, symlink_hooks_to: nil)
repo_path = File.join(storage_path, name)
repo_path += '.git' unless repo_path.end_with?('.git')
FileUtils.mkdir_p(repo_path, mode: 0770) FileUtils.mkdir_p(repo_path, mode: 0770)
# Equivalent to `git --git-path=#{repo_path} init [--bare]` # Equivalent to `git --git-path=#{repo_path} init [--bare]`
......
...@@ -53,6 +53,11 @@ module Gitlab ...@@ -53,6 +53,11 @@ module Gitlab
GitalyClient.call(@storage, :repository_service, :fetch_remote, request) GitalyClient.call(@storage, :repository_service, :fetch_remote, request)
end end
def create_repository
request = Gitaly::CreateRepositoryRequest.new(repository: @gitaly_repo)
GitalyClient.call(@storage, :repository_service, :create_repository, request)
end
end end
end end
end end
...@@ -65,7 +65,7 @@ module Gitlab ...@@ -65,7 +65,7 @@ module Gitlab
# Init new repository # Init new repository
# #
# storage - project's storage path # storage - project's storage name
# name - project path with namespace # name - project path with namespace
# #
# Ex. # Ex.
...@@ -73,7 +73,19 @@ module Gitlab ...@@ -73,7 +73,19 @@ module Gitlab
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def add_repository(storage, name) def add_repository(storage, name)
Gitlab::Git::Repository.create(storage, name, bare: true, symlink_hooks_to: gitlab_shell_hooks_path) relative_path = name.dup
relative_path << '.git' unless relative_path.end_with?('.git')
gitaly_migrate(:create_repository) do |is_enabled|
if is_enabled
repository = Gitlab::Git::Repository.new(storage, relative_path, '')
repository.gitaly_repository_client.create_repository
true
else
repo_path = File.join(Gitlab.config.repositories.storages[storage]['path'], relative_path)
Gitlab::Git::Repository.create(repo_path, bare: true, symlink_hooks_to: gitlab_shell_hooks_path)
end
end
rescue => err rescue => err
Rails.logger.error("Failed to add repository #{storage}/#{name}: #{err}") Rails.logger.error("Failed to add repository #{storage}/#{name}: #{err}")
false false
......
...@@ -79,7 +79,7 @@ namespace :gitlab do ...@@ -79,7 +79,7 @@ namespace :gitlab do
if File.exist?(path_to_repo) if File.exist?(path_to_repo)
print '-' print '-'
else else
if Gitlab::Shell.new.add_repository(project.repository_storage_path, if Gitlab::Shell.new.add_repository(project.repository_storage,
project.disk_path) project.disk_path)
print '.' print '.'
else else
......
...@@ -3,15 +3,10 @@ module QA ...@@ -3,15 +3,10 @@ module QA
module Admin module Admin
class Menu < Page::Base class Menu < Page::Base
def go_to_license def go_to_license
within_middle_menu { click_link 'License' } link = find_link 'License'
end # Click space to scroll this link into the view
link.send_keys(:space)
private link.click
def within_middle_menu
page.within('.nav-control') do
yield
end
end end
end end
end end
......
#!/usr/bin/env ruby
require 'yaml'
invalid_changelogs = Dir['changelogs/**/*'].reject do |changelog|
next true if changelog =~ /(archive\.md|unreleased(-ee)?)$/
next false unless changelog.end_with?('.yml')
begin
YAML.load_file(changelog)
rescue
end
end
if invalid_changelogs.any?
puts "Invalid changelogs found!\n"
puts invalid_changelogs.sort
exit 1
else
puts "All changelogs are valid YAML.\n"
exit 0
end
...@@ -13,7 +13,8 @@ tasks = [ ...@@ -13,7 +13,8 @@ tasks = [
%w[yarn run eslint], %w[yarn run eslint],
%w[bundle exec rubocop --require rubocop-rspec], %w[bundle exec rubocop --require rubocop-rspec],
%w[scripts/lint-conflicts.sh], %w[scripts/lint-conflicts.sh],
%w[bundle exec rake gettext:lint] %w[bundle exec rake gettext:lint],
%w[scripts/lint-changelog-yaml]
] ]
failed_tasks = tasks.reduce({}) do |failures, task| failed_tasks = tasks.reduce({}) do |failures, task|
......
...@@ -12,5 +12,19 @@ describe EE::Gitlab::Deltas do ...@@ -12,5 +12,19 @@ describe EE::Gitlab::Deltas do
expect(described_class.delta_size_check(change, project.repository)).to be > 0 expect(described_class.delta_size_check(change, project.repository)).to be > 0
end end
it 'handles annotated tags on an object' do
object_id = 'faaf198af3a36dbf41961466703cc1d47c61d051'
options = { message: 'test tag message\n',
tagger: { name: 'John Smith', email: 'john@gmail.com' } }
result = project.repository.rugged.tags.create('annotated-tag', object_id, options)
change = {
oldrev: result.annotation.oid,
newrev: TestEnv::BRANCH_SHA['master']
}
expect(described_class.delta_size_check(change, project.repository)).to eq(0)
end
end end
end end
...@@ -54,36 +54,9 @@ describe('MergeRequestStore', () => { ...@@ -54,36 +54,9 @@ describe('MergeRequestStore', () => {
}); });
}); });
describe('setCodeclimateHeadMetrics', () => {
it('should set defaults', () => {
expect(store.codeclimate).toEqual(mockData.codeclimate);
expect(store.codeclimateMetrics).toEqual({
headIssues: [],
baseIssues: [],
newIssues: [],
resolvedIssues: [],
});
});
it('should set the provided head metrics', () => {
store.setCodeclimateHeadMetrics(headIssues);
expect(store.codeclimateMetrics.headIssues).toEqual(headIssues);
});
});
describe('setCodeclimateBaseMetrics', () => {
it('should set the provided base metrics', () => {
store.setCodeclimateBaseMetrics(baseIssues);
expect(store.codeclimateMetrics.baseIssues).toEqual(baseIssues);
});
});
describe('compareCodeclimateMetrics', () => { describe('compareCodeclimateMetrics', () => {
beforeEach(() => { beforeEach(() => {
store.setCodeclimateHeadMetrics(headIssues); store.compareCodeclimateMetrics(headIssues, baseIssues);
store.setCodeclimateBaseMetrics(baseIssues);
store.compareCodeclimateMetrics();
}); });
it('should return the new issues', () => { it('should return the new issues', () => {
......
...@@ -451,30 +451,42 @@ describe Gitlab::Shell do ...@@ -451,30 +451,42 @@ describe Gitlab::Shell do
end end
describe '#add_repository' do describe '#add_repository' do
it 'creates a repository' do shared_examples '#add_repository' do
created_path = File.join(TestEnv.repos_path, 'project', 'path.git') let(:repository_storage) { 'default' }
hooks_path = File.join(created_path, 'hooks') let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
let(:repo_name) { 'project/path' }
let(:created_path) { File.join(repository_storage_path, repo_name + '.git') }
begin after do
result = gitlab_shell.add_repository(TestEnv.repos_path, 'project/path')
repo_stat = File.stat(created_path) rescue nil
hooks_stat = File.lstat(hooks_path) rescue nil
hooks_dir = File.realpath(hooks_path)
ensure
FileUtils.rm_rf(created_path) FileUtils.rm_rf(created_path)
end end
expect(result).to be_truthy it 'creates a repository' do
expect(repo_stat.mode & 0o777).to eq(0o770) expect(gitlab_shell.add_repository(repository_storage, repo_name)).to be_truthy
expect(hooks_stat.symlink?).to be_truthy
expect(hooks_dir).to eq(gitlab_shell_hooks_path) expect(File.stat(created_path).mode & 0o777).to eq(0o770)
hooks_path = File.join(created_path, 'hooks')
expect(File.lstat(hooks_path)).to be_symlink
expect(File.realpath(hooks_path)).to eq(gitlab_shell_hooks_path)
end
it 'returns false when the command fails' do
FileUtils.mkdir_p(File.dirname(created_path))
# This file will block the creation of the repo's .git directory. That
# should cause #add_repository to fail.
FileUtils.touch(created_path)
expect(gitlab_shell.add_repository(repository_storage, repo_name)).to be_falsy
end
end end
it 'returns false when the command fails' do context 'with gitlay' do
expect(FileUtils).to receive(:mkdir_p).and_raise(Errno::EEXIST) it_behaves_like '#add_repository'
end
expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be_falsy context 'without gitaly', skip_gitaly_mock: true do
it_behaves_like '#add_repository'
end end
end end
......
...@@ -214,15 +214,12 @@ describe Gitlab::Workhorse do ...@@ -214,15 +214,12 @@ describe Gitlab::Workhorse do
end end
it 'includes a Repository param' do it 'includes a Repository param' do
repo_param = { Repository: { repo_param = {
storage_name: 'default', storage_name: 'default',
relative_path: project.full_path + '.git', relative_path: project.full_path + '.git'
git_object_directory: '', }
git_alternate_object_directories: [],
gl_repository: ''
} }
expect(subject).to include(repo_param) expect(subject[:Repository]).to include(repo_param)
end end
context "when git_upload_pack action is passed" do context "when git_upload_pack action is passed" do
......
...@@ -1484,7 +1484,7 @@ describe Project do ...@@ -1484,7 +1484,7 @@ describe Project do
context 'using a regular repository' do context 'using a regular repository' do
it 'creates the repository' do it 'creates the repository' do
expect(shell).to receive(:add_repository) expect(shell).to receive(:add_repository)
.with(project.repository_storage_path, project.disk_path) .with(project.repository_storage, project.disk_path)
.and_return(true) .and_return(true)
expect(project.repository).to receive(:after_create) expect(project.repository).to receive(:after_create)
...@@ -1494,7 +1494,7 @@ describe Project do ...@@ -1494,7 +1494,7 @@ describe Project do
it 'adds an error if the repository could not be created' do it 'adds an error if the repository could not be created' do
expect(shell).to receive(:add_repository) expect(shell).to receive(:add_repository)
.with(project.repository_storage_path, project.disk_path) .with(project.repository_storage, project.disk_path)
.and_return(false) .and_return(false)
expect(project.repository).not_to receive(:after_create) expect(project.repository).not_to receive(:after_create)
...@@ -1551,7 +1551,7 @@ describe Project do ...@@ -1551,7 +1551,7 @@ describe Project do
.and_return(false) .and_return(false)
expect(shell).to receive(:add_repository) expect(shell).to receive(:add_repository)
.with(project.repository_storage_path, project.disk_path) .with(project.repository_storage, project.disk_path)
.and_return(true) .and_return(true)
project.ensure_repository project.ensure_repository
......
...@@ -156,10 +156,11 @@ describe Projects::CreateService, '#execute' do ...@@ -156,10 +156,11 @@ describe Projects::CreateService, '#execute' do
} }
end end
let(:repository_storage_path) { Gitlab.config.repositories.storages['default']['path'] } let(:repository_storage) { 'default' }
let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
before do before do
gitlab_shell.add_repository(repository_storage_path, "#{user.namespace.full_path}/existing") gitlab_shell.add_repository(repository_storage, "#{user.namespace.full_path}/existing")
end end
after do after do
......
...@@ -76,10 +76,11 @@ describe Projects::ForkService do ...@@ -76,10 +76,11 @@ describe Projects::ForkService do
end end
context 'repository already exists' do context 'repository already exists' do
let(:repository_storage_path) { Gitlab.config.repositories.storages['default']['path'] } let(:repository_storage) { 'default' }
let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
before do before do
gitlab_shell.add_repository(repository_storage_path, "#{@to_user.namespace.full_path}/#{@from_project.path}") gitlab_shell.add_repository(repository_storage, "#{@to_user.namespace.full_path}/#{@from_project.path}")
end end
after do after do
......
...@@ -121,11 +121,14 @@ describe Projects::TransferService do ...@@ -121,11 +121,14 @@ describe Projects::TransferService do
end end
context 'namespace which contains orphan repository with same projects path name' do context 'namespace which contains orphan repository with same projects path name' do
let(:repository_storage_path) { Gitlab.config.repositories.storages['default']['path'] } let(:repository_storage) { 'default' }
let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
before do before do
group.add_owner(user) group.add_owner(user)
gitlab_shell.add_repository(repository_storage_path, "#{group.full_path}/#{project.path}") unless gitlab_shell.add_repository(repository_storage, "#{group.full_path}/#{project.path}")
raise 'failed to add repository'
end
@result = transfer_project(project, user, group) @result = transfer_project(project, user, group)
end end
......
...@@ -150,10 +150,11 @@ describe Projects::UpdateService, '#execute' do ...@@ -150,10 +150,11 @@ describe Projects::UpdateService, '#execute' do
end end
context 'when renaming a project' do context 'when renaming a project' do
let(:repository_storage_path) { Gitlab.config.repositories.storages['default']['path'] } let(:repository_storage) { 'default' }
let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
before do before do
gitlab_shell.add_repository(repository_storage_path, "#{user.namespace.full_path}/existing") gitlab_shell.add_repository(repository_storage, "#{user.namespace.full_path}/existing")
end end
after do after do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment