diff --git a/app/models/project.rb b/app/models/project.rb index 3e5c912e0b47a22cc5489b9cbfb1dd53da5095e9..9bd271eddc91d0ed9663f97f8702116012355152 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -246,6 +246,18 @@ class Project < ActiveRecord::Base gitlab_ci_service && gitlab_ci_service.active end + def path_with_namespace + if namespace + namespace.path + '/' + path + else + path + end + end + + def namespace? + ! namespace.nil? + end + # For compatibility with old code def code path diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index b7a64394ad0ecf6b3284317e24d522e2a41d4d2e..3e83744218343f6ad8c11ee0d0b9f9c44cfc2e3d 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -55,6 +55,12 @@ namespace :gitlab do # Restore backup of GitLab system desc "GITLAB | Restore a previously created backup" task :restore => :environment do + + if Process.uid != 0 + puts "Please run the restore as root user".red + exit 1 + end + Dir.chdir(Gitlab.config.backup.path) # check for existing backups in the backup dir @@ -114,40 +120,112 @@ namespace :gitlab do task :create => :environment do backup_path_repo = File.join(Gitlab.config.backup.path, "repositories") FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) + + # Gitlab repositories puts "Dumping repositories:" - project = Project.all.map { |n| [n.path, n.path_to_repo] } - project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] - project.each do |project| - print "- Dumping repository #{project.first}... " - if Kernel.system("cd #{project.second} > /dev/null 2>&1 && git bundle create #{backup_path_repo}/#{project.first}.bundle --all > /dev/null 2>&1") - puts "[DONE]".green + Project.all.each do |project| + print "- Dumping repository '#{project.path_with_namespace}.git'... " + unless project.empty_repo? + + namespace = project.namespace? ? project.namespace.path : "/" + path_to_bundle = File.join(backup_path_repo, project.path_with_namespace + ".bundle") + FileUtils.mkdir_p(File.join(backup_path_repo, namespace)) + + if Kernel.system("cd #{project.path_to_repo} > /dev/null 2>&1 && git bundle create #{path_to_bundle} --all > /dev/null 2>&1") + puts "[DONE]".green + else + puts "[FAILED]".red + end + else - puts "[FAILED]".red + puts "[SKIPPING]".yellow end end - end + + # Non gitlab managed repositories + [ "gitolite-admin.git", "testing.git" ].each do |repository| + path_to_repo = File.join(Gitlab.config.git_base_path, repository) + path_to_bundle = File.join(backup_path_repo, repository + ".bundle") + + print "- Dumping repository '#{repository}'... " + if Grit::Repo.new(path_to_repo).head_count == 0 + puts "[SKIPPING]".yellow + else + if Kernel.system("cd #{path_to_repo} > /dev/null 2>&1 && git bundle create #{path_to_bundle} --all > /dev/null 2>&1") + puts "[DONE]".green + else + puts "[FAILED]".red + end + end + end + end # create task :restore => :environment do - backup_path_repo = File.join(Gitlab.config.backup.path, "repositories") + backup_path_repo = File.join(Gitlab.config.backup.path, "repositories") + repos_in_backup = Dir.chdir(backup_path_repo) && Dir.glob("{*.bundle,*/*.bundle}") + permission_commands = [ + "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}", + "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}", + "sudo -u git -Hi /home/git/bin/gitolite compile" # recreates gitolite access files in repositories + ] + + # Gitlab repositories puts "Restoring repositories:" - project = Project.all.map { |n| [n.path, n.path_to_repo] } - project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] - project.each do |project| - print "- Restoring repository #{project.first}... " - FileUtils.rm_rf(project.second) if File.dirname(project.second) # delete old stuff - if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1") - permission_commands = [ - "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}", - "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}" - ] - permission_commands.each { |command| Kernel.system(command) } - puts "[DONE]".green + Project.all.each do |project| + + print "- Restoring repository '#{project.path_with_namespace}.git'... " + FileUtils.rm_rf(project.path_to_repo) if File.dirname(project.path_to_repo) + + if repos_in_backup.include?(project.path_with_namespace + ".bundle") # true: we can restore the repo from backup + + namespace = project.namespace? ? project.namespace.path : "/" + path_to_bundle = File.join(backup_path_repo, project.path_with_namespace + ".bundle") + path_to_repo_base = File.join(Gitlab.config.git_base_path, namespace) + + FileUtils.mkdir_p(project.path_to_repo) until Dir.exists?(path_to_repo_base) + + if Kernel.system("git clone --bare #{path_to_bundle} #{project.path_to_repo} > /dev/null 2>&1") + puts "[DONE]".green + else + puts "[FAILED]".red + end + + else # false: need to create a new empty repo + if Grit::Repo.init_bare(project.path_to_repo) + puts "[DONE]".green + else + puts "[FAILED]".red + end + end + end # |project| + + # Non gitlab managed repositories + [ "gitolite-admin.git", "testing.git" ].each do |repository| + path_to_bundle = File.join(backup_path_repo, repository + ".bundle") + path_to_restore_point = File.join(Gitlab.config.git_base_path, repository) + + print "- Restoring repository '#{repository}'... " + FileUtils.rm_rf(path_to_restore_point) if File.dirname(path_to_restore_point) + + if File.exists?(path_to_bundle) + if Kernel.system("git clone --bare #{path_to_bundle} #{path_to_restore_point} > /dev/null 2>&1") + puts "[DONE]".green + else + puts "[FAILED]".red + end else - puts "[FAILED]".red + if Grit::Repo.init_bare(path_to_restore_point) + puts "[DONE]".green + else + puts "[FAILED]".red + end end end - end - end + + # Fixing repository permissions + permission_commands.each { |command| Kernel.system(command) } + end # restore + end # repo ###################################### DB ###################################### diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 83a769760987b719e10892723c78ae797bed01d0..776f6374c7c6e6389b45e5498bc2f9bc3ff0c482 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -86,6 +86,7 @@ describe Project do it { should respond_to(:path_to_repo) } it { should respond_to(:valid_repo?) } it { should respond_to(:repo_exists?) } + it { should respond_to(:namespace?) } # Repository Role it { should respond_to(:tree) } @@ -161,6 +162,19 @@ describe Project do project.web_url.should == "#{Gitlab.config.gitlab.url}/somewhere" end + describe :namespace? do + let(:project) { create(:project) } + + it "should return true" do + project.namespace = Namespace.new(path: "some_namespace") + project.namespace?.should be_true + end + + it "should return false" do + project.namespace?.should be_false + end + end + describe "last_activity methods" do let(:project) { create(:project) } let(:last_event) { double(created_at: Time.now) }