Commit 7c9983c7 authored by Toon Claes's avatar Toon Claes

Allow project owners to set up forking relation through API

Before this change only GitLab admins where allowed to set up forking
relation through the API. This changes that so project owners can
do this too.

Closes gitlab-org/gitlab-ce#40550.
parent 3c80adf5
---
title: Allow project owners to set up forking relation through API
merge_request: 18104
author:
type: changed
...@@ -1413,9 +1413,9 @@ DELETE /projects/:id/hooks/:hook_id ...@@ -1413,9 +1413,9 @@ DELETE /projects/:id/hooks/:hook_id
Note the JSON response differs if the hook is available or not. If the project hook Note the JSON response differs if the hook is available or not. If the project hook
is available before it is returned in the JSON response or an empty response is returned. is available before it is returned in the JSON response or an empty response is returned.
## Admin fork relation ## Fork relationship
Allows modification of the forked relationship between existing projects. Available only for admins. Allows modification of the forked relationship between existing projects. Available only for project owners and admins.
### Create a forked from/to relation between existing projects ### Create a forked from/to relation between existing projects
......
...@@ -386,7 +386,7 @@ module API ...@@ -386,7 +386,7 @@ module API
requires :forked_from_id, type: String, desc: 'The ID of the project it was forked from' requires :forked_from_id, type: String, desc: 'The ID of the project it was forked from'
end end
post ":id/fork/:forked_from_id" do post ":id/fork/:forked_from_id" do
authenticated_as_admin! authorize! :admin_project, user_project
fork_from_project = find_project!(params[:forked_from_id]) fork_from_project = find_project!(params[:forked_from_id])
......
...@@ -402,7 +402,7 @@ describe API::Projects do ...@@ -402,7 +402,7 @@ describe API::Projects do
context 'and with min_access_level' do context 'and with min_access_level' do
before do before do
project2.add_master(user2) project2.add_maintainer(user2)
project3.add_developer(user2) project3.add_developer(user2)
project4.add_reporter(user2) project4.add_reporter(user2)
end end
...@@ -1121,31 +1121,68 @@ describe API::Projects do ...@@ -1121,31 +1121,68 @@ describe API::Projects do
describe 'fork management' do describe 'fork management' do
let(:project_fork_target) { create(:project) } let(:project_fork_target) { create(:project) }
let(:project_fork_source) { create(:project, :public) } let(:project_fork_source) { create(:project, :public) }
let(:private_project_fork_source) { create(:project, :private) }
describe 'POST /projects/:id/fork/:forked_from_id' do describe 'POST /projects/:id/fork/:forked_from_id' do
let(:new_project_fork_source) { create(:project, :public) } context 'user is a developer' do
before do
project_fork_target.add_developer(user)
end
it "is not available for non admin users" do it 'denies project to be forked from an existing project' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
expect(response).to have_gitlab_http_status(403) expect(response).to have_gitlab_http_status(403)
end end
end
it 'refreshes the forks count cache' do
expect(project_fork_source.forks_count).to be_zero
end
context 'user is maintainer' do
before do
project_fork_target.add_maintainer(user)
end
it 'allows project to be forked from an existing project' do it 'allows project to be forked from an existing project' do
expect(project_fork_target.forked?).not_to be_truthy expect(project_fork_target).not_to be_forked
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
expect(response).to have_gitlab_http_status(201) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
project_fork_target.reload project_fork_target.reload
expect(response).to have_gitlab_http_status(201)
expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id) expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
expect(project_fork_target.forked_project_link).not_to be_nil expect(project_fork_target.forked_project_link).to be_present
expect(project_fork_target.forked?).to be_truthy expect(project_fork_target).to be_forked
end end
it 'refreshes the forks count cache' do it 'denies project to be forked from a private project' do
expect(project_fork_source.forks_count).to be_zero post api("/projects/#{project_fork_target.id}/fork/#{private_project_fork_source.id}", user)
expect(response).to have_gitlab_http_status(404)
end
end
context 'user is admin' do
it 'allows project to be forked from an existing project' do
expect(project_fork_target).not_to be_forked
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
expect(project_fork_source.forks_count).to eq(1) expect(response).to have_gitlab_http_status(201)
end
it 'allows project to be forked from a private project' do
post api("/projects/#{project_fork_target.id}/fork/#{private_project_fork_source.id}", admin)
expect(response).to have_gitlab_http_status(201)
end
it 'refreshes the forks count cachce' do
expect do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
end.to change(project_fork_source, :forks_count).by(1)
end end
it 'fails if forked_from project which does not exist' do it 'fails if forked_from project which does not exist' do
...@@ -1154,14 +1191,17 @@ describe API::Projects do ...@@ -1154,14 +1191,17 @@ describe API::Projects do
end end
it 'fails with 409 if already forked' do it 'fails with 409 if already forked' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) other_project_fork_source = create(:project, :public)
Projects::ForkService.new(project_fork_source, admin).execute(project_fork_target)
post api("/projects/#{project_fork_target.id}/fork/#{other_project_fork_source.id}", admin)
project_fork_target.reload project_fork_target.reload
expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
post api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin)
expect(response).to have_gitlab_http_status(409) expect(response).to have_gitlab_http_status(409)
project_fork_target.reload
expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id) expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
expect(project_fork_target.forked?).to be_truthy expect(project_fork_target).to be_forked
end
end end
end end
...@@ -1183,8 +1223,8 @@ describe API::Projects do ...@@ -1183,8 +1223,8 @@ describe API::Projects do
before do before do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
project_fork_target.reload project_fork_target.reload
expect(project_fork_target.forked_from_project).not_to be_nil expect(project_fork_target.forked_from_project).to be_present
expect(project_fork_target.forked?).to be_truthy expect(project_fork_target).to be_forked
end end
it 'makes forked project unforked' do it 'makes forked project unforked' do
...@@ -1193,7 +1233,7 @@ describe API::Projects do ...@@ -1193,7 +1233,7 @@ describe API::Projects do
expect(response).to have_gitlab_http_status(204) expect(response).to have_gitlab_http_status(204)
project_fork_target.reload project_fork_target.reload
expect(project_fork_target.forked_from_project).to be_nil expect(project_fork_target.forked_from_project).to be_nil
expect(project_fork_target.forked?).not_to be_truthy expect(project_fork_target).not_to be_forked
end end
it_behaves_like '412 response' do it_behaves_like '412 response' do
...@@ -1228,8 +1268,8 @@ describe API::Projects do ...@@ -1228,8 +1268,8 @@ describe API::Projects do
before do before do
post api("/projects/#{private_fork.id}/fork/#{project_fork_source.id}", admin) post api("/projects/#{private_fork.id}/fork/#{project_fork_source.id}", admin)
private_fork.reload private_fork.reload
expect(private_fork.forked_from_project).not_to be_nil expect(private_fork.forked_from_project).to be_present
expect(private_fork.forked?).to be_truthy expect(private_fork).to be_forked
project_fork_source.reload project_fork_source.reload
expect(project_fork_source.forks.length).to eq(1) expect(project_fork_source.forks.length).to eq(1)
expect(project_fork_source.forks).to include(private_fork) expect(project_fork_source.forks).to include(private_fork)
......
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