Commit 93cf1825 authored by Leo Lu's avatar Leo Lu Committed by Rémy Coutable

Support finding namespace by ID or path on fork API

parent 8be98b2a
---
title: Support finding namespace by ID or path on fork API
merge_request: 20603
author: leoleoasd
type: fixed
...@@ -1207,7 +1207,9 @@ POST /projects/:id/fork ...@@ -1207,7 +1207,9 @@ POST /projects/:id/fork
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `namespace` | integer/string | yes | The ID or path of the namespace that the project will be forked to | | `namespace` | integer/string | no | (deprecated) The ID or path of the namespace that the project will be forked to |
| `namespace_id` | integer | no | The ID of the namespace that the project will be forked to |
| `namespace_path` | string | no | The path of the namespace that the project will be forked to |
| `path` | string | no | The path that will be assigned to the resultant project after forking | | `path` | string | no | The path that will be assigned to the resultant project after forking |
| `name` | string | no | The name that will be assigned to the resultant project after forking | | `name` | string | no | The name that will be assigned to the resultant project after forking |
......
...@@ -142,6 +142,12 @@ module API ...@@ -142,6 +142,12 @@ module API
end end
end end
def check_namespace_access(namespace)
return namespace if can?(current_user, :read_namespace, namespace)
not_found!('Namespace')
end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def find_namespace(id) def find_namespace(id)
if id.to_s =~ /^\d+$/ if id.to_s =~ /^\d+$/
...@@ -153,13 +159,15 @@ module API ...@@ -153,13 +159,15 @@ module API
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def find_namespace!(id) def find_namespace!(id)
namespace = find_namespace(id) check_namespace_access(find_namespace(id))
end
if can?(current_user, :read_namespace, namespace) def find_namespace_by_path(path)
namespace Namespace.find_by_full_path(path)
else end
not_found!('Namespace')
end def find_namespace_by_path!(path)
check_namespace_access(find_namespace_by_path(path))
end end
def find_branch!(branch_name) def find_branch!(branch_name)
......
...@@ -263,7 +263,9 @@ module API ...@@ -263,7 +263,9 @@ module API
success Entities::Project success Entities::Project
end end
params do params do
optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be forked into' optional :namespace, type: String, desc: '(deprecated) The ID or name of the namespace that the project will be forked into'
optional :namespace_id, type: Integer, desc: 'The ID of the namespace that the project will be forked into'
optional :namespace_path, type: String, desc: 'The path of the namespace that the project will be forked into'
optional :path, type: String, desc: 'The path that will be assigned to the fork' optional :path, type: String, desc: 'The path that will be assigned to the fork'
optional :name, type: String, desc: 'The name that will be assigned to the fork' optional :name, type: String, desc: 'The name that will be assigned to the fork'
end end
...@@ -273,7 +275,15 @@ module API ...@@ -273,7 +275,15 @@ module API
not_found! unless can?(current_user, :fork_project, user_project) not_found! unless can?(current_user, :fork_project, user_project)
fork_params = declared_params(include_missing: false) fork_params = declared_params(include_missing: false)
fork_params[:namespace] = find_namespace!(fork_params[:namespace]) if fork_params[:namespace].present?
fork_params[:namespace] =
if fork_params[:namespace_id].present?
find_namespace!(fork_params[:namespace_id])
elsif fork_params[:namespace_path].present?
find_namespace_by_path!(fork_params[:namespace_path])
elsif fork_params[:namespace].present?
find_namespace!(fork_params[:namespace])
end
service = ::Projects::ForkService.new(user_project, current_user, fork_params) service = ::Projects::ForkService.new(user_project, current_user, fork_params)
...@@ -285,8 +295,8 @@ module API ...@@ -285,8 +295,8 @@ module API
conflict!(forked_project.errors.messages) conflict!(forked_project.errors.messages)
else else
present forked_project, with: Entities::Project, present forked_project, with: Entities::Project,
user_can_admin_project: can?(current_user, :admin_project, forked_project), user_can_admin_project: can?(current_user, :admin_project, forked_project),
current_user: current_user current_user: current_user
end end
end end
......
...@@ -2871,6 +2871,66 @@ describe API::Projects do ...@@ -2871,6 +2871,66 @@ describe API::Projects do
expect(json_response['namespace']['name']).to eq(group2.name) expect(json_response['namespace']['name']).to eq(group2.name)
end end
context 'when namespace_id is specified' do
shared_examples_for 'forking to specified namespace_id' do
it 'forks to specified namespace_id' do
expect(response).to have_gitlab_http_status(:created)
expect(json_response['owner']['id']).to eq(user2.id)
expect(json_response['namespace']['id']).to eq(user2.namespace.id)
end
end
context 'and namespace_id is specified alone' do
before do
post api("/projects/#{project.id}/fork", user2), params: { namespace_id: user2.namespace.id }
end
it_behaves_like 'forking to specified namespace_id'
end
context 'and namespace_id and namespace are both specified' do
before do
post api("/projects/#{project.id}/fork", user2), params: { namespace_id: user2.namespace.id, namespace: admin.namespace.id }
end
it_behaves_like 'forking to specified namespace_id'
end
context 'and namespace_id and namespace_path are both specified' do
before do
post api("/projects/#{project.id}/fork", user2), params: { namespace_id: user2.namespace.id, namespace_path: admin.namespace.path }
end
it_behaves_like 'forking to specified namespace_id'
end
end
context 'when namespace_path is specified' do
shared_examples_for 'forking to specified namespace_path' do
it 'forks to specified namespace_path' do
expect(response).to have_gitlab_http_status(:created)
expect(json_response['owner']['id']).to eq(user2.id)
expect(json_response['namespace']['path']).to eq(user2.namespace.path)
end
end
context 'and namespace_path is specified alone' do
before do
post api("/projects/#{project.id}/fork", user2), params: { namespace_path: user2.namespace.path }
end
it_behaves_like 'forking to specified namespace_path'
end
context 'and namespace_path and namespace are both specified' do
before do
post api("/projects/#{project.id}/fork", user2), params: { namespace_path: user2.namespace.path, namespace: admin.namespace.path }
end
it_behaves_like 'forking to specified namespace_path'
end
end
it 'forks to owned subgroup' do it 'forks to owned subgroup' do
full_path = "#{group2.path}/#{group3.path}" full_path = "#{group2.path}/#{group3.path}"
post api("/projects/#{project.id}/fork", user2), params: { namespace: full_path } post api("/projects/#{project.id}/fork", user2), params: { namespace: full_path }
......
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