diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb index 90b4ff8b2ca619120cbae23ec0acc6bb7c1a5907..98a9b5f10189de7ea014b1803db1f01beaffc744 100644 --- a/app/controllers/import/gitlab_projects_controller.rb +++ b/app/controllers/import/gitlab_projects_controller.rb @@ -12,12 +12,10 @@ class Import::GitlabProjectsController < Import::BaseController return redirect_back_or_default(options: { alert: "You need to upload a GitLab project export archive." }) end - @project = Project.create_from_import_job(current_user_id: current_user.id, - tmp_file: File.expand_path(params[:file].path), - namespace_id: project_params[:namespace_id], - project_path: project_params[:path]) - - @project = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute + @project = Gitlab::GitlabImport::ProjectCreator.new(Namespace.find(project_params[:namespace_id]), + current_user, + File.expand_path(params[:file].path), + project_params[:path]).execute flash[:notice] = "The project import has been started." diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 5c657290046ccf0b9e7175cbc05dcdca95b8371d..a1d581443996a64346141046fba063a593b6fe5e 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -190,7 +190,7 @@ class ProjectsController < Projects::ApplicationController redirect_to( edit_project_path(@project), - notice: "Project export successfully started" + notice: "Project export successfully started." ) end diff --git a/app/models/project.rb b/app/models/project.rb index ab7947a088083617fde840c8426999fbf5724f6f..1625e8802205266bd985ccfc9cd4dbe2c06b35f8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -492,6 +492,10 @@ class Project < ActiveRecord::Base Gitlab::UrlSanitizer.new(import_url).masked_url end + def gitlab_project_import? + import_type == 'gitlab_project' + end + def check_limit unless creator.can_create_project? or namespace.kind == 'group' projects_limit = creator.projects_limit diff --git a/app/models/todo.rb b/app/models/todo.rb index b04014632696cc4383291fbc710aa567bfa1a244..3a09137332911565659ba36aff1888d698556b79 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -45,10 +45,6 @@ class Todo < ActiveRecord::Base target_type == "Commit" end - def for_project? - target_type == "Project" - end - # override to return commits, which are not active record def target if for_commit? diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 61cac5419ad00ffa2d370ffc902e8b505e48dd61..7e467541539f8af4e3076c4f47198f832d9c9c67 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -52,9 +52,11 @@ module Projects save_project_and_import_data(import_data) + @project.import_url = download_export_namespace_project_path(@project.namespace, @project) if @project.gitlab_project_import? + @project.import_start if @project.import? - after_create_actions if @project.persisted? + after_create_actions if @project.persisted? && !@project.gitlab_project_import? if @project.errors.empty? @project.add_import_job if @project.import? diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index c4838d31f2f64a50ff7677a316d4aa02ae529a69..b4b4c34b012f0cee86dd9daa41d37148a7647b5a 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -9,7 +9,8 @@ module Projects 'fogbugz', 'gitlab', 'github', - 'google_code' + 'google_code', + 'gitlab_project' ] def execute @@ -37,7 +38,7 @@ module Projects def import_repository begin - gitlab_shell.import_repository(project.path_with_namespace, project.import_url) + gitlab_shell.import_repository(project.path_with_namespace, project.import_url) unless @project.gitlab_project_import? rescue Gitlab::Shell::Error => e raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}" end @@ -58,6 +59,8 @@ module Projects end def importer + return Gitlab::ImportExport::Importer if @project.gitlab_project_import? + class_name = "Gitlab::#{project.import_type.camelize}Import::Importer" class_name.constantize.new(project) end diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 8449fe1e4e0947dcb84b003766da97c274fdcc1f..9a832eceaf55769f5480213d4e042b12afb9d6d7 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -120,6 +120,19 @@ = link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project), method: :post, class: "btn btn-save" %hr + .row.prepend-top-default + .col-lg-3 + %h4.prepend-top-0 + Export project + %p.append-bottom-0 + %p + Generates a compressed export file of the project and sends a link to download the export. + .col-lg-9 + + = link_to 'Generate new export', export_namespace_project_path(@project.namespace, @project), + method: :post, class: "btn btn-default" + + %hr - if can? current_user, :archive_project, @project .row.prepend-top-default .col-lg-3 diff --git a/app/workers/project_import_worker.rb b/app/workers/project_import_worker.rb index b2902c3278e6d1446dfabc989d3ef8a2e8a485a8..b18d453702e14d1d6bf775c86e71bee236095c08 100644 --- a/app/workers/project_import_worker.rb +++ b/app/workers/project_import_worker.rb @@ -7,10 +7,10 @@ class ProjectImportWorker def perform(current_user_id, tmp_file, namespace_id, path) current_user = User.find(current_user_id) - project = Gitlab::ImportExport::ImportService.execute(archive_file: tmp_file, - owner: current_user, - namespace_id: namespace_id, - project_path: path) + project = Gitlab::ImportExport::Importer.execute(archive_file: tmp_file, + owner: current_user, + namespace_id: namespace_id, + project_path: path) if project project.repository.after_import else diff --git a/lib/gitlab/gitlab_import/project_creator.rb b/lib/gitlab/gitlab_import/project_creator.rb index 3d0418261bb340a4b2ad4cc515e36cf543e35a02..72b10f536ec2d4b2dce7d7117f2183772e4876ce 100644 --- a/lib/gitlab/gitlab_import/project_creator.rb +++ b/lib/gitlab/gitlab_import/project_creator.rb @@ -3,24 +3,21 @@ module Gitlab class ProjectCreator attr_reader :repo, :namespace, :current_user, :session_data - def initialize(repo, namespace, current_user, session_data) - @repo = repo - @namespace = namespace + def initialize(namespace_id, current_user, file, project_path) + @namespace_id = namespace_id @current_user = current_user - @session_data = session_data + @file = file + @project_path = project_path end def execute ::Projects::CreateService.new( current_user, - name: repo["name"], - path: repo["path"], - description: repo["description"], - namespace_id: namespace.id, - visibility_level: repo["visibility_level"], - import_type: "gitlab", - import_source: repo["path_with_namespace"], - import_url: repo["http_url_to_repo"].sub("://", "://oauth2:#{@session_data[:gitlab_access_token]}@") + name: @project_path, + path: @project_path, + namespace_id: namespace_id, + import_type: "gitlab_project", + import_source: @file ).execute end end diff --git a/lib/gitlab/import_export/file_importer.rb b/lib/gitlab/import_export/file_importer.rb new file mode 100644 index 0000000000000000000000000000000000000000..0e70d9282d50d1b6228d6e5e2818c9a06befbc9c --- /dev/null +++ b/lib/gitlab/import_export/file_importer.rb @@ -0,0 +1,30 @@ +module Gitlab + module ImportExport + class FileImporter + include Gitlab::ImportExport::CommandLineUtil + + def self.import(*args) + new(*args).import + end + + def initialize(archive_file:, shared:) + @archive_file = archive_file + @shared = shared + end + + def import + FileUtils.mkdir_p(@shared.export_path) + decompress_archive + rescue => e + @shared.error(e) + false + end + + private + + def decompress_archive + untar_zxf(archive: @archive_file, dir: @shared.export_path) + end + end + end +end diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 3796fc8cd0281352bed3b2da9e4264995d9e9a48..164ab6238c44ef74cfd15b5b73dde1a77b58d605 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -30,8 +30,6 @@ project_tree: # Only include the following attributes for the models specified. included_attributes: project: - - :name - - :path - :description - :issues_enabled - :merge_requests_enabled diff --git a/lib/gitlab/import_export/import_service.rb b/lib/gitlab/import_export/import_service.rb deleted file mode 100644 index 95d4fb17eadcf03a679c22f0998c5935c5ff3bca..0000000000000000000000000000000000000000 --- a/lib/gitlab/import_export/import_service.rb +++ /dev/null @@ -1,81 +0,0 @@ -module Gitlab - module ImportExport - class ImportService - - def self.execute(*args) - new(*args).execute - end - - def initialize(archive_file:, owner:, namespace_id:, project_path:) - @archive_file = archive_file - @current_user = owner - @namespace = Namespace.find(namespace_id) - @shared = Gitlab::ImportExport::Shared.new(relative_path: path_with_namespace(project_path), project_path: project_path) - end - - def execute - Gitlab::ImportExport::Importer.import(archive_file: @archive_file, - shared: @shared) - if check_version! && [project_tree, repo_restorer, wiki_restorer, uploads_restorer].all?(&:restore) - project_tree.project - else - project_tree.project.destroy if project_tree.project - nil - end - end - - private - - def check_version! - Gitlab::ImportExport::VersionChecker.check!(shared: @shared) - end - - def project_tree - @project_tree ||= Gitlab::ImportExport::ProjectTreeRestorer.new(user: @current_user, - shared: @shared, - namespace_id: @namespace.id) - end - - def repo_restorer - Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: repo_path, - shared: @shared, - project: project_tree.project) - end - - def wiki_restorer - Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: wiki_repo_path, - shared: @shared, - project: ProjectWiki.new(project_tree.project), - wiki: true) - end - - def uploads_restorer - Gitlab::ImportExport::UploadsRestorer.new(project: project_tree.project, shared: @shared) - end - - def path_with_namespace(project_path) - File.join(@namespace.path, project_path) - end - - def repo_path - File.join(@shared.export_path, 'project.bundle') - end - - def wiki_repo_path - File.join(@shared.export_path, 'project.wiki.bundle') - end - - def attributes_for_todo - { user_id: @current_user.id, - project_id: project_tree.project.id, - target_type: 'Project', - target: project_tree.project, - action: Todo::IMPORTED, - author_id: @current_user.id, - state: :pending, - target_id: project_tree.project.id - } - end - end - end -end diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb index 8020aab3da963c99f6526868f7a6ea1183aeef8c..d096e17bdf01bfaa3271452acd6bfaea1ec3d066 100644 --- a/lib/gitlab/import_export/importer.rb +++ b/lib/gitlab/import_export/importer.rb @@ -1,29 +1,79 @@ module Gitlab module ImportExport class Importer - include Gitlab::ImportExport::CommandLineUtil - def self.import(*args) - new(*args).import + def self.execute(*args) + new(*args).execute end - def initialize(archive_file:, shared:) - @archive_file = archive_file - @shared = shared + def initialize(project) + @archive_file = project.import_source + @current_user = project.creator + @shared = Gitlab::ImportExport::Shared.new(relative_path: path_with_namespace(@project.path)) end - def import - FileUtils.mkdir_p(@shared.export_path) - decompress_archive - rescue => e - @shared.error(e) - false + def execute + Gitlab::ImportExport::FileImporter.import(archive_file: @archive_file, + shared: @shared) + if check_version! && [project_tree, repo_restorer, wiki_restorer, uploads_restorer].all?(&:restore) + project_tree.project + else + project_tree.project.destroy if project_tree.project + nil + end end private - def decompress_archive - untar_zxf(archive: @archive_file, dir: @shared.export_path) + def check_version! + Gitlab::ImportExport::VersionChecker.check!(shared: @shared) + end + + def project_tree + @project_tree ||= Gitlab::ImportExport::ProjectTreeRestorer.new(user: @current_user, + shared: @shared, + project: @project) + end + + def repo_restorer + Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: repo_path, + shared: @shared, + project: project_tree.project) + end + + def wiki_restorer + Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: wiki_repo_path, + shared: @shared, + project: ProjectWiki.new(project_tree.project), + wiki: true) + end + + def uploads_restorer + Gitlab::ImportExport::UploadsRestorer.new(project: project_tree.project, shared: @shared) + end + + def path_with_namespace(project_path) + File.join(@namespace.path, project_path) + end + + def repo_path + File.join(@shared.export_path, 'project.bundle') + end + + def wiki_repo_path + File.join(@shared.export_path, 'project.wiki.bundle') + end + + def attributes_for_todo + { user_id: @current_user.id, + project_id: project_tree.project.id, + target_type: 'Project', + target: project_tree.project, + action: Todo::IMPORTED, + author_id: @current_user.id, + state: :pending, + target_id: project_tree.project.id + } end end end diff --git a/lib/gitlab/import_export/project_factory.rb b/lib/gitlab/import_export/project_factory.rb deleted file mode 100644 index 6cd4736649b6f9e74ec09c529adcdd5d15011770..0000000000000000000000000000000000000000 --- a/lib/gitlab/import_export/project_factory.rb +++ /dev/null @@ -1,41 +0,0 @@ -module Gitlab - module ImportExport - module ProjectFactory - extend self - - def create(project_params:, user:, namespace_id:) - project = Project.new(project_params.except('id')) - project.creator = user - check_namespace(namespace_id, project, user) - end - - def check_namespace(namespace_id, project, user) - if namespace_id - # Find matching namespace and check if it allowed - # for current user if namespace_id passed. - if allowed_namespace?(user, namespace_id) - project.namespace_id = namespace_id - else - project.namespace_id = nil - deny_namespace(project) - end - else - # Set current user namespace if namespace_id is nil - project.namespace_id = user.namespace_id - end - project - end - - private - - def allowed_namespace?(user, namespace_id) - namespace = Namespace.find_by(id: namespace_id) - user.can?(:create_projects, namespace) - end - - def deny_namespace(project) - project.errors.add(:namespace, "is not valid") - end - end - end -end diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index c7c1c376ab7cf8eb7f3187a1da089f4643fbdedd..290b38927aee5d59eb2b99bc6b5281102b469d61 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -2,12 +2,11 @@ module Gitlab module ImportExport class ProjectTreeRestorer - def initialize(user:, shared:, namespace_id:) + def initialize(user:, shared:, project:) @path = File.join(shared.export_path, 'project.json') @user = user - @project_path = shared.opts[:project_path] - @namespace_id = namespace_id @shared = shared + @project = project end def restore @@ -21,7 +20,7 @@ module Gitlab end def project - @project ||= create_project + @restored_project ||= restore_project end private @@ -57,14 +56,10 @@ module Gitlab end end - def create_project + def restore_project project_params = @tree_hash.reject { |_key, value| value.is_a?(Array) } - project = Gitlab::ImportExport::ProjectFactory.create( - project_params: project_params, user: @user, namespace_id: @namespace_id) - project.path = @project_path - project.name = @project_path - project.save! - project + @project.update(project_params) + @project end # Given a relation hash containing one or more models and its relationships,