Skip to content
Snippets Groups Projects
Commit 1e2bd853 authored by Ben's avatar Ben Committed by Dmytro Zaporozhets (DZ)
Browse files

API for importing external repos

parent f598daf2
No related branches found
No related tags found
Loading
...@@ -18,6 +18,7 @@ def find_jobs(import_type) ...@@ -18,6 +18,7 @@ def find_jobs(import_type)
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
# deprecated: being replaced by app/services/import/base_service.rb
def find_or_create_namespace(names, owner) def find_or_create_namespace(names, owner)
names = params[:target_namespace].presence || names names = params[:target_namespace].presence || names
...@@ -32,6 +33,7 @@ def find_or_create_namespace(names, owner) ...@@ -32,6 +33,7 @@ def find_or_create_namespace(names, owner)
current_user.namespace current_user.namespace
end end
# deprecated: being replaced by app/services/import/base_service.rb
def project_save_error(project) def project_save_error(project)
project.errors.full_messages.join(', ') project.errors.full_messages.join(', ')
end end
......
...@@ -39,28 +39,21 @@ def jobs ...@@ -39,28 +39,21 @@ def jobs
end end
def create def create
repo = client.repo(params[:repo_id].to_i) result = Import::GithubService.new(client, current_user, import_params).execute(access_params, provider)
project_name = params[:new_name].presence || repo.name
namespace_path = params[:target_namespace].presence || current_user.namespace_path if result[:status] == :success
target_namespace = find_or_create_namespace(namespace_path, current_user.namespace_path) render json: ProjectSerializer.new.represent(result[:project])
if can?(current_user, :create_projects, target_namespace)
project = Gitlab::LegacyGithubImport::ProjectCreator
.new(repo, project_name, target_namespace, current_user, access_params, type: provider)
.execute(extra_project_attrs)
if project.persisted?
render json: ProjectSerializer.new.represent(project)
else
render json: { errors: project_save_error(project) }, status: :unprocessable_entity
end
else else
render json: { errors: 'This namespace has already been taken! Please choose another one.' }, status: :unprocessable_entity render json: { errors: result[:message] }, status: result[:http_status]
end end
end end
private private
def import_params
params.permit(:repo_id, :new_name, :target_namespace)
end
def client def client
@client ||= Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options) @client ||= Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options)
end end
...@@ -124,10 +117,6 @@ def client_options ...@@ -124,10 +117,6 @@ def client_options
{} {}
end end
def extra_project_attrs
{}
end
def extra_import_params def extra_import_params
{} {}
end end
......
# frozen_string_literal: true
module Import
class BaseService < ::BaseService
def initialize(client, user, params)
@client = client
@current_user = user
@params = params
end
private
def find_or_create_namespace(namespace, owner)
namespace = params[:target_namespace].presence || namespace
return current_user.namespace if namespace == owner
group = Groups::NestedCreateService.new(current_user, group_path: namespace).execute
group.errors.any? ? current_user.namespace : group
rescue => e
Gitlab::AppLogger.error(e)
current_user.namespace
end
def project_save_error(project)
project.errors.full_messages.join(', ')
end
def success(project)
super().merge(project: project, status: :success)
end
end
end
# frozen_string_literal: true
module Import
class GithubService < Import::BaseService
attr_accessor :client
attr_reader :params, :current_user
def execute(access_params, provider)
unless authorized?
return error('This namespace has already been taken! Please choose another one.', :unprocessable_entity)
end
project = Gitlab::LegacyGithubImport::ProjectCreator
.new(repo, project_name, target_namespace, current_user, access_params, type: provider)
.execute(extra_project_attrs)
if project.persisted?
success(project)
else
error(project_save_error(project), :unprocessable_entity)
end
end
def repo
@repo ||= client.repo(params[:repo_id].to_i)
end
def project_name
@project_name ||= params[:new_name].presence || repo.name
end
def namespace_path
@namespace_path ||= params[:target_namespace].presence || current_user.namespace_path
end
def target_namespace
@target_namespace ||= find_or_create_namespace(namespace_path, current_user.namespace_path)
end
def extra_project_attrs
{}
end
def authorized?
can?(current_user, :create_projects, target_namespace)
end
end
end
# Import API
## Import repository from GitHub
Import your projects from GitHub to GitLab via the API.
```
POST /import/github
```
| Attribute | Type | Required | Description |
|------------|---------|----------|---------------------|
| `personal_access_token` | string | yes | GitHub personal access token |
| `repo_id` | integer | yes | GitHub repository ID |
| `new_name` | string | no | New repo name |
| `target_namespace` | string | yes | Namespace to import repo into |
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "personal_access_token=abc123&repo_id=12345&target_namespace=root" https://gitlab.example.com/api/v4/import/github
```
Example response:
```json
{
"id": 27,
"name": "my-repo",
"full_path": "/root/my-repo",
"full_name": "Administrator / my-repo"
}
```
...@@ -110,6 +110,7 @@ class API < Grape::API ...@@ -110,6 +110,7 @@ class API < Grape::API
mount ::API::GroupMilestones mount ::API::GroupMilestones
mount ::API::Groups mount ::API::Groups
mount ::API::GroupVariables mount ::API::GroupVariables
mount ::API::ImportGithub
mount ::API::Internal mount ::API::Internal
mount ::API::Issues mount ::API::Issues
mount ::API::JobArtifacts mount ::API::JobArtifacts
......
# frozen_string_literal: true
module API
class ImportGithub < Grape::API
rescue_from Octokit::Unauthorized, with: :provider_unauthorized
helpers do
def client
@client ||= Gitlab::LegacyGithubImport::Client.new(params[:personal_access_token], client_options)
end
def access_params
{ github_access_token: params[:personal_access_token] }
end
def client_options
{}
end
def provider
:github
end
end
desc 'Import a GitHub project' do
detail 'This feature was introduced in GitLab 11.3.4.'
success Entities::ProjectEntity
end
params do
requires :personal_access_token, type: String, desc: 'GitHub personal access token'
requires :repo_id, type: Integer, desc: 'GitHub repository ID'
optional :new_name, type: String, desc: 'New repo name'
requires :target_namespace, type: String, desc: 'Namespace to import repo into'
end
post 'import/github' do
result = Import::GithubService.new(client, current_user, params).execute(access_params, provider)
if result[:status] == :success
present ProjectSerializer.new.represent(result[:project])
else
status result[:http_status]
{ errors: result[:message] }
end
end
end
end
require 'spec_helper'
describe API::ImportGithub do
include ApiHelpers
let(:token) { "asdasd12345" }
let(:provider) { :github }
let(:access_params) { { github_access_token: token } }
describe "POST /import/github" do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:provider_username) { user.username }
let(:provider_user) { OpenStruct.new(login: provider_username) }
let(:provider_repo) do
OpenStruct.new(
name: 'vim',
full_name: "#{provider_username}/vim",
owner: OpenStruct.new(login: provider_username)
)
end
before do
Grape::Endpoint.before_each do |endpoint|
allow(endpoint).to receive(:client).and_return(double('client', user: provider_user, repo: provider_repo).as_null_object)
end
end
it 'returns 201 response when the project is imported successfully' do
allow(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
.and_return(double(execute: project))
post api("/import/github", user), params: {
target_namespace: user.namespace_path,
personal_access_token: token,
repo_id: 1234
}
expect(response).to have_gitlab_http_status(201)
expect(json_response).to be_a Hash
expect(json_response['name']).to eq(project.name)
end
it 'returns 422 response when user can not create projects in the chosen namespace' do
other_namespace = create(:group, name: 'other_namespace')
post api("/import/github", user), params: {
target_namespace: other_namespace.name,
personal_access_token: token,
repo_id: 1234
}
expect(response).to have_gitlab_http_status(422)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment