Commit a2108973 authored by Stan Hu's avatar Stan Hu Committed by Mayra Cabrera

Fix project creation with templates using /projects/user/:id API

Previously creation with an instance or group template with POST
`/api/v4/projects worked`, but `/api/v4/projects/user/:id` did not
because the latter did not accept the `use_custom_templates` parameter
due to an oversight.

This commit fixes this by adding the `optional_create_project_params`
Grape API and add tests for project creation via the user endpoint.

Closes https://gitlab.com/gitlab-org/gitlab/issues/37004
parent 3fe00c56
---
title: Fix project creation with templates using /projects/user/:id API
merge_request: 20590
author:
type: fixed
......@@ -182,120 +182,165 @@ describe API::Projects do
end
end
describe 'POST /projects' do
shared_examples 'creates projects with templates' do
before do
group.add_maintainer(user)
stub_licensed_features(custom_project_templates: true)
stub_ee_application_setting(custom_project_templates_group_id: group.id)
# Assumes the following variables are defined:
# group
# project
# new_project_name
# api_call
shared_examples 'creates projects with templates' do
before do
group.add_maintainer(user)
stub_licensed_features(custom_project_templates: true)
stub_ee_application_setting(custom_project_templates_group_id: group.id)
end
it 'creates a project using a template' do
expect(ProjectExportWorker).to receive(:perform_async).and_call_original
Sidekiq::Testing.fake! do
expect { api_call }.to change { Project.count }.by(1)
end
it 'creates a project using a template' do
expect(ProjectExportWorker).to receive(:perform_async).and_call_original
expect(response).to have_gitlab_http_status(201)
Sidekiq::Testing.fake! do
expect { post api('/projects', user), params: project_params }
.to change { Project.count }.by(1)
end
project = Project.find(json_response['id'])
expect(project.name).to eq(new_project_name)
end
expect(response).to have_gitlab_http_status(201)
it 'returns a 400 error for an invalid template name' do
project_params.delete(:template_project_id)
project_params[:template_name] = 'bogus-template'
project = Project.find(json_response['id'])
expect(project.name).to eq(new_project_name)
end
expect { api_call }.not_to change { Project.count }
it 'returns a 400 error for an invalid template name' do
project_params.delete(:template_project_id)
project_params[:template_name] = 'bogus-template'
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['template_name']).to eq(["'bogus-template' is unknown or invalid"])
end
expect { post api('/projects', user), params: project_params }
.not_to change { Project.count }
it 'returns a 400 error for an invalid template ID' do
project_params.delete(:template_name)
new_project = create(:project)
project_params[:template_project_id] = new_project.id
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['template_name']).to eq(["'bogus-template' is unknown or invalid"])
end
expect { api_call }.not_to change { Project.count }
it 'returns a 400 error for an invalid template ID' do
project_params.delete(:template_name)
new_project = create(:project)
project_params[:template_project_id] = new_project.id
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['template_project_id']).to eq(["#{new_project.id} is unknown or invalid"])
end
end
expect { post api('/projects', user), params: project_params }
.not_to change { Project.count }
shared_context 'base instance template models' do
let(:group) { create(:group) }
let!(:project) { create(:project, :public, namespace: group) }
let(:new_project_name) { "project-#{SecureRandom.hex}" }
end
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['template_project_id']).to eq(["#{new_project.id} is unknown or invalid"])
end
shared_context 'instance template name' do
include_context 'base instance template models'
let(:project_params) do
{
template_name: project.name,
name: new_project_name,
path: new_project_name,
use_custom_template: true,
namespace_id: group.id
}
end
end
context 'with instance-level templates' do
let(:group) { create(:group) }
let!(:project) { create(:project, :public, namespace: group) }
let(:new_project_name) { "project-#{SecureRandom.hex}" }
context 'using template name' do
let(:project_params) do
{
template_name: project.name,
name: new_project_name,
path: new_project_name,
use_custom_template: true,
namespace_id: group.id
}
end
shared_context 'instance template ID' do
include_context 'base instance template models'
let(:project_params) do
{
template_project_id: project.id,
name: new_project_name,
path: new_project_name,
use_custom_template: true,
namespace_id: group.id
}
end
end
shared_context 'base group template models' do
let(:parent_group) { create(:group) }
let(:subgroup) { create(:group, :public, parent: parent_group) }
let(:group) { subgroup }
let!(:project) { create(:project, :public, namespace: subgroup) }
let(:new_project_name) { "project-#{SecureRandom.hex}" }
end
shared_context 'group template name' do
include_context 'base group template models'
let(:project_params) do
{
template_name: project.name,
name: new_project_name,
path: new_project_name,
use_custom_template: true,
group_with_project_templates_id: subgroup.id,
namespace_id: subgroup.id
}
end
end
shared_context 'group template ID' do
include_context 'base group template models'
let(:project_params) do
{
template_project_id: project.id,
name: new_project_name,
path: new_project_name,
use_custom_template: true,
group_with_project_templates_id: subgroup.id,
namespace_id: subgroup.id
}
end
end
describe 'POST /projects/user/:id' do
let(:admin) { create(:admin) }
let(:api_call) { post api("/projects/user/#{user.id}", admin), params: project_params }
context 'with templates' do
include_context 'instance template name' do
it_behaves_like 'creates projects with templates'
end
context 'using template project ID' do
let(:project_params) do
{
template_project_id: project.id,
name: new_project_name,
path: new_project_name,
use_custom_template: true,
namespace_id: group.id
}
end
include_context 'instance template ID' do
it_behaves_like 'creates projects with templates'
end
include_context 'group template name' do
it_behaves_like 'creates projects with templates'
end
include_context 'group template ID' do
it_behaves_like 'creates projects with templates'
end
end
end
context 'with group templates' do
let(:parent_group) { create(:group) }
let(:subgroup) { create(:group, :public, parent: parent_group) }
let(:group) { subgroup }
let!(:project) { create(:project, :public, namespace: subgroup) }
let(:new_project_name) { "project-#{SecureRandom.hex}" }
context 'using template name' do
let(:project_params) do
{
template_name: project.name,
name: new_project_name,
path: new_project_name,
use_custom_template: true,
group_with_project_templates_id: subgroup.id,
namespace_id: subgroup.id
}
end
describe 'POST /projects' do
let(:api_call) { post api('/projects', user), params: project_params }
context 'with templates' do
include_context 'instance template name' do
it_behaves_like 'creates projects with templates'
end
context 'using template project ID' do
let(:project_params) do
{
template_project_id: project.id,
name: new_project_name,
path: new_project_name,
use_custom_template: true,
group_with_project_templates_id: subgroup.id,
namespace_id: subgroup.id
}
end
include_context 'instance template ID' do
it_behaves_like 'creates projects with templates'
end
include_context 'group template name' do
it_behaves_like 'creates projects with templates'
end
include_context 'group template ID' do
it_behaves_like 'creates projects with templates'
end
end
......
......@@ -191,6 +191,7 @@ module API
optional :path, type: String, desc: 'The path of the repository'
optional :default_branch, type: String, desc: 'The default branch of the project'
use :optional_project_params
use :optional_create_project_params
use :create_params
end
# rubocop: disable CodeReuse/ActiveRecord
......
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