Commit 22a7853d authored by James Fargher's avatar James Fargher

Merge branch 'jh-group_import_status' into 'master'

Display import status page after Group import

See merge request gitlab-org/gitlab!31731
parents 1d375778 12f8a859
...@@ -49,6 +49,12 @@ ...@@ -49,6 +49,12 @@
} }
} }
.save-group-loader {
margin-top: $gl-padding-50;
margin-bottom: $gl-padding-50;
color: $gl-gray-700;
}
.group-nav-container .nav-controls { .group-nav-container .nav-controls {
.group-filter-form { .group-filter-form {
flex: 1 1 auto; flex: 1 1 auto;
......
# frozen_string_literal: true
class Groups::ImportsController < Groups::ApplicationController
include ContinueParams
def show
if @group.import_state.nil? || @group.import_state.finished?
if continue_params[:to]
redirect_to continue_params[:to], notice: continue_params[:notice]
else
redirect_to group_path(@group), notice: s_('GroupImport|The group was successfully imported.')
end
elsif @group.import_state.failed?
redirect_to new_group_path(@group), alert: s_('GroupImport|Failed to import group.')
else
flash.now[:notice] = continue_params[:notice_now]
end
end
end
...@@ -74,8 +74,12 @@ class GroupsController < Groups::ApplicationController ...@@ -74,8 +74,12 @@ class GroupsController < Groups::ApplicationController
def show def show
respond_to do |format| respond_to do |format|
format.html do format.html do
if @group.import_state&.in_progress?
redirect_to group_import_path(@group)
else
render_show_html render_show_html
end end
end
format.atom do format.atom do
render_details_view_atom render_details_view_atom
......
...@@ -8,7 +8,7 @@ class Import::GitlabGroupsController < ApplicationController ...@@ -8,7 +8,7 @@ class Import::GitlabGroupsController < ApplicationController
def create def create
unless file_is_valid?(group_params[:file]) unless file_is_valid?(group_params[:file])
return redirect_back_or_default(options: { alert: _('Unable to process group import file') }) return redirect_back_or_default(options: { alert: s_('GroupImport|Unable to process group import file') })
end end
group_data = group_params.except(:file).merge( group_data = group_params.except(:file).merge(
...@@ -19,15 +19,17 @@ class Import::GitlabGroupsController < ApplicationController ...@@ -19,15 +19,17 @@ class Import::GitlabGroupsController < ApplicationController
group = ::Groups::CreateService.new(current_user, group_data).execute group = ::Groups::CreateService.new(current_user, group_data).execute
if group.persisted? if group.persisted?
Groups::ImportExport::ImportService.new(group: group, user: current_user).async_execute if Groups::ImportExport::ImportService.new(group: group, user: current_user).async_execute
redirect_to( redirect_to(
group_path(group), group_path(group),
notice: _("Group '%{group_name}' is being imported.") % { group_name: group.name } notice: s_("GroupImport|Group '%{group_name}' is being imported.") % { group_name: group.name }
) )
else
redirect_to group_path(group), alert: _("Group import could not be scheduled")
end
else else
redirect_back_or_default( redirect_back_or_default(
options: { alert: _("Group could not be imported: %{errors}") % { errors: group.errors.full_messages.to_sentence } } options: { alert: s_("GroupImport|Group could not be imported: %{errors}") % { errors: group.errors.full_messages.to_sentence } }
) )
end end
end end
......
...@@ -32,4 +32,8 @@ class GroupImportState < ApplicationRecord ...@@ -32,4 +32,8 @@ class GroupImportState < ApplicationRecord
state.update_column(:last_error, last_error) if last_error state.update_column(:last_error, last_error) if last_error
end end
end end
def in_progress?
created? || started?
end
end end
...@@ -13,7 +13,16 @@ module Groups ...@@ -13,7 +13,16 @@ module Groups
end end
def async_execute def async_execute
GroupImportWorker.perform_async(current_user.id, group.id) group_import_state = GroupImportState.safe_find_or_create_by!(group: group)
jid = GroupImportWorker.perform_async(current_user.id, group.id)
if jid.present?
group_import_state.update!(jid: jid)
else
group_import_state.fail_op('Failed to schedule import job')
false
end
end end
def execute def execute
......
- page_title _('Import in progress')
- @content_class = "limit-container-width" unless fluid_layout
.save-group-loader
.center
%h2
%i.loading.spinner.spinner-sm
= page_title
%p
= s_('GroupImport|Please wait while we import the group for you. Refresh at will.')
...@@ -9,15 +9,16 @@ class GroupImportWorker # rubocop:disable Scalability/IdempotentWorker ...@@ -9,15 +9,16 @@ class GroupImportWorker # rubocop:disable Scalability/IdempotentWorker
def perform(user_id, group_id) def perform(user_id, group_id)
current_user = User.find(user_id) current_user = User.find(user_id)
group = Group.find(group_id) group = Group.find(group_id)
group_import = group.build_import_state(jid: self.jid) group_import_state = group.import_state || group.build_import_state
group_import.start! group_import_state.jid = self.jid
group_import_state.start!
::Groups::ImportExport::ImportService.new(group: group, user: current_user).execute ::Groups::ImportExport::ImportService.new(group: group, user: current_user).execute
group_import.finish! group_import_state.finish!
rescue StandardError => e rescue StandardError => e
group_import&.fail_op(e.message) group_import_state&.fail_op(e.message)
raise e raise e
end end
......
---
title: Show import in progress screen for group imports
merge_request: 31731
author:
type: added
...@@ -70,6 +70,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do ...@@ -70,6 +70,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
end end
resource :avatar, only: [:destroy] resource :avatar, only: [:destroy]
resource :import, only: [:show]
concerns :clusterable concerns :clusterable
......
...@@ -10928,9 +10928,6 @@ msgstr "" ...@@ -10928,9 +10928,6 @@ msgstr ""
msgid "Group %{group_name} was successfully created." msgid "Group %{group_name} was successfully created."
msgstr "" msgstr ""
msgid "Group '%{group_name}' is being imported."
msgstr ""
msgid "Group Audit Events" msgid "Group Audit Events"
msgstr "" msgstr ""
...@@ -10967,9 +10964,6 @@ msgstr "" ...@@ -10967,9 +10964,6 @@ msgstr ""
msgid "Group by:" msgid "Group by:"
msgstr "" msgstr ""
msgid "Group could not be imported: %{errors}"
msgstr ""
msgid "Group description" msgid "Group description"
msgstr "" msgstr ""
...@@ -10997,6 +10991,9 @@ msgstr "" ...@@ -10997,6 +10991,9 @@ msgstr ""
msgid "Group has not been marked for deletion" msgid "Group has not been marked for deletion"
msgstr "" msgstr ""
msgid "Group import could not be scheduled"
msgstr ""
msgid "Group info:" msgid "Group info:"
msgstr "" msgstr ""
...@@ -11063,6 +11060,24 @@ msgstr "" ...@@ -11063,6 +11060,24 @@ msgstr ""
msgid "GroupActivyMetrics|Recent activity (last 90 days)" msgid "GroupActivyMetrics|Recent activity (last 90 days)"
msgstr "" msgstr ""
msgid "GroupImport|Failed to import group."
msgstr ""
msgid "GroupImport|Group '%{group_name}' is being imported."
msgstr ""
msgid "GroupImport|Group could not be imported: %{errors}"
msgstr ""
msgid "GroupImport|Please wait while we import the group for you. Refresh at will."
msgstr ""
msgid "GroupImport|The group was successfully imported."
msgstr ""
msgid "GroupImport|Unable to process group import file"
msgstr ""
msgid "GroupRoadmap|%{dateWord} – No end date" msgid "GroupRoadmap|%{dateWord} – No end date"
msgstr "" msgstr ""
...@@ -23870,9 +23885,6 @@ msgstr "" ...@@ -23870,9 +23885,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page." msgid "Unable to load the merge request widget. Try reloading the page."
msgstr "" msgstr ""
msgid "Unable to process group import file"
msgstr ""
msgid "Unable to resolve" msgid "Unable to resolve"
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
describe Groups::ImportsController do
describe 'GET #show' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
context 'when the user has permission to view the group' do
before do
sign_in(user)
group.add_maintainer(user)
end
context 'when the import is in progress' do
before do
create(:group_import_state, group: group)
end
it 'renders the show template' do
get :show, params: { group_id: group }
expect(response).to render_template :show
end
it 'sets the flash notice' do
get :show, params: { group_id: group, continue: { to: '/', notice_now: 'In progress' } }
expect(flash.now[:notice]).to eq 'In progress'
end
end
context 'when the import has failed' do
before do
create(:group_import_state, :failed, group: group)
end
it 'redirects to the new group path' do
get :show, params: { group_id: group }
expect(response).to redirect_to new_group_path(group)
end
it 'sets a flash error' do
get :show, params: { group_id: group }
expect(flash[:alert]).to eq 'Failed to import group.'
end
end
context 'when the import has finished' do
before do
create(:group_import_state, :finished, group: group)
end
it 'redirects to the group page' do
get :show, params: { group_id: group }
expect(response).to redirect_to group_path(group)
end
end
context 'when there is no import state' do
it 'redirects to the group page' do
get :show, params: { group_id: group }
expect(response).to redirect_to group_path(group)
end
end
end
context 'when the user does not have permission to view the group' do
before do
sign_in(user)
end
it 'returns a 404' do
get :show, params: { group_id: group }
expect(response).to have_gitlab_http_status :not_found
end
end
end
end
...@@ -66,9 +66,21 @@ RSpec.describe GroupsController do ...@@ -66,9 +66,21 @@ RSpec.describe GroupsController do
subject { get :show, params: { id: group.to_param }, format: format } subject { get :show, params: { id: group.to_param }, format: format }
context 'when the group is not importing' do
it_behaves_like 'details view' it_behaves_like 'details view'
end end
context 'when the group is importing' do
before do
create(:group_import_state, group: group)
end
it 'redirects to the import status page' do
expect(subject).to redirect_to group_import_path(group)
end
end
end
describe 'GET #details' do describe 'GET #details' do
before do before do
sign_in(user) sign_in(user)
......
...@@ -35,4 +35,38 @@ describe GroupImportState do ...@@ -35,4 +35,38 @@ describe GroupImportState do
expect(import_state).to be_valid expect(import_state).to be_valid
end end
end end
describe '#in_progress?' do
context "when the import is 'created'" do
it "returns true" do
group_import_state = build(:group_import_state, :created)
expect(group_import_state.in_progress?).to eq true
end
end
context "when the import is 'started'" do
it "returns true" do
group_import_state = build(:group_import_state, :started)
expect(group_import_state.in_progress?).to eq true
end
end
context "when the import is 'finished'" do
it "returns false" do
group_import_state = build(:group_import_state, :finished)
expect(group_import_state.in_progress?).to eq false
end
end
context "when the import is 'failed'" do
it "returns false" do
group_import_state = build(:group_import_state, :failed)
expect(group_import_state.in_progress?).to eq false
end
end
end
end end
...@@ -16,6 +16,12 @@ describe Groups::ImportExport::ImportService do ...@@ -16,6 +16,12 @@ describe Groups::ImportExport::ImportService do
import_service.async_execute import_service.async_execute
end end
it 'marks the group import as in progress' do
import_service.async_execute
expect(group.import_state.in_progress?).to eq true
end
it 'returns truthy' do it 'returns truthy' do
expect(import_service.async_execute).to be_truthy expect(import_service.async_execute).to be_truthy
end end
...@@ -31,6 +37,10 @@ describe Groups::ImportExport::ImportService do ...@@ -31,6 +37,10 @@ describe Groups::ImportExport::ImportService do
it 'returns falsey' do it 'returns falsey' do
expect(import_service.async_execute).to be_falsey expect(import_service.async_execute).to be_falsey
end end
it 'does not mark the group import as created' do
expect { import_service.async_execute }.not_to change { group.import_state }
end
end end
end end
......
...@@ -26,7 +26,7 @@ describe GroupImportWorker do ...@@ -26,7 +26,7 @@ describe GroupImportWorker do
subject.perform(user.id, group.id) subject.perform(user.id, group.id)
end end
context 'import state' do context 'when the import state does not exist' do
it 'creates group import' do it 'creates group import' do
expect(group.import_state).to be_nil expect(group.import_state).to be_nil
...@@ -54,6 +54,17 @@ describe GroupImportWorker do ...@@ -54,6 +54,17 @@ describe GroupImportWorker do
subject.perform(user.id, group.id) subject.perform(user.id, group.id)
end end
end end
context 'when the import state already exists' do
it 'updates the existing state' do
existing_state = create(:group_import_state, group: group)
expect { subject.perform(user.id, group.id) }
.not_to change { GroupImportState.count }
expect(existing_state.reload).to be_finished
end
end
end end
context 'when it fails' do context 'when it fails' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment