Commit 33feba76 authored by James Lopez's avatar James Lopez

Merge branch 'georgekoltsov/group-import-show-available-groups' into 'master'

Add listing of top level groups to BulkImportsController

See merge request gitlab-org/gitlab!43155
parents c1637245 13c9a452
......@@ -6,6 +6,8 @@ class Import::BulkImportsController < ApplicationController
feature_category :importers
rescue_from Gitlab::BulkImport::Client::ConnectionError, with: :bulk_import_connection_error
def configure
session[access_token_key] = params[access_token_key]&.strip
session[url_key] = params[url_key]
......@@ -13,8 +15,37 @@ class Import::BulkImportsController < ApplicationController
redirect_to status_import_bulk_import_url
end
def status
respond_to do |format|
format.json do
render json: { importable_data: serialized_importable_data }
end
format.html
end
end
private
def serialized_importable_data
serializer.represent(importable_data, {}, Import::BulkImportEntity)
end
def serializer
@serializer ||= BaseSerializer.new(current_user: current_user)
end
def importable_data
client.get('groups', top_level_only: true)
end
def client
@client ||= Gitlab::BulkImport::Client.new(
uri: session[url_key],
token: session[access_token_key]
)
end
def import_params
params.permit(access_token_key, url_key)
end
......@@ -41,8 +72,7 @@ class Import::BulkImportsController < ApplicationController
}
)
rescue Gitlab::UrlBlocker::BlockedUrlError => e
session[access_token_key] = nil
session[url_key] = nil
clear_session_data
redirect_to new_group_path, alert: _('Specified URL cannot be used: "%{reason}"') % { reason: e.message }
end
......@@ -50,4 +80,30 @@ class Import::BulkImportsController < ApplicationController
def allow_local_requests?
Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
end
def bulk_import_connection_error(error)
clear_session_data
error_message = _("Unable to connect to server: %{error}") % { error: error }
flash[:alert] = error_message
respond_to do |format|
format.json do
render json: {
error: {
message: error_message,
redirect: new_group_path
}
}, status: :unprocessable_entity
end
format.html do
redirect_to new_group_path
end
end
end
def clear_session_data
session[url_key] = nil
session[access_token_key] = nil
end
end
# frozen_string_literal: true
class Import::BulkImportEntity < Grape::Entity
expose :id do |entity|
entity['id']
end
expose :full_name do |entity|
entity['full_name']
end
expose :full_path do |entity|
entity['full_path']
end
end
# frozen_string_literal: true
module Gitlab
module BulkImport
class Client
API_VERSION = 'v4'.freeze
DEFAULT_PAGE = 1.freeze
DEFAULT_PER_PAGE = 30.freeze
ConnectionError = Class.new(StandardError)
def initialize(uri:, token:, page: DEFAULT_PAGE, per_page: DEFAULT_PER_PAGE, api_version: API_VERSION)
@uri = URI.parse(uri)
@token = token&.strip
@page = page
@per_page = per_page
@api_version = api_version
end
def get(resource, query = {})
response = with_error_handling do
Gitlab::HTTP.get(
resource_url(resource),
headers: request_headers,
follow_redirects: false,
query: query.merge(request_query)
)
end
response.parsed_response
end
private
def request_query
{
page: @page,
per_page: @per_page
}
end
def request_headers
{
'Content-Type' => 'application/json',
'Authorization' => "Bearer #{@token}"
}
end
def with_error_handling
response = yield
raise ConnectionError.new("Error #{response.code}") unless response.success?
response
rescue *Gitlab::HTTP::HTTP_ERRORS => e
raise ConnectionError, e
end
def base_uri
@base_uri ||= "#{@uri.scheme}://#{@uri.host}:#{@uri.port}"
end
def api_url
Gitlab::Utils.append_path(base_uri, "/api/#{@api_version}")
end
def resource_url(resource)
Gitlab::Utils.append_path(api_url, resource)
end
end
end
end
......@@ -51,6 +51,28 @@ RSpec.describe Import::BulkImportsController do
end
describe 'GET status' do
let(:client) { Gitlab::BulkImport::Client.new(uri: 'http://gitlab.example', token: 'token') }
describe 'serialized group data' do
let(:client_response) do
[
{ 'id' => 1, 'full_name' => 'group1', 'full_path' => 'full/path/group1' },
{ 'id' => 2, 'full_name' => 'group2', 'full_path' => 'full/path/group2' }
]
end
before do
allow(controller).to receive(:client).and_return(client)
allow(client).to receive(:get).with('groups', top_level_only: true).and_return(client_response)
end
it 'returns serialized group data' do
get :status, format: :json
expect(response.parsed_body).to eq({ importable_data: client_response }.as_json)
end
end
context 'when host url is local or not http' do
%w[https://localhost:3000 http://192.168.0.1 ftp://testing].each do |url|
before do
......@@ -85,6 +107,26 @@ RSpec.describe Import::BulkImportsController do
end
end
end
context 'when connection error occurs' do
before do
allow(controller).to receive(:client).and_return(client)
allow(client).to receive(:get).and_raise(Gitlab::BulkImport::Client::ConnectionError)
end
it 'returns 422' do
get :status, format: :json
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
it 'clears session' do
get :status, format: :json
expect(session[:gitlab_url]).to be_nil
expect(session[:gitlab_access_token]).to be_nil
end
end
end
end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BulkImport::Client do
include ImportSpecHelper
let(:uri) { 'http://gitlab.example' }
let(:token) { 'token' }
let(:resource) { 'resource' }
subject { described_class.new(uri: uri, token: token) }
describe '#get' do
let(:response_double) { double(code: 200, success?: true, parsed_response: {}) }
shared_examples 'performs network request' do
it 'performs network request' do
expect(Gitlab::HTTP).to receive(:get).with(*expected_args).and_return(response_double)
subject.get(resource)
end
end
describe 'parsed response' do
it 'returns parsed response' do
response_double = double(code: 200, success?: true, parsed_response: [{ id: 1 }, { id: 2 }])
allow(Gitlab::HTTP).to receive(:get).and_return(response_double)
expect(subject.get(resource)).to eq(response_double.parsed_response)
end
end
describe 'request query' do
include_examples 'performs network request' do
let(:expected_args) do
[
anything,
hash_including(
query: {
page: described_class::DEFAULT_PAGE,
per_page: described_class::DEFAULT_PER_PAGE
}
)
]
end
end
end
describe 'request headers' do
include_examples 'performs network request' do
let(:expected_args) do
[
anything,
hash_including(
headers: {
'Content-Type' => 'application/json',
'Authorization' => "Bearer #{token}"
}
)
]
end
end
end
describe 'request uri' do
include_examples 'performs network request' do
let(:expected_args) do
['http://gitlab.example:80/api/v4/resource', anything]
end
end
end
context 'error handling' do
context 'when error occurred' do
it 'raises ConnectionError' do
allow(Gitlab::HTTP).to receive(:get).and_raise(Errno::ECONNREFUSED)
expect { subject.get(resource) }.to raise_exception(described_class::ConnectionError)
end
end
context 'when response is not success' do
it 'raises ConnectionError' do
response_double = double(code: 503, success?: false)
allow(Gitlab::HTTP).to receive(:get).and_return(response_double)
expect { subject.get(resource) }.to raise_exception(described_class::ConnectionError)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Import::BulkImportEntity do
let(:importable_data) do
{
'id' => 1,
'full_name' => 'test',
'full_path' => 'full/path/test',
'foo' => 'bar'
}
end
subject { described_class.represent(importable_data).as_json }
%w[id full_name full_path].each do |attribute|
it "exposes #{attribute}" do
expect(subject[attribute.to_sym]).to eq(importable_data[attribute])
end
end
it 'does not expose unspecified attributes' do
expect(subject[:foo]).to be_nil
end
end
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