From 5fc871381ad0768bb38879ab1621e538ca3008d0 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Mon, 14 Aug 2017 12:29:47 +0100 Subject: Speed up project creation by inlining repository creation --- .gitlab-ci.yml | 1 - lib/gitlab/git/repository.rb | 22 ++++++++++++++++++++++ lib/gitlab/shell.rb | 12 +++++++++--- spec/lib/gitlab/shell_spec.rb | 35 ++++++++++++++++++++++++----------- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cd19b6f47ff..4fcf51fb86e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -474,7 +474,6 @@ db:rollback-mysql: variables: SIZE: "1" SETUP_DB: "false" - RAILS_ENV: "development" script: - git clone https://gitlab.com/gitlab-org/gitlab-test.git /home/git/repositories/gitlab-org/gitlab-test.git diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 38772d06dbd..1d5ca68137a 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -18,6 +18,28 @@ module Gitlab InvalidBlobName = Class.new(StandardError) InvalidRef = Class.new(StandardError) + class << self + # Unlike `new`, `create` takes the storage path, not the storage name + def create(storage_path, name, 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) + + # Equivalent to `git --git-path=#{repo_path} init [--bare]` + repo = Rugged::Repository.init_at(repo_path, bare) + repo.close + + if symlink_hooks_to.present? + hooks_path = File.join(repo_path, 'hooks') + FileUtils.rm_rf(hooks_path) + FileUtils.ln_s(symlink_hooks_to, hooks_path) + end + + true + end + end + # Full path to repo attr_reader :path diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index 0cb28732402..280a9abf03e 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -73,8 +73,10 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 def add_repository(storage, name) - gitlab_shell_fast_execute([gitlab_shell_projects_path, - 'add-project', storage, "#{name}.git"]) + Gitlab::Git::Repository.create(storage, name, bare: true, symlink_hooks_to: gitlab_shell_hooks_path) + rescue => err + Rails.logger.error("Failed to add repository #{storage}/#{name}: #{err}") + false end # Import repository @@ -273,7 +275,11 @@ module Gitlab protected def gitlab_shell_path - Gitlab.config.gitlab_shell.path + File.expand_path(Gitlab.config.gitlab_shell.path) + end + + def gitlab_shell_hooks_path + File.expand_path(Gitlab.config.gitlab_shell.hooks_path) end def gitlab_shell_user_home diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index 2345874cf10..cfadee0bcf5 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -94,28 +94,41 @@ describe Gitlab::Shell do end describe 'projects commands' do - let(:projects_path) { 'tmp/tests/shell-projects-test/bin/gitlab-projects' } + let(:gitlab_shell_path) { File.expand_path('tmp/tests/gitlab-shell') } + let(:projects_path) { File.join(gitlab_shell_path, 'bin/gitlab-projects') } + let(:gitlab_shell_hooks_path) { File.join(gitlab_shell_path, 'hooks') } before do - allow(Gitlab.config.gitlab_shell).to receive(:path).and_return('tmp/tests/shell-projects-test') + allow(Gitlab.config.gitlab_shell).to receive(:path).and_return(gitlab_shell_path) + allow(Gitlab.config.gitlab_shell).to receive(:hooks_path).and_return(gitlab_shell_hooks_path) allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800) end describe '#add_repository' do - it 'returns true when the command succeeds' do - expect(Gitlab::Popen).to receive(:popen) - .with([projects_path, 'add-project', 'current/storage', 'project/path.git'], - nil, popen_vars).and_return([nil, 0]) + it 'creates a repository' do + created_path = File.join(TestEnv.repos_path, 'project', 'path.git') + hooks_path = File.join(created_path, 'hooks') + + begin + 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) + end - expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be true + expect(result).to be_truthy + expect(repo_stat.mode & 0o777).to eq(0o770) + expect(hooks_stat.symlink?).to be_truthy + expect(hooks_dir).to eq(gitlab_shell_hooks_path) end it 'returns false when the command fails' do - expect(Gitlab::Popen).to receive(:popen) - .with([projects_path, 'add-project', 'current/storage', 'project/path.git'], - nil, popen_vars).and_return(["error", 1]) + expect(FileUtils).to receive(:mkdir_p).and_raise(Errno::EEXIST) - expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be false + expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be_falsy end end -- cgit v1.2.1