summaryrefslogtreecommitdiff
path: root/lib/gitlab_projects.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab_projects.rb')
-rw-r--r--lib/gitlab_projects.rb108
1 files changed, 78 insertions, 30 deletions
diff --git a/lib/gitlab_projects.rb b/lib/gitlab_projects.rb
index bea5686..82ae519 100644
--- a/lib/gitlab_projects.rb
+++ b/lib/gitlab_projects.rb
@@ -1,10 +1,12 @@
-require 'open3'
require 'fileutils'
+require 'timeout'
require_relative 'gitlab_config'
require_relative 'gitlab_logger'
class GitlabProjects
+ GLOBAL_HOOKS_DIRECTORY = File.join(ROOT_PATH, 'hooks')
+
# Project name is a directory name for repository with .git at the end
# It may be namespaced or not. Like repo.git or gitlab/repo.git
attr_reader :project_name
@@ -17,11 +19,19 @@ class GitlabProjects
# Ex /home/git/repositories/test.git
attr_reader :full_path
+ def self.create_hooks(path)
+ local_hooks_directory = File.join(path, 'hooks')
+ unless File.realpath(local_hooks_directory) == File.realpath(GLOBAL_HOOKS_DIRECTORY)
+ FileUtils.mv(local_hooks_directory, "#{local_hooks_directory}.old.#{Time.now.to_i}")
+ FileUtils.ln_s(GLOBAL_HOOKS_DIRECTORY, local_hooks_directory)
+ end
+ end
+
def initialize
@command = ARGV.shift
@project_name = ARGV.shift
@repos_path = GitlabConfig.new.repos_path
- @full_path = File.join(@repos_path, @project_name)
+ @full_path = File.join(@repos_path, @project_name) unless @project_name.nil?
end
def exec
@@ -31,6 +41,7 @@ class GitlabProjects
when 'create-tag'; create_tag
when 'rm-tag'; rm_tag
when 'add-project'; add_project
+ when 'list-projects'; puts list_projects
when 'rm-project'; rm_project
when 'mv-project'; mv_project
when 'import-project'; import_project
@@ -48,38 +59,46 @@ class GitlabProjects
def create_branch
branch_name = ARGV.shift
ref = ARGV.shift || "HEAD"
- cmd = "cd #{full_path} && git branch #{branch_name} #{ref}"
- system(cmd)
+ cmd = %W(git --git-dir=#{full_path} branch -- #{branch_name} #{ref})
+ system(*cmd)
end
def rm_branch
branch_name = ARGV.shift
- cmd = "cd #{full_path} && git branch -D #{branch_name}"
- system(cmd)
+ cmd = %W(git --git-dir=#{full_path} branch -D #{branch_name})
+ system(*cmd)
end
def create_tag
tag_name = ARGV.shift
ref = ARGV.shift || "HEAD"
- cmd = "cd #{full_path} && git tag #{tag_name} #{ref}"
- system(cmd)
+ cmd = %W(git --git-dir=#{full_path} tag)
+ if ARGV.size > 0
+ msg = ARGV.shift
+ cmd += %W(-a -m #{msg})
+ end
+ cmd += %W(-- #{tag_name} #{ref})
+ system(*cmd)
end
def rm_tag
tag_name = ARGV.shift
- cmd = "cd #{full_path} && git tag -d #{tag_name}"
- system(cmd)
+ cmd = %W(git --git-dir=#{full_path} tag -d #{tag_name})
+ system(*cmd)
end
def add_project
$logger.info "Adding project #{@project_name} at <#{full_path}>."
FileUtils.mkdir_p(full_path, mode: 0770)
- cmd = "cd #{full_path} && git init --bare && #{create_hooks_cmd}"
- system(cmd)
+ cmd = %W(git --git-dir=#{full_path} init --bare)
+ system(*cmd) && self.class.create_hooks(full_path)
end
- def create_hooks_cmd
- create_hooks_to(full_path)
+ def list_projects
+ $logger.info 'Listing projects'
+ Dir.chdir(repos_path) do
+ next Dir.glob('**/*.git')
+ end
end
def rm_project
@@ -87,13 +106,53 @@ class GitlabProjects
FileUtils.rm_rf(full_path)
end
+ def mask_password_in_url(url)
+ result = URI(url)
+ result.password = "*****" unless result.password.nil?
+ result
+ rescue
+ url
+ end
+
+ def remove_origin_in_repo
+ cmd = %W(git --git-dir=#{full_path} remote rm origin)
+ pid = Process.spawn(*cmd)
+ Process.wait(pid)
+ end
+
# Import project via git clone --bare
# URL must be publicly cloneable
def import_project
+ # Skip import if repo already exists
+ return false if File.exists?(full_path)
+
@source = ARGV.shift
- $logger.info "Importing project #{@project_name} from <#{@source}> to <#{full_path}>."
- cmd = "cd #{repos_path} && git clone --bare #{@source} #{project_name} && #{create_hooks_cmd}"
- system(cmd)
+ masked_source = mask_password_in_url(@source)
+
+ # timeout for clone
+ timeout = (ARGV.shift || 120).to_i
+ $logger.info "Importing project #{@project_name} from <#{masked_source}> to <#{full_path}>."
+ cmd = %W(git clone --bare -- #{@source} #{full_path})
+
+ pid = Process.spawn(*cmd)
+
+ begin
+ Timeout.timeout(timeout) do
+ Process.wait(pid)
+ end
+ rescue Timeout::Error
+ $logger.error "Importing project #{@project_name} from <#{masked_source}> failed due to timeout."
+
+ Process.kill('KILL', pid)
+ Process.wait
+ FileUtils.rm_rf(full_path)
+ false
+ else
+ self.class.create_hooks(full_path)
+ # The project was imported successfully.
+ # Remove the origin URL since it may contain password.
+ remove_origin_in_repo
+ end
end
# Move repository from one directory to another
@@ -154,8 +213,8 @@ class GitlabProjects
end
$logger.info "Forking project from <#{full_path}> to <#{full_destination_path}>."
- cmd = "cd #{namespaced_path} && git clone --bare #{full_path} && #{create_hooks_to(full_destination_path)}"
- system(cmd)
+ cmd = %W(git clone --bare -- #{full_path} #{full_destination_path})
+ system(*cmd) && self.class.create_hooks(full_destination_path)
end
def update_head
@@ -166,11 +225,6 @@ class GitlabProjects
return false
end
- unless File.exists?(File.join(full_path, 'refs/heads', new_head))
- $logger.error "update-head failed: specified branch does not exist in ref/heads."
- return false
- end
-
File.open(File.join(full_path, 'HEAD'), 'w') do |f|
f.write("ref: refs/heads/#{new_head}")
end
@@ -178,10 +232,4 @@ class GitlabProjects
$logger.info "Update head in project #{project_name} to <#{new_head}>."
true
end
-
- private
-
- def create_hooks_to(dest_path)
- "ln -s #{File.join(ROOT_PATH, 'hooks', 'update')} #{dest_path}/hooks/update"
- end
end