diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb index d63dd64b728acf5f32c7021548ce634a20479b80..f99aa490d3eafa31af0afe2d27dff1b7ac62bfb2 100644 --- a/app/controllers/import/gitlab_projects_controller.rb +++ b/app/controllers/import/gitlab_projects_controller.rb @@ -3,6 +3,7 @@ class Import::GitlabProjectsController < Import::BaseController def new @namespace_id = project_params[:namespace_id] + @namespace_name = Namespace.find(project_params[:namespace_id]).name @path = project_params[:path] end @@ -23,8 +24,8 @@ class Import::GitlabProjectsController < Import::BaseController ) else redirect_to( - new_project_path, - alert: "Project could not be exported: #{@project.errors.full_messages.join(', ')}" + new_import_gitlab_project_path, + alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}" ) end end @@ -32,7 +33,7 @@ class Import::GitlabProjectsController < Import::BaseController private def file_is_valid? - project_params[:file].respond_to?(:read) + project_params[:file] && project_params[:file].respond_to?(:read) end def verify_gitlab_project_import_enabled diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index affc298e0ca8768a998dfd1ce1f6c4bdeae16d72..af357ae9a717aefc8f52a1905aa9324098b06eac 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -7,7 +7,7 @@ class ProjectsController < Projects::ApplicationController before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists? # Authorize - before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export] + before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export] before_action :event_filter, only: [:show, :activity] layout :determine_layout @@ -186,19 +186,38 @@ class ProjectsController < Projects::ApplicationController end def export - @project.add_export_job(current_user_id: current_user.id) + @project.add_export_job(current_user: current_user) redirect_to( edit_project_path(@project), - notice: "Project export started." + notice: "Project export started. A download link will be sent by e-mail." ) end def download_export + export_project_path = @project.export_project_path + if export_project_path send_file export_project_path, disposition: 'attachment' else - render_404 + redirect_to( + edit_project_path(@project), + alert: "Project export link has expired. Please generate a new export from your project settings." + ) + end + end + + def remove_export + if @project.remove_exports + redirect_to( + edit_project_path(@project), + notice: "Project export has been deleted." + ) + else + redirect_to( + edit_project_path(@project), + alert: "Project export could not be deleted." + ) end end @@ -264,8 +283,4 @@ class ProjectsController < Projects::ApplicationController def get_id project.repository.root_ref end - - def export_project_path - Dir.glob("#{@project.export_path}/*export.tar.gz").max_by {|f| File.ctime(f)} - end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index aeebdf90ba699b883cb0272f76be313d3d7ac0d4..5e5d170a9f30ee4ca1001298832a47fa5881f789 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -348,10 +348,4 @@ module ProjectsHelper message.strip.gsub(Gitlab.config.gitlab_shell.repos_path.chomp('/'), "[REPOS PATH]") end - - def db_export_list - YAML.load_file(Gitlab::ImportExport.config_file)['project_tree'].map do |relation| - relation.is_a?(Hash) ? relation.keys.first.to_s : relation.to_s - end + ['notes', 'merge_request_diffs'] - end end diff --git a/app/models/project.rb b/app/models/project.rb index 4cffb1b7dc1476492a673cef37710c047ea52efe..57bf8aa3eacc80523947e84aa2c22f537e731132 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1100,8 +1100,8 @@ class Project < ActiveRecord::Base @errors = original_errors end - def add_export_job(current_user_id:) - job_id = ProjectExportWorker.perform_async(current_user_id, self.id) + def add_export_job(current_user:) + job_id = ProjectExportWorker.perform_async(current_user.id, self.id) if job_id Rails.logger.info "Export job started for project ID #{self.id} with job ID #{job_id}" @@ -1113,4 +1113,13 @@ class Project < ActiveRecord::Base def export_path File.join(Gitlab::ImportExport.storage_path, path_with_namespace) end + + def export_project_path + Dir.glob("#{export_path}/*export.tar.gz").max_by { |f| File.ctime(f) } + end + + def remove_exports + _, status = Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete)) + status.zero? + end end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index ffac357e91de4d968948fddf02985a2b57658610..55956be28445b5b8da27b54d8b1e809ffecd0250 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -54,7 +54,7 @@ module Projects @project.import_start if @project.import? - after_create_actions if @project.persisted? && !@project.gitlab_project_import? + after_create_actions if @project.persisted? if @project.errors.empty? @project.add_import_job if @project.import? @@ -80,16 +80,18 @@ module Projects def after_create_actions log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"") - @project.create_wiki if @project.wiki_enabled? + unless @project.gitlab_project_import? + @project.create_wiki if @project.wiki_enabled? - @project.build_missing_services + @project.build_missing_services - @project.create_labels + @project.create_labels + end event_service.create_project(@project, current_user) system_hook_service.execute_hooks_for(@project, :create) - unless @project.group + unless @project.group || @project.gitlab_project_import? @project.team << [current_user, :master, current_user] end end diff --git a/app/views/import/gitlab_projects/new.html.haml b/app/views/import/gitlab_projects/new.html.haml index d0ef7a534e6e76fd14de09407cc95e0c47603df4..44e2653ca4affb4c37bba944f977b5d101a97c00 100644 --- a/app/views/import/gitlab_projects/new.html.haml +++ b/app/views/import/gitlab_projects/new.html.haml @@ -2,19 +2,17 @@ - header_title "Projects", root_path %h3.page-title = icon('gitlab') - Import projects from GitLab + Import an exported GitLab project %hr = form_tag import_gitlab_project_path, class: 'form-horizontal', multipart: true do %p - Project will be imported to path + Project will be imported as %strong - #{@path} + #{@namespace_name}/#{@path} %p - To get started add your exported project file below, then you will be redirected to the new project page and the project will appear once the import is done. - %p - You can generate a new export file from your project settings. + To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here. .form-group = hidden_field_tag :namespace_id, @namespace_id = hidden_field_tag :path, @path @@ -24,4 +22,4 @@ = file_field_tag :file, class: '' .form-actions - = submit_tag 'Continue to the next step', class: 'btn btn-create' + = submit_tag 'Import project', class: 'btn btn-create' diff --git a/app/views/notify/project_was_not_exported_email.html.haml b/app/views/notify/project_was_not_exported_email.html.haml index 78d4751b64a9a370c12d78eab970ddd800041085..c9e9ade2cf1364c12462c1b1d93c21d88cd16a0f 100644 --- a/app/views/notify/project_was_not_exported_email.html.haml +++ b/app/views/notify/project_was_not_exported_email.html.haml @@ -3,5 +3,7 @@ %p The errors we encountered were: - %h3{style: "background: black; color: red;"} - #{@errors} + %ul + - @errors.each do |error| + %li + error diff --git a/app/views/notify/project_was_not_exported_email.text.erb b/app/views/notify/project_was_not_exported_email.text.erb index ad730d2162b9d0a77b53586e0fdf1fb992b2137f..a07f6edacf7aa8093f991375a295fbe7169dc1db 100644 --- a/app/views/notify/project_was_not_exported_email.text.erb +++ b/app/views/notify/project_was_not_exported_email.text.erb @@ -2,4 +2,5 @@ Project <%= @project.name %> couldn't be exported. The errors we encountered were: -<%= @errors %> +- @errors.each do |error| +<%= error %> \ No newline at end of file diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 2441e71a5d2854e10b2da02f975f26c17bf44914..a6f982b1d79086fe6d6f9c7411b4b3b52aa03185 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -126,30 +126,35 @@ Export project %p.append-bottom-0 %p - Generates a compressed export file of the project and sends a link to download the export. + Export this project with all its related data in order to move your project to a new GitLab instance. Once the export is finished, you can import the file from the "New Project" page. + %p + Once the exported file is ready, you will receive a notification email with a download link. + .col-lg-9 - = link_to 'Export project', export_namespace_project_path(@project.namespace, @project), + - if @project.export_project_path + = link_to 'Download export', download_export_namespace_project_path(@project.namespace, @project), + method: :get, class: "btn btn-default" + = link_to 'Delete export', remove_export_namespace_project_path(@project.namespace, @project), + method: :post, class: "btn btn-default" + - else + = link_to 'Export project', export_namespace_project_path(@project.namespace, @project), method: :post, class: "btn btn-default" - - %p.append-bottom-0 - %p - .row.prepend-top-default - Clicking on Export project, will produce a compressed file that will be sent as a link to your registered e-mail address. .bs-callout.bs-callout-info %p.append-bottom-0 %p The following items will be exported: %ul - %li Project and wiki repository + %li Project and wiki repositories %li Project uploads - %li DB items, including configuration - %ul - - db_export_list.each do |export_relation| - %li - %code #{export_relation} - + %li Project configuration including web hooks and services + %li Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities + %p + The following items will NOT be exported: + %ul + %li Build traces and artifacts + %li LFS objects %hr - if can? current_user, :archive_project, @project .row.prepend-top-default diff --git a/app/views/projects/imports/show.html.haml b/app/views/projects/imports/show.html.haml index 9e99b81bb6c62a57fa4cb650c0a504d51453ccb2..4d8ee562e6a29565e7c48ffc5bcca779dd69680c 100644 --- a/app/views/projects/imports/show.html.haml +++ b/app/views/projects/imports/show.html.haml @@ -7,7 +7,7 @@ Forking in progress. - else Import in progress. - - unless @project.forked? || @project.gitlab_project_import? + - if @project.external_import? %p.monospace git clone --bare #{@project.safe_import_url} %p Please wait while we import the repository for you. Refresh at will. :javascript diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 79ef92842687d71b6475c4af27149ad9643beef2..50cc7a450396d96751bee184168a085c1c8c6348 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -93,7 +93,7 @@ - if gitlab_project_import_enabled? = link_to new_import_gitlab_project_path, class: 'btn import_gitlab_project project-submit' do %i.fa.fa-gitlab - %span GitLab project + %span GitLab export .js-toggle-content.hide = render "shared/import_form", f: f @@ -124,21 +124,33 @@ e.preventDefault(); var import_modal = $(this).next(".modal").show(); }); + $('.modal-header .close').bind('click', function() { $(".modal").hide(); }); + $('.import_gitlab_project').bind('click', function() { var _href = $("a.import_gitlab_project").attr("href"); $(".import_gitlab_project").attr("href", _href + '?namespace_id=' + $("#project_namespace_id").val() + '&path=' + $("#project_path").val()); }); + $('.import_gitlab_project').attr('disabled',true) $('.import_gitlab_project').attr('title', 'Project path required.'); - $('#project_path').keyup(function(){ - if($(this).val().length !=0) { - $('.import_gitlab_project').attr('disabled', false); - $('.import_gitlab_project').attr('title',''); - } else { - $('.import_gitlab_project').attr('disabled',true); - $('.import_gitlab_project').attr('title', 'Project path required.'); - } - }) + + $('.import_gitlab_project').click(function( event ) { + if($('.import_gitlab_project').attr('disabled')) { + event.preventDefault(); + new Flash("Project path required.", "alert"); + } + }); + + $('#project_path').keyup(function(){ + if($(this).val().length !=0) { + $('.import_gitlab_project').attr('disabled', false); + $('.import_gitlab_project').attr('title',''); + $(".flash-container").html("") + } else { + $('.import_gitlab_project').attr('disabled',true); + $('.import_gitlab_project').attr('title', 'Project path required.'); + } + }) diff --git a/config/routes.rb b/config/routes.rb index 024a0df6e44deb968ee6368899962a2ed73fb4e4..549cf02b067771c23555a324d6146a6f136fa8f3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -455,6 +455,7 @@ Rails.application.routes.draw do post :toggle_star post :markdown_preview post :export + post :remove_export get :download_export get :autocomplete_sources get :activity diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb index e39bdb5084d80441dfe96153b99c13e835fe602d..d209e04f7be5f735113b513e7743fdc0aa70b3ed 100644 --- a/lib/gitlab/import_export/importer.rb +++ b/lib/gitlab/import_export/importer.rb @@ -15,7 +15,7 @@ module Gitlab if check_version! && [project_tree, repo_restorer, wiki_restorer, uploads_restorer].all?(&:restore) project_tree.restored_project else - raise Projects::ImportService::Error.new, @shared.errors.join(', ') + raise Projects::ImportService::Error.new(@shared.errors.join(', ')) end end diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb index ef4d9c24067fa278b526df48ced4b83f3ec7d25b..3c2b801b571e97c5ccadf015cefea851dd7b5e60 100644 --- a/lib/gitlab/import_export/repo_restorer.rb +++ b/lib/gitlab/import_export/repo_restorer.rb @@ -11,7 +11,8 @@ module Gitlab end def restore - return false unless File.exist?(@path_to_bundle) || wiki? + return true if wiki? + return false unless File.exist?(@path_to_bundle) FileUtils.mkdir_p(path_to_repo) diff --git a/lib/gitlab/import_sources.rb b/lib/gitlab/import_sources.rb index 4cae819d356dcd1f6948bdcf455316e073066df6..cf81aced4b0fa7b82773790e69208b63fe71ce28 100644 --- a/lib/gitlab/import_sources.rb +++ b/lib/gitlab/import_sources.rb @@ -21,7 +21,7 @@ module Gitlab 'Google Code' => 'google_code', 'FogBugz' => 'fogbugz', 'Repo by URL' => 'git', - 'GitLab project' => 'gitlab_project' + 'GitLab export' => 'gitlab_export' } end diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index 816bef65acea6a5a623cefe11e10a23104487882..c5fb0fc783be1be6f9f6a463ac64e9b9f8b3dc41 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -25,14 +25,14 @@ feature 'project import', feature: true, js: true do select2('2', from: '#project_namespace_id') fill_in :project_path, with:'test-project-path', visible: true - click_link 'GitLab project' + click_link 'GitLab export' expect(page).to have_content('GitLab project export') expect(URI.parse(current_url).query).to eq('namespace_id=2&path=test-project-path') attach_file('file', file) - click_on 'Continue to the next step' # import starts + click_on 'Import project' # import starts expect(project).not_to be_nil expect(project.issues).not_to be_empty